diff --git a/__pycache__/app.cpython-312.pyc b/__pycache__/app.cpython-312.pyc index a0c699c..08608bc 100644 Binary files a/__pycache__/app.cpython-312.pyc and b/__pycache__/app.cpython-312.pyc differ diff --git a/__pycache__/config.cpython-312.pyc b/__pycache__/config.cpython-312.pyc index 8db7163..281027a 100644 Binary files a/__pycache__/config.cpython-312.pyc and b/__pycache__/config.cpython-312.pyc differ diff --git a/__pycache__/extensions.cpython-312.pyc b/__pycache__/extensions.cpython-312.pyc index 6494f48..4bf94c2 100644 Binary files a/__pycache__/extensions.cpython-312.pyc and b/__pycache__/extensions.cpython-312.pyc differ diff --git a/__pycache__/models.cpython-312.pyc b/__pycache__/models.cpython-312.pyc index 3a9b8a0..7e60e5a 100644 Binary files a/__pycache__/models.cpython-312.pyc and b/__pycache__/models.cpython-312.pyc differ diff --git a/app.py b/app.py index fc2f723..a0809ba 100644 --- a/app.py +++ b/app.py @@ -4,6 +4,7 @@ from extensions import db, redis_client from blueprints.auth import auth_bp from blueprints.api import api_bp from blueprints.admin import admin_bp +from blueprints.payment import payment_bp import threading import time @@ -22,6 +23,7 @@ def create_app(): app.register_blueprint(auth_bp) app.register_blueprint(api_bp) app.register_blueprint(admin_bp) + app.register_blueprint(payment_bp) @app.route('/') def index(): diff --git a/blueprints/__pycache__/admin.cpython-312.pyc b/blueprints/__pycache__/admin.cpython-312.pyc index 5ad2b03..4455fa7 100644 Binary files a/blueprints/__pycache__/admin.cpython-312.pyc and b/blueprints/__pycache__/admin.cpython-312.pyc differ diff --git a/blueprints/__pycache__/api.cpython-312.pyc b/blueprints/__pycache__/api.cpython-312.pyc index 976e61f..9cab3a2 100644 Binary files a/blueprints/__pycache__/api.cpython-312.pyc and b/blueprints/__pycache__/api.cpython-312.pyc differ diff --git a/blueprints/__pycache__/auth.cpython-312.pyc b/blueprints/__pycache__/auth.cpython-312.pyc index 2a5fea6..321c4d0 100644 Binary files a/blueprints/__pycache__/auth.cpython-312.pyc and b/blueprints/__pycache__/auth.cpython-312.pyc differ diff --git a/blueprints/__pycache__/payment.cpython-312.pyc b/blueprints/__pycache__/payment.cpython-312.pyc new file mode 100644 index 0000000..90581d1 Binary files /dev/null and b/blueprints/__pycache__/payment.cpython-312.pyc differ diff --git a/blueprints/admin.py b/blueprints/admin.py index 0e513a3..7e0cc41 100644 --- a/blueprints/admin.py +++ b/blueprints/admin.py @@ -1,6 +1,6 @@ from flask import Blueprint, request, jsonify from extensions import db -from models import User, Role, Permission, SystemDict, SystemNotification +from models import User, Role, Permission, SystemDict, SystemNotification, Order from middlewares.auth import permission_required admin_bp = Blueprint('admin', __name__, url_prefix='/api/admin') @@ -187,4 +187,23 @@ def delete_notification(): db.session.delete(n) db.session.commit() return jsonify({"message": "通知删除成功"}) - return jsonify({"error": "通知不存在"}), 404 \ No newline at end of file + return jsonify({"error": "通知不存在"}), 404 + +# --- 订单管理 --- +@admin_bp.route('/orders', methods=['GET']) +@permission_required('manage_system') # 仅限超级管理员 +def get_orders(): + orders = Order.query.order_by(Order.created_at.desc()).all() + return jsonify({ + "orders": [{ + "id": o.id, + "out_trade_no": o.out_trade_no, + "user_phone": o.user.phone if o.user else "未知", + "amount": float(o.amount), + "points": o.points, + "status": o.status, + "trade_no": o.trade_no, + "created_at": o.created_at.strftime('%Y-%m-%d %H:%M:%S'), + "paid_at": o.paid_at.strftime('%Y-%m-%d %H:%M:%S') if o.paid_at else None + } for o in orders] + }) \ No newline at end of file diff --git a/blueprints/payment.py b/blueprints/payment.py new file mode 100644 index 0000000..54a14c7 --- /dev/null +++ b/blueprints/payment.py @@ -0,0 +1,111 @@ +from flask import Blueprint, request, redirect, url_for, session, jsonify, render_template +from extensions import db +from models import Order, User +from services.alipay_service import AlipayService +import uuid +from datetime import datetime + +payment_bp = Blueprint('payment', __name__, url_prefix='/payment') + +# 积分价格配置 +POINTS_PACKAGES = { + '50': {'points': 50, 'amount': 5.00}, + '200': {'points': 200, 'amount': 20.00}, + '1000': {'points': 1000, 'amount': 100.00}, + '5000': {'points': 5000, 'amount': 500.00}, +} + +@payment_bp.route('/create', methods=['POST']) +def create_payment(): + if 'user_id' not in session: + return jsonify({'code': 401, 'msg': '请先登录'}), 401 + + package_id = request.form.get('package_id') + if package_id not in POINTS_PACKAGES: + return jsonify({'code': 400, 'msg': '无效的套餐'}), 400 + + package = POINTS_PACKAGES[package_id] + user_id = session['user_id'] + + # 生成唯一订单号 (时间戳 + 随机位) + out_trade_no = datetime.now().strftime('%Y%m%d%H%M%S') + str(uuid.uuid4().hex[:6]) + + # 创建订单记录 + try: + order = Order( + out_trade_no=out_trade_no, + user_id=user_id, + amount=package['amount'], + points=package['points'], + status='PENDING' + ) + db.session.add(order) + db.session.commit() + except Exception as e: + db.session.rollback() + return f"订单创建失败: {str(e)}", 500 + + # 获取支付链接 + try: + alipay_service = AlipayService() + pay_url = alipay_service.create_order_url( + out_trade_no=out_trade_no, + total_amount=package['amount'], + subject=f"购买{package['points']}积分" + ) + return redirect(pay_url) + except Exception as e: + return f"支付链接生成失败: {str(e)}", 500 + +@payment_bp.route('/return') +def payment_return(): + """支付成功后的同步跳转页面""" + data = request.args.to_dict() + signature = data.pop("sign", None) + + if not signature: + return "参数错误", 400 + + alipay_service = AlipayService() + success = alipay_service.verify_notify(data, signature) + + out_trade_no = data.get('out_trade_no') + order = Order.query.filter_by(out_trade_no=out_trade_no).first() + + if success: + # 同步通知仅用于页面展示,实际业务逻辑在异步通知 notify 中处理 + return render_template('buy.html', success=True, order=order) + else: + return "支付验证失败", 400 + +@payment_bp.route('/notify', methods=['POST']) +def payment_notify(): + """支付宝异步通知""" + data = request.form.to_dict() + signature = data.pop("sign", None) + + if not signature: + return "fail" + + alipay_service = AlipayService() + success = alipay_service.verify_notify(data, signature) + + if success and data.get('trade_status') in ['TRADE_SUCCESS', 'TRADE_FINISHED']: + out_trade_no = data.get('out_trade_no') + trade_no = data.get('trade_no') + + order = Order.query.filter_by(out_trade_no=out_trade_no).first() + if order and order.status == 'PENDING': + order.status = 'PAID' + order.trade_no = trade_no + order.paid_at = datetime.utcnow() + + # 给用户加积分 + user = User.query.get(order.user_id) + if user: + user.points += order.points + + db.session.commit() + return "success" + + return "fail" diff --git a/config.py b/config.py index e469929..4215064 100644 --- a/config.py +++ b/config.py @@ -44,6 +44,18 @@ class Config: SMS_TEMPLATE_CODE = "100001" SMS_NEED_PARAM = False # 该模板需要参数,如使用系统赠送模板请改为 False + # 支付宝配置 (待填) + ALIPAY_APP_ID = "2021006126656681" # 支付宝 AppID + ALIPAY_APP_PRIVATE_KEY = """-----BEGIN RSA PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCJSgmesQisfxNdz5dUhdv3Anh6aOGyQ03t69cqnenFumyEiLFk1N9FBDRR6onUsW9ZUGf7+P1sn/TMHdoOQZzZsxYVCCj85820ORP/DHTyP0ONHfBj0GqnKig5o3OGosC9ieJT6QLBzycOmiv/3YcHSJQPQ3zlyUloPScD1UsslgpCFWF3c3UDstzhYy/i1LbNy63w+Hr/xj01f1JCzivJoir9erLpTbbjPcPbQXd9xpycwIyGufXbFh1kOE6q+WOZq6NAXCe0/leUwh+q5v0pTnWnY07iB9nQtL2qvXQIBZWGI6HV4NDnO6rblDf1oOwNWYKcjCtL045xcHfUWKlrAgMBAAECggEAO4qfp3JyJ5WpSYtJv3+aiYNJyxUHpW9pMeGR3MrF41pZzBUYknl8J4uOQWStyE/30c18e5xeFKk+2vOraXltVEFGN3Lli+HgpeQHVxsI8TMc0ewFINT4HG29KlpINUEKxGkzfl7VMkbsUnns0Tg7Yp5IkGIdne7xZkL3U8NCqh/0oHAczMTwV1gqOFetyENNhdqzZJgwjR5c2OIIsNAuq+s0CcIqIw6hSwKzYN3H2i+4UKXmgU9kB2pGIzyxOH41FbEZp/UAcv9m2ikK2oYSXIHozaEsYyUXZbvHn4vmz1+grwnMJy2UQZQUCOLjvkul7tGKcNXTFSCvtgudBMSQ2QKBgQDxKvs97C3CRqgM/GkajI3DVmCY9NZGj5fd75JVg0yIeYQ4tmUmVIepTfq/8YxmgUD284FAFeyfbcFMbZnP4MXQ5Ddun0je70P3snLhfCw52PG1ypxBHl/jzZPdecy5kPKSQIWK9dfaXzwvhRC+YFV2x2V+tcubfeGgZkJ4+79KPQKBgQCRu483SbkjIbKTlJVL1m8a8RtljEg0AxnGIOQQvpkNHWRRHEqE3ozkj3PUHicDh9MumyZSRm9ifSmbD+cYSnjpQYafD9pZQ4lFWE72rCrz2vTTiZKyd/VuuQl2wTcj57ffX7cCaXQ635O1w+tz4VXnZzFnN0Lx3KDQ76bpPEEExwKBgHpRqoyFtc/LtoCfpU9p6p0gum3aALRZMFXIpRfqOG8f8wgwuqzuQsCEZKHmCagT9rdKWkv+0r0qFdiF3nWpM6v3lIXvFC6+fGKth8cGDAhrGG10DjyZA1mvc0fp9wRHmEDFqPYKKyj/FK+ldhCZG7/a8oeJ/XMoLcAFHcHvLd6hAoGAFQnDmhKthHHX6tA3YVRag8Qs1VMUFVYhQWX8JqKtS6RjmAYCh/3szw4ahZO4xBy2kvLY7GW4rLou6HC6RtpxbBMGkS3jsqE6TuV5uMiQBtYkI+mnYNZKeyqBQECSaj+IXtndfJ6mpd0i4Mmg0wDDuv09t43Vvz6/hIokSWVmaX8CgYEApzBH2M3R3j/jz2Hb3cevI+3MaeSIZMCedj2oTI2VB+6cOfuCW+65uuj7VuZkjEWzHMt3jVWPBtjyp002D3unYfIiaFaXUK4hSeoOCVj9ma8xhqR278Llkhxgf6KDx2E43YeTtrg9jStHmuD+Wr4UV96MOuIyaKqOFQHs4P/sQqY= +-----END RSA PRIVATE KEY-----""" # 应用私钥 + ALIPAY_PUBLIC_KEY = """-----BEGIN PUBLIC KEY----- +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx6iXKiRpbs5WLHlb6fdoteef+vs+QxxtmwDL2IJwhEJ+OMrkwlKyd4noYaiGDy2YcyHKahb4bsHRoPLVEqLveuVFksjsiFTH2mUhuwuqDe//XwE4hHsguNL3nY72gZ6qjwbg5mAVrHRcKUi6XSLSP4pWdCzD0leZ4GA9Kw1WstCS4sGBcrzyHPhRvtdVFZR5UjNLVAaN6HIMNhW0TBXz4r1ihXMV4byeN3n0n6e6reBLXr222f7c5almGurq6D9pLqwAmsqWbQWbvitOjZRll+bjpa29JIkNi+jEpPdYpGjU3e0Tl8aWkKjtYXmDyWtdw00RkciHUR4hMuCZW5qIjwIDAQAB +-----END PUBLIC KEY-----""" # 支付宝公钥 + ALIPAY_RETURN_URL = "http://331002.xyz:2010/payment/return" # 支付成功跳转地址 + ALIPAY_NOTIFY_URL = "http://331002.xyz:2010/payment/notify" # 支付异步通知地址 + ALIPAY_DEBUG = False # 是否使用沙箱环境 + # 开发模式配置 DEV_MODE = False # True=开发模式(固定验证码),False=生产模式(真实短信) DEV_SMS_CODE = "888888" # 开发模式下的固定验证码 diff --git a/logs/system.log b/logs/system.log index d62d3d0..d2cb7ed 100644 --- a/logs/system.log +++ b/logs/system.log @@ -128,3 +128,5 @@ [2026-01-13 23:52:22] INFO - 用户生成图片成功 [2026-01-13 23:59:01] INFO - 用户登录尝试 [2026-01-13 23:59:02] INFO - 用户登录成功 +[2026-01-14 16:45:23] INFO - 用户登录尝试 +[2026-01-14 16:45:23] INFO - 用户登录成功 diff --git a/middlewares/__pycache__/auth.cpython-312.pyc b/middlewares/__pycache__/auth.cpython-312.pyc index 60baaeb..9e51700 100644 Binary files a/middlewares/__pycache__/auth.cpython-312.pyc and b/middlewares/__pycache__/auth.cpython-312.pyc differ diff --git a/models.py b/models.py index 3315eb9..05993fc 100644 --- a/models.py +++ b/models.py @@ -101,3 +101,19 @@ class SystemNotification(db.Model): # 哪些用户已读 read_by_users = db.relationship('User', secondary=notification_reads, backref=db.backref('read_notifications', lazy='dynamic')) + +class Order(db.Model): + """订单模型""" + __tablename__ = 'orders' + + id = db.Column(db.Integer, primary_key=True) + out_trade_no = db.Column(db.String(64), unique=True, nullable=False) # 系统订单号 + user_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False) + amount = db.Column(db.Numeric(10, 2), nullable=False) # 金额 + points = db.Column(db.Integer, nullable=False) # 购买的积分 + status = db.Column(db.String(20), default='PENDING') # PENDING, PAID, CANCELLED + trade_no = db.Column(db.String(64)) # 支付宝交易号 + created_at = db.Column(db.DateTime, default=datetime.utcnow) + paid_at = db.Column(db.DateTime) + + user = db.relationship('User', backref=db.backref('orders', lazy='dynamic', order_by='Order.created_at.desc()')) diff --git a/requirements.txt b/requirements.txt index c0ada96..5af9243 100644 Binary files a/requirements.txt and b/requirements.txt differ diff --git a/services/__pycache__/alipay_service.cpython-312.pyc b/services/__pycache__/alipay_service.cpython-312.pyc new file mode 100644 index 0000000..9519a14 Binary files /dev/null and b/services/__pycache__/alipay_service.cpython-312.pyc differ diff --git a/services/__pycache__/logger.cpython-312.pyc b/services/__pycache__/logger.cpython-312.pyc index 7268fff..e522000 100644 Binary files a/services/__pycache__/logger.cpython-312.pyc and b/services/__pycache__/logger.cpython-312.pyc differ diff --git a/services/__pycache__/sms_service.cpython-312.pyc b/services/__pycache__/sms_service.cpython-312.pyc index 7d5fa63..6e63e62 100644 Binary files a/services/__pycache__/sms_service.cpython-312.pyc and b/services/__pycache__/sms_service.cpython-312.pyc differ diff --git a/services/alipay_service.py b/services/alipay_service.py new file mode 100644 index 0000000..afdc000 --- /dev/null +++ b/services/alipay_service.py @@ -0,0 +1,42 @@ +from alipay import AliPay +from flask import current_app +import os + +class AlipayService: + def __init__(self): + self.app_id = current_app.config.get('ALIPAY_APP_ID') + self.private_key = current_app.config.get('ALIPAY_APP_PRIVATE_KEY') + self.public_key = current_app.config.get('ALIPAY_PUBLIC_KEY') + self.return_url = current_app.config.get('ALIPAY_RETURN_URL') + self.notify_url = current_app.config.get('ALIPAY_NOTIFY_URL') + self.debug = current_app.config.get('ALIPAY_DEBUG', True) + + def get_alipay_client(self): + """获取支付宝客户端实例""" + return AliPay( + appid=self.app_id, + app_notify_url=self.notify_url, + app_private_key_string=self.private_key, + alipay_public_key_string=self.public_key, + sign_type="RSA2", + debug=self.debug + ) + + def create_order_url(self, out_trade_no, total_amount, subject): + """生成支付链接 (电脑网站支付)""" + alipay = self.get_alipay_client() + order_string = alipay.api_alipay_trade_page_pay( + out_trade_no=out_trade_no, + total_amount=str(total_amount), + subject=subject, + return_url=self.return_url, + notify_url=self.notify_url + ) + # 拼接支付网关 (使用最新的支付宝沙箱域名) + gateway = "https://openapi-sandbox.dl.alipaydev.com/gateway.do" if self.debug else "https://openapi.alipay.com/gateway.do" + return f"{gateway}?{order_string}" + + def verify_notify(self, data, signature): + """验证通知签名""" + alipay = self.get_alipay_client() + return alipay.verify(data, signature) diff --git a/sync_db.py b/sync_db.py new file mode 100644 index 0000000..c5a66a2 --- /dev/null +++ b/sync_db.py @@ -0,0 +1,15 @@ +from app import app +from extensions import db +import models + +def init(): + with app.app_context(): + print("🔧 正在同步数据库架构...") + try: + db.create_all() + print("✅ 数据库表已成功创建或已存在") + except Exception as e: + print(f"❌ 同步失败: {e}") + +if __name__ == '__main__': + init() diff --git a/templates/buy.html b/templates/buy.html index 1eb9551..ff897cc 100644 --- a/templates/buy.html +++ b/templates/buy.html @@ -15,8 +15,20 @@ + {% if success %} +
+
+ +
+
+

支付成功!

+

您的订单 #{{ order.out_trade_no if order else '' }} 已完成,积分已到账。

+
+
+ {% endif %} +
-
+
体验测试
@@ -30,9 +42,12 @@ 快速开启 AI 体验
- +
+ + +
@@ -49,9 +64,12 @@ 满足日常生成需求
- +
+ + +
@@ -67,9 +85,12 @@ 创作自由,无需等待 - +
+ + +
@@ -85,22 +106,12 @@ 至尊权限,顶级服务 - - - - - -
-
-
- -
-
-

官方充值通道接入中

-

Coming Soon · 敬请期待

-
+
+ + +
@@ -118,9 +129,6 @@ {% block scripts %} {% endblock %} \ No newline at end of file diff --git a/venv/Lib/site-packages/Cryptodome/Cipher/AES.py b/venv/Lib/site-packages/Cryptodome/Cipher/AES.py new file mode 100644 index 0000000..42f4bab --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Cipher/AES.py @@ -0,0 +1,235 @@ +# -*- coding: utf-8 -*- +# +# Cipher/AES.py : AES +# +# =================================================================== +# The contents of this file are dedicated to the public domain. To +# the extent that dedication to the public domain is not available, +# everyone is granted a worldwide, perpetual, royalty-free, +# non-exclusive license to exercise all rights associated with the +# contents of this file for any purpose whatsoever. +# No rights are reserved. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# =================================================================== + +import sys + +from Cryptodome.Cipher import _create_cipher +from Cryptodome.Util._raw_api import (load_pycryptodome_raw_lib, + VoidPointer, SmartPointer, + c_size_t, c_uint8_ptr) + +from Cryptodome.Util import _cpu_features +from Cryptodome.Random import get_random_bytes + +MODE_ECB = 1 #: Electronic Code Book (:ref:`ecb_mode`) +MODE_CBC = 2 #: Cipher-Block Chaining (:ref:`cbc_mode`) +MODE_CFB = 3 #: Cipher Feedback (:ref:`cfb_mode`) +MODE_OFB = 5 #: Output Feedback (:ref:`ofb_mode`) +MODE_CTR = 6 #: Counter mode (:ref:`ctr_mode`) +MODE_OPENPGP = 7 #: OpenPGP mode (:ref:`openpgp_mode`) +MODE_CCM = 8 #: Counter with CBC-MAC (:ref:`ccm_mode`) +MODE_EAX = 9 #: :ref:`eax_mode` +MODE_SIV = 10 #: Synthetic Initialization Vector (:ref:`siv_mode`) +MODE_GCM = 11 #: Galois Counter Mode (:ref:`gcm_mode`) +MODE_OCB = 12 #: Offset Code Book (:ref:`ocb_mode`) +MODE_KW = 13 #: Key Wrap (:ref:`kw_mode`) +MODE_KWP = 14 #: Key Wrap with Padding (:ref:`kwp_mode`) + +_cproto = """ + int AES_start_operation(const uint8_t key[], + size_t key_len, + void **pResult); + int AES_encrypt(const void *state, + const uint8_t *in, + uint8_t *out, + size_t data_len); + int AES_decrypt(const void *state, + const uint8_t *in, + uint8_t *out, + size_t data_len); + int AES_stop_operation(void *state); + """ + + +# Load portable AES +_raw_aes_lib = load_pycryptodome_raw_lib("Cryptodome.Cipher._raw_aes", + _cproto) + +# Try to load AES with AES NI instructions +try: + _raw_aesni_lib = None + if _cpu_features.have_aes_ni(): + _raw_aesni_lib = load_pycryptodome_raw_lib("Cryptodome.Cipher._raw_aesni", + _cproto.replace("AES", + "AESNI")) +# _raw_aesni may not have been compiled in +except OSError: + pass + + +def _create_base_cipher(dict_parameters): + """This method instantiates and returns a handle to a low-level + base cipher. It will absorb named parameters in the process.""" + + use_aesni = dict_parameters.pop("use_aesni", True) + + try: + key = dict_parameters.pop("key") + except KeyError: + raise TypeError("Missing 'key' parameter") + + if len(key) not in key_size: + raise ValueError("Incorrect AES key length (%d bytes)" % len(key)) + + if use_aesni and _raw_aesni_lib: + start_operation = _raw_aesni_lib.AESNI_start_operation + stop_operation = _raw_aesni_lib.AESNI_stop_operation + else: + start_operation = _raw_aes_lib.AES_start_operation + stop_operation = _raw_aes_lib.AES_stop_operation + + cipher = VoidPointer() + result = start_operation(c_uint8_ptr(key), + c_size_t(len(key)), + cipher.address_of()) + if result: + raise ValueError("Error %X while instantiating the AES cipher" + % result) + return SmartPointer(cipher.get(), stop_operation) + + +def _derive_Poly1305_key_pair(key, nonce): + """Derive a tuple (r, s, nonce) for a Poly1305 MAC. + + If nonce is ``None``, a new 16-byte nonce is generated. + """ + + if len(key) != 32: + raise ValueError("Poly1305 with AES requires a 32-byte key") + + if nonce is None: + nonce = get_random_bytes(16) + elif len(nonce) != 16: + raise ValueError("Poly1305 with AES requires a 16-byte nonce") + + s = new(key[:16], MODE_ECB).encrypt(nonce) + return key[16:], s, nonce + + +def new(key, mode, *args, **kwargs): + """Create a new AES cipher. + + Args: + key(bytes/bytearray/memoryview): + The secret key to use in the symmetric cipher. + + It must be 16 (*AES-128)*, 24 (*AES-192*) or 32 (*AES-256*) bytes long. + + For ``MODE_SIV`` only, it doubles to 32, 48, or 64 bytes. + mode (a ``MODE_*`` constant): + The chaining mode to use for encryption or decryption. + If in doubt, use ``MODE_EAX``. + + Keyword Args: + iv (bytes/bytearray/memoryview): + (Only applicable for ``MODE_CBC``, ``MODE_CFB``, ``MODE_OFB``, + and ``MODE_OPENPGP`` modes). + + The initialization vector to use for encryption or decryption. + + For ``MODE_CBC``, ``MODE_CFB``, and ``MODE_OFB`` it must be 16 bytes long. + + For ``MODE_OPENPGP`` mode only, + it must be 16 bytes long for encryption + and 18 bytes for decryption (in the latter case, it is + actually the *encrypted* IV which was prefixed to the ciphertext). + + If not provided, a random byte string is generated (you must then + read its value with the :attr:`iv` attribute). + + nonce (bytes/bytearray/memoryview): + (Only applicable for ``MODE_CCM``, ``MODE_EAX``, ``MODE_GCM``, + ``MODE_SIV``, ``MODE_OCB``, and ``MODE_CTR``). + + A value that must never be reused for any other encryption done + with this key (except possibly for ``MODE_SIV``, see below). + + For ``MODE_EAX``, ``MODE_GCM`` and ``MODE_SIV`` there are no + restrictions on its length (recommended: **16** bytes). + + For ``MODE_CCM``, its length must be in the range **[7..13]**. + Bear in mind that with CCM there is a trade-off between nonce + length and maximum message size. Recommendation: **11** bytes. + + For ``MODE_OCB``, its length must be in the range **[1..15]** + (recommended: **15**). + + For ``MODE_CTR``, its length must be in the range **[0..15]** + (recommended: **8**). + + For ``MODE_SIV``, the nonce is optional, if it is not specified, + then no nonce is being used, which renders the encryption + deterministic. + + If not provided, for modes other than ``MODE_SIV``, a random + byte string of the recommended length is used (you must then + read its value with the :attr:`nonce` attribute). + + segment_size (integer): + (Only ``MODE_CFB``).The number of **bits** the plaintext and ciphertext + are segmented in. It must be a multiple of 8. + If not specified, it will be assumed to be 8. + + mac_len (integer): + (Only ``MODE_EAX``, ``MODE_GCM``, ``MODE_OCB``, ``MODE_CCM``) + Length of the authentication tag, in bytes. + + It must be even and in the range **[4..16]**. + The recommended value (and the default, if not specified) is **16**. + + msg_len (integer): + (Only ``MODE_CCM``). Length of the message to (de)cipher. + If not specified, ``encrypt`` must be called with the entire message. + Similarly, ``decrypt`` can only be called once. + + assoc_len (integer): + (Only ``MODE_CCM``). Length of the associated data. + If not specified, all associated data is buffered internally, + which may represent a problem for very large messages. + + initial_value (integer or bytes/bytearray/memoryview): + (Only ``MODE_CTR``). + The initial value for the counter. If not present, the cipher will + start counting from 0. The value is incremented by one for each block. + The counter number is encoded in big endian mode. + + counter (object): + (Only ``MODE_CTR``). + Instance of ``Cryptodome.Util.Counter``, which allows full customization + of the counter block. This parameter is incompatible to both ``nonce`` + and ``initial_value``. + + use_aesni: (boolean): + Use Intel AES-NI hardware extensions (default: use if available). + + Returns: + an AES object, of the applicable mode. + """ + + kwargs["add_aes_modes"] = True + return _create_cipher(sys.modules[__name__], key, mode, *args, **kwargs) + + +# Size of a data block (in bytes) +block_size = 16 +# Size of a key (in bytes) +key_size = (16, 24, 32) diff --git a/venv/Lib/site-packages/Cryptodome/Cipher/AES.pyi b/venv/Lib/site-packages/Cryptodome/Cipher/AES.pyi new file mode 100644 index 0000000..3f07b65 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Cipher/AES.pyi @@ -0,0 +1,156 @@ +from typing import Dict, Optional, Tuple, Union, overload +from typing_extensions import Literal + +Buffer=bytes|bytearray|memoryview + +from Cryptodome.Cipher._mode_ecb import EcbMode +from Cryptodome.Cipher._mode_cbc import CbcMode +from Cryptodome.Cipher._mode_cfb import CfbMode +from Cryptodome.Cipher._mode_ofb import OfbMode +from Cryptodome.Cipher._mode_ctr import CtrMode +from Cryptodome.Cipher._mode_openpgp import OpenPgpMode +from Cryptodome.Cipher._mode_ccm import CcmMode +from Cryptodome.Cipher._mode_eax import EaxMode +from Cryptodome.Cipher._mode_gcm import GcmMode +from Cryptodome.Cipher._mode_siv import SivMode +from Cryptodome.Cipher._mode_ocb import OcbMode + +MODE_ECB: Literal[1] +MODE_CBC: Literal[2] +MODE_CFB: Literal[3] +MODE_OFB: Literal[5] +MODE_CTR: Literal[6] +MODE_OPENPGP: Literal[7] +MODE_CCM: Literal[8] +MODE_EAX: Literal[9] +MODE_SIV: Literal[10] +MODE_GCM: Literal[11] +MODE_OCB: Literal[12] + +# MODE_ECB +@overload +def new(key: Buffer, + mode: Literal[1], + use_aesni : bool = ...) -> \ + EcbMode: ... + +# MODE_CBC +@overload +def new(key: Buffer, + mode: Literal[2], + iv : Optional[Buffer] = ..., + use_aesni : bool = ...) -> \ + CbcMode: ... + +@overload +def new(key: Buffer, + mode: Literal[2], + IV : Optional[Buffer] = ..., + use_aesni : bool = ...) -> \ + CbcMode: ... + +# MODE_CFB +@overload +def new(key: Buffer, + mode: Literal[3], + iv : Optional[Buffer] = ..., + segment_size : int = ..., + use_aesni : bool = ...) -> \ + CfbMode: ... + +@overload +def new(key: Buffer, + mode: Literal[3], + IV : Optional[Buffer] = ..., + segment_size : int = ..., + use_aesni : bool = ...) -> \ + CfbMode: ... + +# MODE_OFB +@overload +def new(key: Buffer, + mode: Literal[5], + iv : Optional[Buffer] = ..., + use_aesni : bool = ...) -> \ + OfbMode: ... + +@overload +def new(key: Buffer, + mode: Literal[5], + IV : Optional[Buffer] = ..., + use_aesni : bool = ...) -> \ + OfbMode: ... + +# MODE_CTR +@overload +def new(key: Buffer, + mode: Literal[6], + nonce : Optional[Buffer] = ..., + initial_value : Union[int, Buffer] = ..., + counter : Dict = ..., + use_aesni : bool = ...) -> \ + CtrMode: ... + +# MODE_OPENPGP +@overload +def new(key: Buffer, + mode: Literal[7], + iv : Optional[Buffer] = ..., + use_aesni : bool = ...) -> \ + OpenPgpMode: ... + +@overload +def new(key: Buffer, + mode: Literal[7], + IV : Optional[Buffer] = ..., + use_aesni : bool = ...) -> \ + OpenPgpMode: ... + +# MODE_CCM +@overload +def new(key: Buffer, + mode: Literal[8], + nonce : Optional[Buffer] = ..., + mac_len : int = ..., + assoc_len : int = ..., + use_aesni : bool = ...) -> \ + CcmMode: ... + +# MODE_EAX +@overload +def new(key: Buffer, + mode: Literal[9], + nonce : Optional[Buffer] = ..., + mac_len : int = ..., + use_aesni : bool = ...) -> \ + EaxMode: ... + +# MODE_GCM +@overload +def new(key: Buffer, + mode: Literal[10], + nonce : Optional[Buffer] = ..., + use_aesni : bool = ...) -> \ + SivMode: ... + +# MODE_SIV +@overload +def new(key: Buffer, + mode: Literal[11], + nonce : Optional[Buffer] = ..., + mac_len : int = ..., + use_aesni : bool = ...) -> \ + GcmMode: ... + +# MODE_OCB +@overload +def new(key: Buffer, + mode: Literal[12], + nonce : Optional[Buffer] = ..., + mac_len : int = ..., + use_aesni : bool = ...) -> \ + OcbMode: ... + + +block_size: int +key_size: Tuple[int, int, int] diff --git a/venv/Lib/site-packages/Cryptodome/Cipher/ARC2.py b/venv/Lib/site-packages/Cryptodome/Cipher/ARC2.py new file mode 100644 index 0000000..4dc1bb8 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Cipher/ARC2.py @@ -0,0 +1,175 @@ +# -*- coding: utf-8 -*- +# +# Cipher/ARC2.py : ARC2.py +# +# =================================================================== +# The contents of this file are dedicated to the public domain. To +# the extent that dedication to the public domain is not available, +# everyone is granted a worldwide, perpetual, royalty-free, +# non-exclusive license to exercise all rights associated with the +# contents of this file for any purpose whatsoever. +# No rights are reserved. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# =================================================================== +""" +Module's constants for the modes of operation supported with ARC2: + +:var MODE_ECB: :ref:`Electronic Code Book (ECB) ` +:var MODE_CBC: :ref:`Cipher-Block Chaining (CBC) ` +:var MODE_CFB: :ref:`Cipher FeedBack (CFB) ` +:var MODE_OFB: :ref:`Output FeedBack (OFB) ` +:var MODE_CTR: :ref:`CounTer Mode (CTR) ` +:var MODE_OPENPGP: :ref:`OpenPGP Mode ` +:var MODE_EAX: :ref:`EAX Mode ` +""" + +import sys + +from Cryptodome.Cipher import _create_cipher +from Cryptodome.Util.py3compat import byte_string +from Cryptodome.Util._raw_api import (load_pycryptodome_raw_lib, + VoidPointer, SmartPointer, + c_size_t, c_uint8_ptr) + +_raw_arc2_lib = load_pycryptodome_raw_lib( + "Cryptodome.Cipher._raw_arc2", + """ + int ARC2_start_operation(const uint8_t key[], + size_t key_len, + size_t effective_key_len, + void **pResult); + int ARC2_encrypt(const void *state, + const uint8_t *in, + uint8_t *out, + size_t data_len); + int ARC2_decrypt(const void *state, + const uint8_t *in, + uint8_t *out, + size_t data_len); + int ARC2_stop_operation(void *state); + """ + ) + + +def _create_base_cipher(dict_parameters): + """This method instantiates and returns a handle to a low-level + base cipher. It will absorb named parameters in the process.""" + + try: + key = dict_parameters.pop("key") + except KeyError: + raise TypeError("Missing 'key' parameter") + + effective_keylen = dict_parameters.pop("effective_keylen", 1024) + + if len(key) not in key_size: + raise ValueError("Incorrect ARC2 key length (%d bytes)" % len(key)) + + if not (40 <= effective_keylen <= 1024): + raise ValueError("'effective_key_len' must be at least 40 and no larger than 1024 " + "(not %d)" % effective_keylen) + + start_operation = _raw_arc2_lib.ARC2_start_operation + stop_operation = _raw_arc2_lib.ARC2_stop_operation + + cipher = VoidPointer() + result = start_operation(c_uint8_ptr(key), + c_size_t(len(key)), + c_size_t(effective_keylen), + cipher.address_of()) + if result: + raise ValueError("Error %X while instantiating the ARC2 cipher" + % result) + + return SmartPointer(cipher.get(), stop_operation) + + +def new(key, mode, *args, **kwargs): + """Create a new RC2 cipher. + + :param key: + The secret key to use in the symmetric cipher. + Its length can vary from 5 to 128 bytes; the actual search space + (and the cipher strength) can be reduced with the ``effective_keylen`` parameter. + :type key: bytes, bytearray, memoryview + + :param mode: + The chaining mode to use for encryption or decryption. + :type mode: One of the supported ``MODE_*`` constants + + :Keyword Arguments: + * **iv** (*bytes*, *bytearray*, *memoryview*) -- + (Only applicable for ``MODE_CBC``, ``MODE_CFB``, ``MODE_OFB``, + and ``MODE_OPENPGP`` modes). + + The initialization vector to use for encryption or decryption. + + For ``MODE_CBC``, ``MODE_CFB``, and ``MODE_OFB`` it must be 8 bytes long. + + For ``MODE_OPENPGP`` mode only, + it must be 8 bytes long for encryption + and 10 bytes for decryption (in the latter case, it is + actually the *encrypted* IV which was prefixed to the ciphertext). + + If not provided, a random byte string is generated (you must then + read its value with the :attr:`iv` attribute). + + * **nonce** (*bytes*, *bytearray*, *memoryview*) -- + (Only applicable for ``MODE_EAX`` and ``MODE_CTR``). + + A value that must never be reused for any other encryption done + with this key. + + For ``MODE_EAX`` there are no + restrictions on its length (recommended: **16** bytes). + + For ``MODE_CTR``, its length must be in the range **[0..7]**. + + If not provided for ``MODE_EAX``, a random byte string is generated (you + can read it back via the ``nonce`` attribute). + + * **effective_keylen** (*integer*) -- + Optional. Maximum strength in bits of the actual key used by the ARC2 algorithm. + If the supplied ``key`` parameter is longer (in bits) of the value specified + here, it will be weakened to match it. + If not specified, no limitation is applied. + + * **segment_size** (*integer*) -- + (Only ``MODE_CFB``).The number of **bits** the plaintext and ciphertext + are segmented in. It must be a multiple of 8. + If not specified, it will be assumed to be 8. + + * **mac_len** : (*integer*) -- + (Only ``MODE_EAX``) + Length of the authentication tag, in bytes. + It must be no longer than 8 (default). + + * **initial_value** : (*integer*) -- + (Only ``MODE_CTR``). The initial value for the counter within + the counter block. By default it is **0**. + + :Return: an ARC2 object, of the applicable mode. + """ + + return _create_cipher(sys.modules[__name__], key, mode, *args, **kwargs) + +MODE_ECB = 1 +MODE_CBC = 2 +MODE_CFB = 3 +MODE_OFB = 5 +MODE_CTR = 6 +MODE_OPENPGP = 7 +MODE_EAX = 9 + +# Size of a data block (in bytes) +block_size = 8 +# Size of a key (in bytes) +key_size = range(5, 128 + 1) diff --git a/venv/Lib/site-packages/Cryptodome/Cipher/ARC2.pyi b/venv/Lib/site-packages/Cryptodome/Cipher/ARC2.pyi new file mode 100644 index 0000000..a122a52 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Cipher/ARC2.pyi @@ -0,0 +1,35 @@ +from typing import Union, Dict, Iterable, Optional + +Buffer = bytes|bytearray|memoryview + +from Cryptodome.Cipher._mode_ecb import EcbMode +from Cryptodome.Cipher._mode_cbc import CbcMode +from Cryptodome.Cipher._mode_cfb import CfbMode +from Cryptodome.Cipher._mode_ofb import OfbMode +from Cryptodome.Cipher._mode_ctr import CtrMode +from Cryptodome.Cipher._mode_openpgp import OpenPgpMode +from Cryptodome.Cipher._mode_eax import EaxMode + +ARC2Mode = int + +MODE_ECB: ARC2Mode +MODE_CBC: ARC2Mode +MODE_CFB: ARC2Mode +MODE_OFB: ARC2Mode +MODE_CTR: ARC2Mode +MODE_OPENPGP: ARC2Mode +MODE_EAX: ARC2Mode + +def new(key: Buffer, + mode: ARC2Mode, + iv : Optional[Buffer] = ..., + IV : Optional[Buffer] = ..., + nonce : Optional[Buffer] = ..., + segment_size : int = ..., + mac_len : int = ..., + initial_value : Union[int, Buffer] = ..., + counter : Dict = ...) -> \ + Union[EcbMode, CbcMode, CfbMode, OfbMode, CtrMode, OpenPgpMode]: ... + +block_size: int +key_size: Iterable[int] diff --git a/venv/Lib/site-packages/Cryptodome/Cipher/ARC4.py b/venv/Lib/site-packages/Cryptodome/Cipher/ARC4.py new file mode 100644 index 0000000..543a323 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Cipher/ARC4.py @@ -0,0 +1,136 @@ +# -*- coding: utf-8 -*- +# +# Cipher/ARC4.py : ARC4 +# +# =================================================================== +# The contents of this file are dedicated to the public domain. To +# the extent that dedication to the public domain is not available, +# everyone is granted a worldwide, perpetual, royalty-free, +# non-exclusive license to exercise all rights associated with the +# contents of this file for any purpose whatsoever. +# No rights are reserved. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# =================================================================== + +from Cryptodome.Util._raw_api import (load_pycryptodome_raw_lib, VoidPointer, + create_string_buffer, get_raw_buffer, + SmartPointer, c_size_t, c_uint8_ptr) + + +_raw_arc4_lib = load_pycryptodome_raw_lib("Cryptodome.Cipher._ARC4", """ + int ARC4_stream_encrypt(void *rc4State, const uint8_t in[], + uint8_t out[], size_t len); + int ARC4_stream_init(uint8_t *key, size_t keylen, + void **pRc4State); + int ARC4_stream_destroy(void *rc4State); + """) + + +class ARC4Cipher: + """ARC4 cipher object. Do not create it directly. Use + :func:`Cryptodome.Cipher.ARC4.new` instead. + """ + + def __init__(self, key, *args, **kwargs): + """Initialize an ARC4 cipher object + + See also `new()` at the module level.""" + + if len(args) > 0: + ndrop = args[0] + args = args[1:] + else: + ndrop = kwargs.pop('drop', 0) + + if len(key) not in key_size: + raise ValueError("Incorrect ARC4 key length (%d bytes)" % + len(key)) + + self._state = VoidPointer() + result = _raw_arc4_lib.ARC4_stream_init(c_uint8_ptr(key), + c_size_t(len(key)), + self._state.address_of()) + if result != 0: + raise ValueError("Error %d while creating the ARC4 cipher" + % result) + self._state = SmartPointer(self._state.get(), + _raw_arc4_lib.ARC4_stream_destroy) + + if ndrop > 0: + # This is OK even if the cipher is used for decryption, + # since encrypt and decrypt are actually the same thing + # with ARC4. + self.encrypt(b'\x00' * ndrop) + + self.block_size = 1 + self.key_size = len(key) + + def encrypt(self, plaintext): + """Encrypt a piece of data. + + :param plaintext: The data to encrypt, of any size. + :type plaintext: bytes, bytearray, memoryview + :returns: the encrypted byte string, of equal length as the + plaintext. + """ + + ciphertext = create_string_buffer(len(plaintext)) + result = _raw_arc4_lib.ARC4_stream_encrypt(self._state.get(), + c_uint8_ptr(plaintext), + ciphertext, + c_size_t(len(plaintext))) + if result: + raise ValueError("Error %d while encrypting with RC4" % result) + return get_raw_buffer(ciphertext) + + def decrypt(self, ciphertext): + """Decrypt a piece of data. + + :param ciphertext: The data to decrypt, of any size. + :type ciphertext: bytes, bytearray, memoryview + :returns: the decrypted byte string, of equal length as the + ciphertext. + """ + + try: + return self.encrypt(ciphertext) + except ValueError as e: + raise ValueError(str(e).replace("enc", "dec")) + + +def new(key, *args, **kwargs): + """Create a new ARC4 cipher. + + :param key: + The secret key to use in the symmetric cipher. + Its length must be in the range ``[1..256]``. + The recommended length is 16 bytes. + :type key: bytes, bytearray, memoryview + + :Keyword Arguments: + * *drop* (``integer``) -- + The amount of bytes to discard from the initial part of the keystream. + In fact, such part has been found to be distinguishable from random + data (while it shouldn't) and also correlated to key. + + The recommended value is 3072_ bytes. The default value is 0. + + :Return: an `ARC4Cipher` object + + .. _3072: http://eprint.iacr.org/2002/067.pdf + """ + return ARC4Cipher(key, *args, **kwargs) + + +# Size of a data block (in bytes) +block_size = 1 +# Size of a key (in bytes) +key_size = range(1, 256+1) diff --git a/venv/Lib/site-packages/Cryptodome/Cipher/ARC4.pyi b/venv/Lib/site-packages/Cryptodome/Cipher/ARC4.pyi new file mode 100644 index 0000000..b081585 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Cipher/ARC4.pyi @@ -0,0 +1,16 @@ +from typing import Any, Union, Iterable + +Buffer = bytes|bytearray|memoryview + +class ARC4Cipher: + block_size: int + key_size: int + + def __init__(self, key: Buffer, *args: Any, **kwargs: Any) -> None: ... + def encrypt(self, plaintext: Buffer) -> bytes: ... + def decrypt(self, ciphertext: Buffer) -> bytes: ... + +def new(key: Buffer, drop : int = ...) -> ARC4Cipher: ... + +block_size: int +key_size: Iterable[int] diff --git a/venv/Lib/site-packages/Cryptodome/Cipher/Blowfish.py b/venv/Lib/site-packages/Cryptodome/Cipher/Blowfish.py new file mode 100644 index 0000000..536cbc8 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Cipher/Blowfish.py @@ -0,0 +1,159 @@ +# -*- coding: utf-8 -*- +# +# Cipher/Blowfish.py : Blowfish +# +# =================================================================== +# The contents of this file are dedicated to the public domain. To +# the extent that dedication to the public domain is not available, +# everyone is granted a worldwide, perpetual, royalty-free, +# non-exclusive license to exercise all rights associated with the +# contents of this file for any purpose whatsoever. +# No rights are reserved. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# =================================================================== +""" +Module's constants for the modes of operation supported with Blowfish: + +:var MODE_ECB: :ref:`Electronic Code Book (ECB) ` +:var MODE_CBC: :ref:`Cipher-Block Chaining (CBC) ` +:var MODE_CFB: :ref:`Cipher FeedBack (CFB) ` +:var MODE_OFB: :ref:`Output FeedBack (OFB) ` +:var MODE_CTR: :ref:`CounTer Mode (CTR) ` +:var MODE_OPENPGP: :ref:`OpenPGP Mode ` +:var MODE_EAX: :ref:`EAX Mode ` +""" + +import sys + +from Cryptodome.Cipher import _create_cipher +from Cryptodome.Util._raw_api import (load_pycryptodome_raw_lib, + VoidPointer, SmartPointer, c_size_t, + c_uint8_ptr) + +_raw_blowfish_lib = load_pycryptodome_raw_lib( + "Cryptodome.Cipher._raw_blowfish", + """ + int Blowfish_start_operation(const uint8_t key[], + size_t key_len, + void **pResult); + int Blowfish_encrypt(const void *state, + const uint8_t *in, + uint8_t *out, + size_t data_len); + int Blowfish_decrypt(const void *state, + const uint8_t *in, + uint8_t *out, + size_t data_len); + int Blowfish_stop_operation(void *state); + """ + ) + + +def _create_base_cipher(dict_parameters): + """This method instantiates and returns a smart pointer to + a low-level base cipher. It will absorb named parameters in + the process.""" + + try: + key = dict_parameters.pop("key") + except KeyError: + raise TypeError("Missing 'key' parameter") + + if len(key) not in key_size: + raise ValueError("Incorrect Blowfish key length (%d bytes)" % len(key)) + + start_operation = _raw_blowfish_lib.Blowfish_start_operation + stop_operation = _raw_blowfish_lib.Blowfish_stop_operation + + void_p = VoidPointer() + result = start_operation(c_uint8_ptr(key), + c_size_t(len(key)), + void_p.address_of()) + if result: + raise ValueError("Error %X while instantiating the Blowfish cipher" + % result) + return SmartPointer(void_p.get(), stop_operation) + + +def new(key, mode, *args, **kwargs): + """Create a new Blowfish cipher + + :param key: + The secret key to use in the symmetric cipher. + Its length can vary from 5 to 56 bytes. + :type key: bytes, bytearray, memoryview + + :param mode: + The chaining mode to use for encryption or decryption. + :type mode: One of the supported ``MODE_*`` constants + + :Keyword Arguments: + * **iv** (*bytes*, *bytearray*, *memoryview*) -- + (Only applicable for ``MODE_CBC``, ``MODE_CFB``, ``MODE_OFB``, + and ``MODE_OPENPGP`` modes). + + The initialization vector to use for encryption or decryption. + + For ``MODE_CBC``, ``MODE_CFB``, and ``MODE_OFB`` it must be 8 bytes long. + + For ``MODE_OPENPGP`` mode only, + it must be 8 bytes long for encryption + and 10 bytes for decryption (in the latter case, it is + actually the *encrypted* IV which was prefixed to the ciphertext). + + If not provided, a random byte string is generated (you must then + read its value with the :attr:`iv` attribute). + + * **nonce** (*bytes*, *bytearray*, *memoryview*) -- + (Only applicable for ``MODE_EAX`` and ``MODE_CTR``). + + A value that must never be reused for any other encryption done + with this key. + + For ``MODE_EAX`` there are no + restrictions on its length (recommended: **16** bytes). + + For ``MODE_CTR``, its length must be in the range **[0..7]**. + + If not provided for ``MODE_EAX``, a random byte string is generated (you + can read it back via the ``nonce`` attribute). + + * **segment_size** (*integer*) -- + (Only ``MODE_CFB``).The number of **bits** the plaintext and ciphertext + are segmented in. It must be a multiple of 8. + If not specified, it will be assumed to be 8. + + * **mac_len** : (*integer*) -- + (Only ``MODE_EAX``) + Length of the authentication tag, in bytes. + It must be no longer than 8 (default). + + * **initial_value** : (*integer*) -- + (Only ``MODE_CTR``). The initial value for the counter within + the counter block. By default it is **0**. + + :Return: a Blowfish object, of the applicable mode. + """ + + return _create_cipher(sys.modules[__name__], key, mode, *args, **kwargs) + +MODE_ECB = 1 +MODE_CBC = 2 +MODE_CFB = 3 +MODE_OFB = 5 +MODE_CTR = 6 +MODE_OPENPGP = 7 +MODE_EAX = 9 + +# Size of a data block (in bytes) +block_size = 8 +# Size of a key (in bytes) +key_size = range(4, 56 + 1) diff --git a/venv/Lib/site-packages/Cryptodome/Cipher/Blowfish.pyi b/venv/Lib/site-packages/Cryptodome/Cipher/Blowfish.pyi new file mode 100644 index 0000000..b8b21c6 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Cipher/Blowfish.pyi @@ -0,0 +1,35 @@ +from typing import Union, Dict, Iterable, Optional + +Buffer = bytes|bytearray|memoryview + +from Cryptodome.Cipher._mode_ecb import EcbMode +from Cryptodome.Cipher._mode_cbc import CbcMode +from Cryptodome.Cipher._mode_cfb import CfbMode +from Cryptodome.Cipher._mode_ofb import OfbMode +from Cryptodome.Cipher._mode_ctr import CtrMode +from Cryptodome.Cipher._mode_openpgp import OpenPgpMode +from Cryptodome.Cipher._mode_eax import EaxMode + +BlowfishMode = int + +MODE_ECB: BlowfishMode +MODE_CBC: BlowfishMode +MODE_CFB: BlowfishMode +MODE_OFB: BlowfishMode +MODE_CTR: BlowfishMode +MODE_OPENPGP: BlowfishMode +MODE_EAX: BlowfishMode + +def new(key: Buffer, + mode: BlowfishMode, + iv : Optional[Buffer] = ..., + IV : Optional[Buffer] = ..., + nonce : Optional[Buffer] = ..., + segment_size : int = ..., + mac_len : int = ..., + initial_value : Union[int, Buffer] = ..., + counter : Dict = ...) -> \ + Union[EcbMode, CbcMode, CfbMode, OfbMode, CtrMode, OpenPgpMode]: ... + +block_size: int +key_size: Iterable[int] diff --git a/venv/Lib/site-packages/Cryptodome/Cipher/CAST.py b/venv/Lib/site-packages/Cryptodome/Cipher/CAST.py new file mode 100644 index 0000000..84eb88e --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Cipher/CAST.py @@ -0,0 +1,159 @@ +# -*- coding: utf-8 -*- +# +# Cipher/CAST.py : CAST +# +# =================================================================== +# The contents of this file are dedicated to the public domain. To +# the extent that dedication to the public domain is not available, +# everyone is granted a worldwide, perpetual, royalty-free, +# non-exclusive license to exercise all rights associated with the +# contents of this file for any purpose whatsoever. +# No rights are reserved. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# =================================================================== +""" +Module's constants for the modes of operation supported with CAST: + +:var MODE_ECB: :ref:`Electronic Code Book (ECB) ` +:var MODE_CBC: :ref:`Cipher-Block Chaining (CBC) ` +:var MODE_CFB: :ref:`Cipher FeedBack (CFB) ` +:var MODE_OFB: :ref:`Output FeedBack (OFB) ` +:var MODE_CTR: :ref:`CounTer Mode (CTR) ` +:var MODE_OPENPGP: :ref:`OpenPGP Mode ` +:var MODE_EAX: :ref:`EAX Mode ` +""" + +import sys + +from Cryptodome.Cipher import _create_cipher +from Cryptodome.Util.py3compat import byte_string +from Cryptodome.Util._raw_api import (load_pycryptodome_raw_lib, + VoidPointer, SmartPointer, + c_size_t, c_uint8_ptr) + +_raw_cast_lib = load_pycryptodome_raw_lib( + "Cryptodome.Cipher._raw_cast", + """ + int CAST_start_operation(const uint8_t key[], + size_t key_len, + void **pResult); + int CAST_encrypt(const void *state, + const uint8_t *in, + uint8_t *out, + size_t data_len); + int CAST_decrypt(const void *state, + const uint8_t *in, + uint8_t *out, + size_t data_len); + int CAST_stop_operation(void *state); + """) + + +def _create_base_cipher(dict_parameters): + """This method instantiates and returns a handle to a low-level + base cipher. It will absorb named parameters in the process.""" + + try: + key = dict_parameters.pop("key") + except KeyError: + raise TypeError("Missing 'key' parameter") + + if len(key) not in key_size: + raise ValueError("Incorrect CAST key length (%d bytes)" % len(key)) + + start_operation = _raw_cast_lib.CAST_start_operation + stop_operation = _raw_cast_lib.CAST_stop_operation + + cipher = VoidPointer() + result = start_operation(c_uint8_ptr(key), + c_size_t(len(key)), + cipher.address_of()) + if result: + raise ValueError("Error %X while instantiating the CAST cipher" + % result) + + return SmartPointer(cipher.get(), stop_operation) + + +def new(key, mode, *args, **kwargs): + """Create a new CAST cipher + + :param key: + The secret key to use in the symmetric cipher. + Its length can vary from 5 to 16 bytes. + :type key: bytes, bytearray, memoryview + + :param mode: + The chaining mode to use for encryption or decryption. + :type mode: One of the supported ``MODE_*`` constants + + :Keyword Arguments: + * **iv** (*bytes*, *bytearray*, *memoryview*) -- + (Only applicable for ``MODE_CBC``, ``MODE_CFB``, ``MODE_OFB``, + and ``MODE_OPENPGP`` modes). + + The initialization vector to use for encryption or decryption. + + For ``MODE_CBC``, ``MODE_CFB``, and ``MODE_OFB`` it must be 8 bytes long. + + For ``MODE_OPENPGP`` mode only, + it must be 8 bytes long for encryption + and 10 bytes for decryption (in the latter case, it is + actually the *encrypted* IV which was prefixed to the ciphertext). + + If not provided, a random byte string is generated (you must then + read its value with the :attr:`iv` attribute). + + * **nonce** (*bytes*, *bytearray*, *memoryview*) -- + (Only applicable for ``MODE_EAX`` and ``MODE_CTR``). + + A value that must never be reused for any other encryption done + with this key. + + For ``MODE_EAX`` there are no + restrictions on its length (recommended: **16** bytes). + + For ``MODE_CTR``, its length must be in the range **[0..7]**. + + If not provided for ``MODE_EAX``, a random byte string is generated (you + can read it back via the ``nonce`` attribute). + + * **segment_size** (*integer*) -- + (Only ``MODE_CFB``).The number of **bits** the plaintext and ciphertext + are segmented in. It must be a multiple of 8. + If not specified, it will be assumed to be 8. + + * **mac_len** : (*integer*) -- + (Only ``MODE_EAX``) + Length of the authentication tag, in bytes. + It must be no longer than 8 (default). + + * **initial_value** : (*integer*) -- + (Only ``MODE_CTR``). The initial value for the counter within + the counter block. By default it is **0**. + + :Return: a CAST object, of the applicable mode. + """ + + return _create_cipher(sys.modules[__name__], key, mode, *args, **kwargs) + +MODE_ECB = 1 +MODE_CBC = 2 +MODE_CFB = 3 +MODE_OFB = 5 +MODE_CTR = 6 +MODE_OPENPGP = 7 +MODE_EAX = 9 + +# Size of a data block (in bytes) +block_size = 8 +# Size of a key (in bytes) +key_size = range(5, 16 + 1) diff --git a/venv/Lib/site-packages/Cryptodome/Cipher/CAST.pyi b/venv/Lib/site-packages/Cryptodome/Cipher/CAST.pyi new file mode 100644 index 0000000..be01f09 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Cipher/CAST.pyi @@ -0,0 +1,35 @@ +from typing import Union, Dict, Iterable, Optional + +Buffer = bytes|bytearray|memoryview + +from Cryptodome.Cipher._mode_ecb import EcbMode +from Cryptodome.Cipher._mode_cbc import CbcMode +from Cryptodome.Cipher._mode_cfb import CfbMode +from Cryptodome.Cipher._mode_ofb import OfbMode +from Cryptodome.Cipher._mode_ctr import CtrMode +from Cryptodome.Cipher._mode_openpgp import OpenPgpMode +from Cryptodome.Cipher._mode_eax import EaxMode + +CASTMode = int + +MODE_ECB: CASTMode +MODE_CBC: CASTMode +MODE_CFB: CASTMode +MODE_OFB: CASTMode +MODE_CTR: CASTMode +MODE_OPENPGP: CASTMode +MODE_EAX: CASTMode + +def new(key: Buffer, + mode: CASTMode, + iv : Optional[Buffer] = ..., + IV : Optional[Buffer] = ..., + nonce : Optional[Buffer] = ..., + segment_size : int = ..., + mac_len : int = ..., + initial_value : Union[int, Buffer] = ..., + counter : Dict = ...) -> \ + Union[EcbMode, CbcMode, CfbMode, OfbMode, CtrMode, OpenPgpMode]: ... + +block_size: int +key_size : Iterable[int] diff --git a/venv/Lib/site-packages/Cryptodome/Cipher/ChaCha20.py b/venv/Lib/site-packages/Cryptodome/Cipher/ChaCha20.py new file mode 100644 index 0000000..b2759b9 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Cipher/ChaCha20.py @@ -0,0 +1,291 @@ +# =================================================================== +# +# Copyright (c) 2014, Legrandin +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# =================================================================== + +from Cryptodome.Random import get_random_bytes + +from Cryptodome.Util.py3compat import _copy_bytes +from Cryptodome.Util._raw_api import (load_pycryptodome_raw_lib, + create_string_buffer, + get_raw_buffer, VoidPointer, + SmartPointer, c_size_t, + c_uint8_ptr, c_ulong, + is_writeable_buffer) + +_raw_chacha20_lib = load_pycryptodome_raw_lib("Cryptodome.Cipher._chacha20", + """ + int chacha20_init(void **pState, + const uint8_t *key, + size_t keySize, + const uint8_t *nonce, + size_t nonceSize); + + int chacha20_destroy(void *state); + + int chacha20_encrypt(void *state, + const uint8_t in[], + uint8_t out[], + size_t len); + + int chacha20_seek(void *state, + unsigned long block_high, + unsigned long block_low, + unsigned offset); + + int hchacha20( const uint8_t key[32], + const uint8_t nonce16[16], + uint8_t subkey[32]); + """) + + +def _HChaCha20(key, nonce): + + assert(len(key) == 32) + assert(len(nonce) == 16) + + subkey = bytearray(32) + result = _raw_chacha20_lib.hchacha20( + c_uint8_ptr(key), + c_uint8_ptr(nonce), + c_uint8_ptr(subkey)) + if result: + raise ValueError("Error %d when deriving subkey with HChaCha20" % result) + + return subkey + + +class ChaCha20Cipher(object): + """ChaCha20 (or XChaCha20) cipher object. + Do not create it directly. Use :py:func:`new` instead. + + :var nonce: The nonce with length 8, 12 or 24 bytes + :vartype nonce: bytes + """ + + block_size = 1 + + def __init__(self, key, nonce): + """Initialize a ChaCha20/XChaCha20 cipher object + + See also `new()` at the module level.""" + + self.nonce = _copy_bytes(None, None, nonce) + + # XChaCha20 requires a key derivation with HChaCha20 + # See 2.3 in https://tools.ietf.org/html/draft-arciszewski-xchacha-03 + if len(nonce) == 24: + key = _HChaCha20(key, nonce[:16]) + nonce = b'\x00' * 4 + nonce[16:] + self._name = "XChaCha20" + else: + self._name = "ChaCha20" + nonce = self.nonce + + self._next = ("encrypt", "decrypt") + + self._state = VoidPointer() + result = _raw_chacha20_lib.chacha20_init( + self._state.address_of(), + c_uint8_ptr(key), + c_size_t(len(key)), + nonce, + c_size_t(len(nonce))) + if result: + raise ValueError("Error %d instantiating a %s cipher" % (result, + self._name)) + self._state = SmartPointer(self._state.get(), + _raw_chacha20_lib.chacha20_destroy) + + def encrypt(self, plaintext, output=None): + """Encrypt a piece of data. + + Args: + plaintext(bytes/bytearray/memoryview): The data to encrypt, of any size. + Keyword Args: + output(bytes/bytearray/memoryview): The location where the ciphertext + is written to. If ``None``, the ciphertext is returned. + Returns: + If ``output`` is ``None``, the ciphertext is returned as ``bytes``. + Otherwise, ``None``. + """ + + if "encrypt" not in self._next: + raise TypeError("Cipher object can only be used for decryption") + self._next = ("encrypt",) + return self._encrypt(plaintext, output) + + def _encrypt(self, plaintext, output): + """Encrypt without FSM checks""" + + if output is None: + ciphertext = create_string_buffer(len(plaintext)) + else: + ciphertext = output + + if not is_writeable_buffer(output): + raise TypeError("output must be a bytearray or a writeable memoryview") + + if len(plaintext) != len(output): + raise ValueError("output must have the same length as the input" + " (%d bytes)" % len(plaintext)) + + result = _raw_chacha20_lib.chacha20_encrypt( + self._state.get(), + c_uint8_ptr(plaintext), + c_uint8_ptr(ciphertext), + c_size_t(len(plaintext))) + if result: + raise ValueError("Error %d while encrypting with %s" % (result, self._name)) + + if output is None: + return get_raw_buffer(ciphertext) + else: + return None + + def decrypt(self, ciphertext, output=None): + """Decrypt a piece of data. + + Args: + ciphertext(bytes/bytearray/memoryview): The data to decrypt, of any size. + Keyword Args: + output(bytes/bytearray/memoryview): The location where the plaintext + is written to. If ``None``, the plaintext is returned. + Returns: + If ``output`` is ``None``, the plaintext is returned as ``bytes``. + Otherwise, ``None``. + """ + + if "decrypt" not in self._next: + raise TypeError("Cipher object can only be used for encryption") + self._next = ("decrypt",) + + try: + return self._encrypt(ciphertext, output) + except ValueError as e: + raise ValueError(str(e).replace("enc", "dec")) + + def seek(self, position): + """Seek to a certain position in the key stream. + + If you want to seek to a certain block, + use ``seek(block_number * 64)``. + + Args: + position (integer): + The absolute position within the key stream, in bytes. + """ + + block_number, offset = divmod(position, 64) + block_low = block_number & 0xFFFFFFFF + block_high = block_number >> 32 + + result = _raw_chacha20_lib.chacha20_seek( + self._state.get(), + c_ulong(block_high), + c_ulong(block_low), + offset + ) + if result: + raise ValueError("Error %d while seeking with %s" % (result, self._name)) + + +def _derive_Poly1305_key_pair(key, nonce): + """Derive a tuple (r, s, nonce) for a Poly1305 MAC. + + If nonce is ``None``, a new 12-byte nonce is generated. + """ + + if len(key) != 32: + raise ValueError("Poly1305 with ChaCha20 requires a 32-byte key") + + if nonce is None: + padded_nonce = nonce = get_random_bytes(12) + elif len(nonce) == 8: + # See RFC7538, 2.6: [...] ChaCha20 as specified here requires a 96-bit + # nonce. So if the provided nonce is only 64-bit, then the first 32 + # bits of the nonce will be set to a constant number. + # This will usually be zero, but for protocols with multiple senders it may be + # different for each sender, but should be the same for all + # invocations of the function with the same key by a particular + # sender. + padded_nonce = b'\x00\x00\x00\x00' + nonce + elif len(nonce) == 12: + padded_nonce = nonce + else: + raise ValueError("Poly1305 with ChaCha20 requires an 8- or 12-byte nonce") + + rs = new(key=key, nonce=padded_nonce).encrypt(b'\x00' * 32) + return rs[:16], rs[16:], nonce + + +def new(**kwargs): + """Create a new ChaCha20 or XChaCha20 cipher + + Keyword Args: + key (bytes/bytearray/memoryview): The secret key to use. + It must be 32 bytes long. + nonce (bytes/bytearray/memoryview): A mandatory value that + must never be reused for any other encryption + done with this key. + + For ChaCha20, it must be 8 or 12 bytes long. + + For XChaCha20, it must be 24 bytes long. + + If not provided, 8 bytes will be randomly generated + (you can find them back in the ``nonce`` attribute). + + :Return: a :class:`Cryptodome.Cipher.ChaCha20.ChaCha20Cipher` object + """ + + try: + key = kwargs.pop("key") + except KeyError as e: + raise TypeError("Missing parameter %s" % e) + + nonce = kwargs.pop("nonce", None) + if nonce is None: + nonce = get_random_bytes(8) + + if len(key) != 32: + raise ValueError("ChaCha20/XChaCha20 key must be 32 bytes long") + + if len(nonce) not in (8, 12, 24): + raise ValueError("Nonce must be 8/12 bytes(ChaCha20) or 24 bytes (XChaCha20)") + + if kwargs: + raise TypeError("Unknown parameters: " + str(kwargs)) + + return ChaCha20Cipher(key, nonce) + +# Size of a data block (in bytes) +block_size = 1 + +# Size of a key (in bytes) +key_size = 32 diff --git a/venv/Lib/site-packages/Cryptodome/Cipher/ChaCha20.pyi b/venv/Lib/site-packages/Cryptodome/Cipher/ChaCha20.pyi new file mode 100644 index 0000000..f5001cd --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Cipher/ChaCha20.pyi @@ -0,0 +1,25 @@ +from typing import Union, overload, Optional + +Buffer = bytes|bytearray|memoryview + +def _HChaCha20(key: Buffer, nonce: Buffer) -> bytearray: ... + +class ChaCha20Cipher: + block_size: int + nonce: bytes + + def __init__(self, key: Buffer, nonce: Buffer) -> None: ... + @overload + def encrypt(self, plaintext: Buffer) -> bytes: ... + @overload + def encrypt(self, plaintext: Buffer, output: Union[bytearray, memoryview]) -> None: ... + @overload + def decrypt(self, plaintext: Buffer) -> bytes: ... + @overload + def decrypt(self, plaintext: Buffer, output: Union[bytearray, memoryview]) -> None: ... + def seek(self, position: int) -> None: ... + +def new(key: Buffer, nonce: Optional[Buffer] = ...) -> ChaCha20Cipher: ... + +block_size: int +key_size: int diff --git a/venv/Lib/site-packages/Cryptodome/Cipher/ChaCha20_Poly1305.py b/venv/Lib/site-packages/Cryptodome/Cipher/ChaCha20_Poly1305.py new file mode 100644 index 0000000..6a89e2a --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Cipher/ChaCha20_Poly1305.py @@ -0,0 +1,334 @@ +# =================================================================== +# +# Copyright (c) 2018, Helder Eijs +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# =================================================================== + +from binascii import unhexlify + +from Cryptodome.Cipher import ChaCha20 +from Cryptodome.Cipher.ChaCha20 import _HChaCha20 +from Cryptodome.Hash import Poly1305, BLAKE2s + +from Cryptodome.Random import get_random_bytes + +from Cryptodome.Util.number import long_to_bytes +from Cryptodome.Util.py3compat import _copy_bytes, bord +from Cryptodome.Util._raw_api import is_buffer + + +def _enum(**enums): + return type('Enum', (), enums) + + +_CipherStatus = _enum(PROCESSING_AUTH_DATA=1, + PROCESSING_CIPHERTEXT=2, + PROCESSING_DONE=3) + + +class ChaCha20Poly1305Cipher(object): + """ChaCha20-Poly1305 and XChaCha20-Poly1305 cipher object. + Do not create it directly. Use :py:func:`new` instead. + + :var nonce: The nonce with length 8, 12 or 24 bytes + :vartype nonce: byte string + """ + + def __init__(self, key, nonce): + """Initialize a ChaCha20-Poly1305 AEAD cipher object + + See also `new()` at the module level.""" + + self._next = ("update", "encrypt", "decrypt", "digest", + "verify") + + self._authenticator = Poly1305.new(key=key, nonce=nonce, cipher=ChaCha20) + + self._cipher = ChaCha20.new(key=key, nonce=nonce) + self._cipher.seek(64) # Block counter starts at 1 + + self._len_aad = 0 + self._len_ct = 0 + self._mac_tag = None + self._status = _CipherStatus.PROCESSING_AUTH_DATA + + def update(self, data): + """Protect the associated data. + + Associated data (also known as *additional authenticated data* - AAD) + is the piece of the message that must stay in the clear, while + still allowing the receiver to verify its integrity. + An example is packet headers. + + The associated data (possibly split into multiple segments) is + fed into :meth:`update` before any call to :meth:`decrypt` or :meth:`encrypt`. + If there is no associated data, :meth:`update` is not called. + + :param bytes/bytearray/memoryview assoc_data: + A piece of associated data. There are no restrictions on its size. + """ + + if "update" not in self._next: + raise TypeError("update() method cannot be called") + + self._len_aad += len(data) + self._authenticator.update(data) + + def _pad_aad(self): + + assert(self._status == _CipherStatus.PROCESSING_AUTH_DATA) + if self._len_aad & 0x0F: + self._authenticator.update(b'\x00' * (16 - (self._len_aad & 0x0F))) + self._status = _CipherStatus.PROCESSING_CIPHERTEXT + + def encrypt(self, plaintext, output=None): + """Encrypt a piece of data. + + Args: + plaintext(bytes/bytearray/memoryview): The data to encrypt, of any size. + Keyword Args: + output(bytes/bytearray/memoryview): The location where the ciphertext + is written to. If ``None``, the ciphertext is returned. + Returns: + If ``output`` is ``None``, the ciphertext is returned as ``bytes``. + Otherwise, ``None``. + """ + + if "encrypt" not in self._next: + raise TypeError("encrypt() method cannot be called") + + if self._status == _CipherStatus.PROCESSING_AUTH_DATA: + self._pad_aad() + + self._next = ("encrypt", "digest") + + result = self._cipher.encrypt(plaintext, output=output) + self._len_ct += len(plaintext) + if output is None: + self._authenticator.update(result) + else: + self._authenticator.update(output) + return result + + def decrypt(self, ciphertext, output=None): + """Decrypt a piece of data. + + Args: + ciphertext(bytes/bytearray/memoryview): The data to decrypt, of any size. + Keyword Args: + output(bytes/bytearray/memoryview): The location where the plaintext + is written to. If ``None``, the plaintext is returned. + Returns: + If ``output`` is ``None``, the plaintext is returned as ``bytes``. + Otherwise, ``None``. + """ + + if "decrypt" not in self._next: + raise TypeError("decrypt() method cannot be called") + + if self._status == _CipherStatus.PROCESSING_AUTH_DATA: + self._pad_aad() + + self._next = ("decrypt", "verify") + + self._len_ct += len(ciphertext) + self._authenticator.update(ciphertext) + return self._cipher.decrypt(ciphertext, output=output) + + def _compute_mac(self): + """Finalize the cipher (if not done already) and return the MAC.""" + + if self._mac_tag: + assert(self._status == _CipherStatus.PROCESSING_DONE) + return self._mac_tag + + assert(self._status != _CipherStatus.PROCESSING_DONE) + + if self._status == _CipherStatus.PROCESSING_AUTH_DATA: + self._pad_aad() + + if self._len_ct & 0x0F: + self._authenticator.update(b'\x00' * (16 - (self._len_ct & 0x0F))) + + self._status = _CipherStatus.PROCESSING_DONE + + self._authenticator.update(long_to_bytes(self._len_aad, 8)[::-1]) + self._authenticator.update(long_to_bytes(self._len_ct, 8)[::-1]) + self._mac_tag = self._authenticator.digest() + return self._mac_tag + + def digest(self): + """Compute the *binary* authentication tag (MAC). + + :Return: the MAC tag, as 16 ``bytes``. + """ + + if "digest" not in self._next: + raise TypeError("digest() method cannot be called") + self._next = ("digest",) + + return self._compute_mac() + + def hexdigest(self): + """Compute the *printable* authentication tag (MAC). + + This method is like :meth:`digest`. + + :Return: the MAC tag, as a hexadecimal string. + """ + return "".join(["%02x" % bord(x) for x in self.digest()]) + + def verify(self, received_mac_tag): + """Validate the *binary* authentication tag (MAC). + + The receiver invokes this method at the very end, to + check if the associated data (if any) and the decrypted + messages are valid. + + :param bytes/bytearray/memoryview received_mac_tag: + This is the 16-byte *binary* MAC, as received from the sender. + :Raises ValueError: + if the MAC does not match. The message has been tampered with + or the key is incorrect. + """ + + if "verify" not in self._next: + raise TypeError("verify() cannot be called" + " when encrypting a message") + self._next = ("verify",) + + secret = get_random_bytes(16) + + self._compute_mac() + + mac1 = BLAKE2s.new(digest_bits=160, key=secret, + data=self._mac_tag) + mac2 = BLAKE2s.new(digest_bits=160, key=secret, + data=received_mac_tag) + + if mac1.digest() != mac2.digest(): + raise ValueError("MAC check failed") + + def hexverify(self, hex_mac_tag): + """Validate the *printable* authentication tag (MAC). + + This method is like :meth:`verify`. + + :param string hex_mac_tag: + This is the *printable* MAC. + :Raises ValueError: + if the MAC does not match. The message has been tampered with + or the key is incorrect. + """ + + self.verify(unhexlify(hex_mac_tag)) + + def encrypt_and_digest(self, plaintext): + """Perform :meth:`encrypt` and :meth:`digest` in one step. + + :param plaintext: The data to encrypt, of any size. + :type plaintext: bytes/bytearray/memoryview + :return: a tuple with two ``bytes`` objects: + + - the ciphertext, of equal length as the plaintext + - the 16-byte MAC tag + """ + + return self.encrypt(plaintext), self.digest() + + def decrypt_and_verify(self, ciphertext, received_mac_tag): + """Perform :meth:`decrypt` and :meth:`verify` in one step. + + :param ciphertext: The piece of data to decrypt. + :type ciphertext: bytes/bytearray/memoryview + :param bytes received_mac_tag: + This is the 16-byte *binary* MAC, as received from the sender. + :return: the decrypted data (as ``bytes``) + :raises ValueError: + if the MAC does not match. The message has been tampered with + or the key is incorrect. + """ + + plaintext = self.decrypt(ciphertext) + self.verify(received_mac_tag) + return plaintext + + +def new(**kwargs): + """Create a new ChaCha20-Poly1305 or XChaCha20-Poly1305 AEAD cipher. + + :keyword key: The secret key to use. It must be 32 bytes long. + :type key: byte string + + :keyword nonce: + A value that must never be reused for any other encryption + done with this key. + + For ChaCha20-Poly1305, it must be 8 or 12 bytes long. + + For XChaCha20-Poly1305, it must be 24 bytes long. + + If not provided, 12 ``bytes`` will be generated randomly + (you can find them back in the ``nonce`` attribute). + :type nonce: bytes, bytearray, memoryview + + :Return: a :class:`Cryptodome.Cipher.ChaCha20.ChaCha20Poly1305Cipher` object + """ + + try: + key = kwargs.pop("key") + except KeyError as e: + raise TypeError("Missing parameter %s" % e) + + if len(key) != 32: + raise ValueError("Key must be 32 bytes long") + + nonce = kwargs.pop("nonce", None) + if nonce is None: + nonce = get_random_bytes(12) + + if len(nonce) in (8, 12): + chacha20_poly1305_nonce = nonce + elif len(nonce) == 24: + key = _HChaCha20(key, nonce[:16]) + chacha20_poly1305_nonce = b'\x00\x00\x00\x00' + nonce[16:] + else: + raise ValueError("Nonce must be 8, 12 or 24 bytes long") + + if not is_buffer(nonce): + raise TypeError("nonce must be bytes, bytearray or memoryview") + + if kwargs: + raise TypeError("Unknown parameters: " + str(kwargs)) + + cipher = ChaCha20Poly1305Cipher(key, chacha20_poly1305_nonce) + cipher.nonce = _copy_bytes(None, None, nonce) + return cipher + + +# Size of a key (in bytes) +key_size = 32 diff --git a/venv/Lib/site-packages/Cryptodome/Cipher/ChaCha20_Poly1305.pyi b/venv/Lib/site-packages/Cryptodome/Cipher/ChaCha20_Poly1305.pyi new file mode 100644 index 0000000..109e805 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Cipher/ChaCha20_Poly1305.pyi @@ -0,0 +1,28 @@ +from typing import Union, Tuple, overload, Optional + +Buffer = bytes|bytearray|memoryview + +class ChaCha20Poly1305Cipher: + nonce: bytes + + def __init__(self, key: Buffer, nonce: Buffer) -> None: ... + def update(self, data: Buffer) -> None: ... + @overload + def encrypt(self, plaintext: Buffer) -> bytes: ... + @overload + def encrypt(self, plaintext: Buffer, output: Union[bytearray, memoryview]) -> None: ... + @overload + def decrypt(self, plaintext: Buffer) -> bytes: ... + @overload + def decrypt(self, plaintext: Buffer, output: Union[bytearray, memoryview]) -> None: ... + def digest(self) -> bytes: ... + def hexdigest(self) -> str: ... + def verify(self, received_mac_tag: Buffer) -> None: ... + def hexverify(self, received_mac_tag: str) -> None: ... + def encrypt_and_digest(self, plaintext: Buffer) -> Tuple[bytes, bytes]: ... + def decrypt_and_verify(self, ciphertext: Buffer, received_mac_tag: Buffer) -> bytes: ... + +def new(key: Buffer, nonce: Optional[Buffer] = ...) -> ChaCha20Poly1305Cipher: ... + +block_size: int +key_size: int diff --git a/venv/Lib/site-packages/Cryptodome/Cipher/DES.py b/venv/Lib/site-packages/Cryptodome/Cipher/DES.py new file mode 100644 index 0000000..026b491 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Cipher/DES.py @@ -0,0 +1,158 @@ +# -*- coding: utf-8 -*- +# +# Cipher/DES.py : DES +# +# =================================================================== +# The contents of this file are dedicated to the public domain. To +# the extent that dedication to the public domain is not available, +# everyone is granted a worldwide, perpetual, royalty-free, +# non-exclusive license to exercise all rights associated with the +# contents of this file for any purpose whatsoever. +# No rights are reserved. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# =================================================================== +""" +Module's constants for the modes of operation supported with Single DES: + +:var MODE_ECB: :ref:`Electronic Code Book (ECB) ` +:var MODE_CBC: :ref:`Cipher-Block Chaining (CBC) ` +:var MODE_CFB: :ref:`Cipher FeedBack (CFB) ` +:var MODE_OFB: :ref:`Output FeedBack (OFB) ` +:var MODE_CTR: :ref:`CounTer Mode (CTR) ` +:var MODE_OPENPGP: :ref:`OpenPGP Mode ` +:var MODE_EAX: :ref:`EAX Mode ` +""" + +import sys + +from Cryptodome.Cipher import _create_cipher +from Cryptodome.Util.py3compat import byte_string +from Cryptodome.Util._raw_api import (load_pycryptodome_raw_lib, + VoidPointer, SmartPointer, + c_size_t, c_uint8_ptr) + +_raw_des_lib = load_pycryptodome_raw_lib( + "Cryptodome.Cipher._raw_des", + """ + int DES_start_operation(const uint8_t key[], + size_t key_len, + void **pResult); + int DES_encrypt(const void *state, + const uint8_t *in, + uint8_t *out, + size_t data_len); + int DES_decrypt(const void *state, + const uint8_t *in, + uint8_t *out, + size_t data_len); + int DES_stop_operation(void *state); + """) + + +def _create_base_cipher(dict_parameters): + """This method instantiates and returns a handle to a low-level + base cipher. It will absorb named parameters in the process.""" + + try: + key = dict_parameters.pop("key") + except KeyError: + raise TypeError("Missing 'key' parameter") + + if len(key) != key_size: + raise ValueError("Incorrect DES key length (%d bytes)" % len(key)) + + start_operation = _raw_des_lib.DES_start_operation + stop_operation = _raw_des_lib.DES_stop_operation + + cipher = VoidPointer() + result = start_operation(c_uint8_ptr(key), + c_size_t(len(key)), + cipher.address_of()) + if result: + raise ValueError("Error %X while instantiating the DES cipher" + % result) + return SmartPointer(cipher.get(), stop_operation) + + +def new(key, mode, *args, **kwargs): + """Create a new DES cipher. + + :param key: + The secret key to use in the symmetric cipher. + It must be 8 byte long. The parity bits will be ignored. + :type key: bytes/bytearray/memoryview + + :param mode: + The chaining mode to use for encryption or decryption. + :type mode: One of the supported ``MODE_*`` constants + + :Keyword Arguments: + * **iv** (*byte string*) -- + (Only applicable for ``MODE_CBC``, ``MODE_CFB``, ``MODE_OFB``, + and ``MODE_OPENPGP`` modes). + + The initialization vector to use for encryption or decryption. + + For ``MODE_CBC``, ``MODE_CFB``, and ``MODE_OFB`` it must be 8 bytes long. + + For ``MODE_OPENPGP`` mode only, + it must be 8 bytes long for encryption + and 10 bytes for decryption (in the latter case, it is + actually the *encrypted* IV which was prefixed to the ciphertext). + + If not provided, a random byte string is generated (you must then + read its value with the :attr:`iv` attribute). + + * **nonce** (*byte string*) -- + (Only applicable for ``MODE_EAX`` and ``MODE_CTR``). + + A value that must never be reused for any other encryption done + with this key. + + For ``MODE_EAX`` there are no + restrictions on its length (recommended: **16** bytes). + + For ``MODE_CTR``, its length must be in the range **[0..7]**. + + If not provided for ``MODE_EAX``, a random byte string is generated (you + can read it back via the ``nonce`` attribute). + + * **segment_size** (*integer*) -- + (Only ``MODE_CFB``).The number of **bits** the plaintext and ciphertext + are segmented in. It must be a multiple of 8. + If not specified, it will be assumed to be 8. + + * **mac_len** : (*integer*) -- + (Only ``MODE_EAX``) + Length of the authentication tag, in bytes. + It must be no longer than 8 (default). + + * **initial_value** : (*integer*) -- + (Only ``MODE_CTR``). The initial value for the counter within + the counter block. By default it is **0**. + + :Return: a DES object, of the applicable mode. + """ + + return _create_cipher(sys.modules[__name__], key, mode, *args, **kwargs) + +MODE_ECB = 1 +MODE_CBC = 2 +MODE_CFB = 3 +MODE_OFB = 5 +MODE_CTR = 6 +MODE_OPENPGP = 7 +MODE_EAX = 9 + +# Size of a data block (in bytes) +block_size = 8 +# Size of a key (in bytes) +key_size = 8 diff --git a/venv/Lib/site-packages/Cryptodome/Cipher/DES.pyi b/venv/Lib/site-packages/Cryptodome/Cipher/DES.pyi new file mode 100644 index 0000000..25a3b23 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Cipher/DES.pyi @@ -0,0 +1,35 @@ +from typing import Union, Dict, Iterable, Optional + +Buffer = bytes|bytearray|memoryview + +from Cryptodome.Cipher._mode_ecb import EcbMode +from Cryptodome.Cipher._mode_cbc import CbcMode +from Cryptodome.Cipher._mode_cfb import CfbMode +from Cryptodome.Cipher._mode_ofb import OfbMode +from Cryptodome.Cipher._mode_ctr import CtrMode +from Cryptodome.Cipher._mode_openpgp import OpenPgpMode +from Cryptodome.Cipher._mode_eax import EaxMode + +DESMode = int + +MODE_ECB: DESMode +MODE_CBC: DESMode +MODE_CFB: DESMode +MODE_OFB: DESMode +MODE_CTR: DESMode +MODE_OPENPGP: DESMode +MODE_EAX: DESMode + +def new(key: Buffer, + mode: DESMode, + iv : Optional[Buffer] = ..., + IV : Optional[Buffer] = ..., + nonce : Optional[Buffer] = ..., + segment_size : int = ..., + mac_len : int = ..., + initial_value : Union[int, Buffer] = ..., + counter : Dict = ...) -> \ + Union[EcbMode, CbcMode, CfbMode, OfbMode, CtrMode, OpenPgpMode]: ... + +block_size: int +key_size: int diff --git a/venv/Lib/site-packages/Cryptodome/Cipher/DES3.py b/venv/Lib/site-packages/Cryptodome/Cipher/DES3.py new file mode 100644 index 0000000..3b2828e --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Cipher/DES3.py @@ -0,0 +1,187 @@ +# -*- coding: utf-8 -*- +# +# Cipher/DES3.py : DES3 +# +# =================================================================== +# The contents of this file are dedicated to the public domain. To +# the extent that dedication to the public domain is not available, +# everyone is granted a worldwide, perpetual, royalty-free, +# non-exclusive license to exercise all rights associated with the +# contents of this file for any purpose whatsoever. +# No rights are reserved. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# =================================================================== +""" +Module's constants for the modes of operation supported with Triple DES: + +:var MODE_ECB: :ref:`Electronic Code Book (ECB) ` +:var MODE_CBC: :ref:`Cipher-Block Chaining (CBC) ` +:var MODE_CFB: :ref:`Cipher FeedBack (CFB) ` +:var MODE_OFB: :ref:`Output FeedBack (OFB) ` +:var MODE_CTR: :ref:`CounTer Mode (CTR) ` +:var MODE_OPENPGP: :ref:`OpenPGP Mode ` +:var MODE_EAX: :ref:`EAX Mode ` +""" + +import sys + +from Cryptodome.Cipher import _create_cipher +from Cryptodome.Util.py3compat import byte_string, bchr, bord, bstr +from Cryptodome.Util._raw_api import (load_pycryptodome_raw_lib, + VoidPointer, SmartPointer, + c_size_t) + +_raw_des3_lib = load_pycryptodome_raw_lib( + "Cryptodome.Cipher._raw_des3", + """ + int DES3_start_operation(const uint8_t key[], + size_t key_len, + void **pResult); + int DES3_encrypt(const void *state, + const uint8_t *in, + uint8_t *out, + size_t data_len); + int DES3_decrypt(const void *state, + const uint8_t *in, + uint8_t *out, + size_t data_len); + int DES3_stop_operation(void *state); + """) + + +def adjust_key_parity(key_in): + """Set the parity bits in a TDES key. + + :param key_in: the TDES key whose bits need to be adjusted + :type key_in: byte string + + :returns: a copy of ``key_in``, with the parity bits correctly set + :rtype: byte string + + :raises ValueError: if the TDES key is not 16 or 24 bytes long + :raises ValueError: if the TDES key degenerates into Single DES + """ + + def parity_byte(key_byte): + parity = 1 + for i in range(1, 8): + parity ^= (key_byte >> i) & 1 + return (key_byte & 0xFE) | parity + + if len(key_in) not in key_size: + raise ValueError("Not a valid TDES key") + + key_out = b"".join([ bchr(parity_byte(bord(x))) for x in key_in ]) + + if key_out[:8] == key_out[8:16] or key_out[-16:-8] == key_out[-8:]: + raise ValueError("Triple DES key degenerates to single DES") + + return key_out + + +def _create_base_cipher(dict_parameters): + """This method instantiates and returns a handle to a low-level base cipher. + It will absorb named parameters in the process.""" + + try: + key_in = dict_parameters.pop("key") + except KeyError: + raise TypeError("Missing 'key' parameter") + + key = adjust_key_parity(bstr(key_in)) + + start_operation = _raw_des3_lib.DES3_start_operation + stop_operation = _raw_des3_lib.DES3_stop_operation + + cipher = VoidPointer() + result = start_operation(key, + c_size_t(len(key)), + cipher.address_of()) + if result: + raise ValueError("Error %X while instantiating the TDES cipher" + % result) + return SmartPointer(cipher.get(), stop_operation) + + +def new(key, mode, *args, **kwargs): + """Create a new Triple DES cipher. + + :param key: + The secret key to use in the symmetric cipher. + It must be 16 or 24 byte long. The parity bits will be ignored. + :type key: bytes/bytearray/memoryview + + :param mode: + The chaining mode to use for encryption or decryption. + :type mode: One of the supported ``MODE_*`` constants + + :Keyword Arguments: + * **iv** (*bytes*, *bytearray*, *memoryview*) -- + (Only applicable for ``MODE_CBC``, ``MODE_CFB``, ``MODE_OFB``, + and ``MODE_OPENPGP`` modes). + + The initialization vector to use for encryption or decryption. + + For ``MODE_CBC``, ``MODE_CFB``, and ``MODE_OFB`` it must be 8 bytes long. + + For ``MODE_OPENPGP`` mode only, + it must be 8 bytes long for encryption + and 10 bytes for decryption (in the latter case, it is + actually the *encrypted* IV which was prefixed to the ciphertext). + + If not provided, a random byte string is generated (you must then + read its value with the :attr:`iv` attribute). + + * **nonce** (*bytes*, *bytearray*, *memoryview*) -- + (Only applicable for ``MODE_EAX`` and ``MODE_CTR``). + + A value that must never be reused for any other encryption done + with this key. + + For ``MODE_EAX`` there are no + restrictions on its length (recommended: **16** bytes). + + For ``MODE_CTR``, its length must be in the range **[0..7]**. + + If not provided for ``MODE_EAX``, a random byte string is generated (you + can read it back via the ``nonce`` attribute). + + * **segment_size** (*integer*) -- + (Only ``MODE_CFB``).The number of **bits** the plaintext and ciphertext + are segmented in. It must be a multiple of 8. + If not specified, it will be assumed to be 8. + + * **mac_len** : (*integer*) -- + (Only ``MODE_EAX``) + Length of the authentication tag, in bytes. + It must be no longer than 8 (default). + + * **initial_value** : (*integer*) -- + (Only ``MODE_CTR``). The initial value for the counter within + the counter block. By default it is **0**. + + :Return: a Triple DES object, of the applicable mode. + """ + + return _create_cipher(sys.modules[__name__], key, mode, *args, **kwargs) + +MODE_ECB = 1 +MODE_CBC = 2 +MODE_CFB = 3 +MODE_OFB = 5 +MODE_CTR = 6 +MODE_OPENPGP = 7 +MODE_EAX = 9 + +# Size of a data block (in bytes) +block_size = 8 +# Size of a key (in bytes) +key_size = (16, 24) diff --git a/venv/Lib/site-packages/Cryptodome/Cipher/DES3.pyi b/venv/Lib/site-packages/Cryptodome/Cipher/DES3.pyi new file mode 100644 index 0000000..2c150f8 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Cipher/DES3.pyi @@ -0,0 +1,37 @@ +from typing import Union, Dict, Tuple, Optional + +Buffer = bytes|bytearray|memoryview + +from Cryptodome.Cipher._mode_ecb import EcbMode +from Cryptodome.Cipher._mode_cbc import CbcMode +from Cryptodome.Cipher._mode_cfb import CfbMode +from Cryptodome.Cipher._mode_ofb import OfbMode +from Cryptodome.Cipher._mode_ctr import CtrMode +from Cryptodome.Cipher._mode_openpgp import OpenPgpMode +from Cryptodome.Cipher._mode_eax import EaxMode + +def adjust_key_parity(key_in: bytes) -> bytes: ... + +DES3Mode = int + +MODE_ECB: DES3Mode +MODE_CBC: DES3Mode +MODE_CFB: DES3Mode +MODE_OFB: DES3Mode +MODE_CTR: DES3Mode +MODE_OPENPGP: DES3Mode +MODE_EAX: DES3Mode + +def new(key: Buffer, + mode: DES3Mode, + iv : Optional[Buffer] = ..., + IV : Optional[Buffer] = ..., + nonce : Optional[Buffer] = ..., + segment_size : int = ..., + mac_len : int = ..., + initial_value : Union[int, Buffer] = ..., + counter : Dict = ...) -> \ + Union[EcbMode, CbcMode, CfbMode, OfbMode, CtrMode, OpenPgpMode]: ... + +block_size: int +key_size: Tuple[int, int] diff --git a/venv/Lib/site-packages/Cryptodome/Cipher/PKCS1_OAEP.py b/venv/Lib/site-packages/Cryptodome/Cipher/PKCS1_OAEP.py new file mode 100644 index 0000000..08f9efe --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Cipher/PKCS1_OAEP.py @@ -0,0 +1,231 @@ +# -*- coding: utf-8 -*- +# +# Cipher/PKCS1_OAEP.py : PKCS#1 OAEP +# +# =================================================================== +# The contents of this file are dedicated to the public domain. To +# the extent that dedication to the public domain is not available, +# everyone is granted a worldwide, perpetual, royalty-free, +# non-exclusive license to exercise all rights associated with the +# contents of this file for any purpose whatsoever. +# No rights are reserved. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# =================================================================== + +from Cryptodome.Signature.pss import MGF1 +import Cryptodome.Hash.SHA1 + +from Cryptodome.Util.py3compat import _copy_bytes +import Cryptodome.Util.number +from Cryptodome.Util.number import ceil_div, bytes_to_long, long_to_bytes +from Cryptodome.Util.strxor import strxor +from Cryptodome import Random +from ._pkcs1_oaep_decode import oaep_decode + + +class PKCS1OAEP_Cipher: + """Cipher object for PKCS#1 v1.5 OAEP. + Do not create directly: use :func:`new` instead.""" + + def __init__(self, key, hashAlgo, mgfunc, label, randfunc): + """Initialize this PKCS#1 OAEP cipher object. + + :Parameters: + key : an RSA key object + If a private half is given, both encryption and decryption are possible. + If a public half is given, only encryption is possible. + hashAlgo : hash object + The hash function to use. This can be a module under `Cryptodome.Hash` + or an existing hash object created from any of such modules. If not specified, + `Cryptodome.Hash.SHA1` is used. + mgfunc : callable + A mask generation function that accepts two parameters: a string to + use as seed, and the lenth of the mask to generate, in bytes. + If not specified, the standard MGF1 consistent with ``hashAlgo`` is used (a safe choice). + label : bytes/bytearray/memoryview + A label to apply to this particular encryption. If not specified, + an empty string is used. Specifying a label does not improve + security. + randfunc : callable + A function that returns random bytes. + + :attention: Modify the mask generation function only if you know what you are doing. + Sender and receiver must use the same one. + """ + self._key = key + + if hashAlgo: + self._hashObj = hashAlgo + else: + self._hashObj = Cryptodome.Hash.SHA1 + + if mgfunc: + self._mgf = mgfunc + else: + self._mgf = lambda x, y: MGF1(x, y, self._hashObj) + + self._label = _copy_bytes(None, None, label) + self._randfunc = randfunc + + def can_encrypt(self): + """Legacy function to check if you can call :meth:`encrypt`. + + .. deprecated:: 3.0""" + return self._key.can_encrypt() + + def can_decrypt(self): + """Legacy function to check if you can call :meth:`decrypt`. + + .. deprecated:: 3.0""" + return self._key.can_decrypt() + + def encrypt(self, message): + """Encrypt a message with PKCS#1 OAEP. + + :param message: + The message to encrypt, also known as plaintext. It can be of + variable length, but not longer than the RSA modulus (in bytes) + minus 2, minus twice the hash output size. + For instance, if you use RSA 2048 and SHA-256, the longest message + you can encrypt is 190 byte long. + :type message: bytes/bytearray/memoryview + + :returns: The ciphertext, as large as the RSA modulus. + :rtype: bytes + + :raises ValueError: + if the message is too long. + """ + + # See 7.1.1 in RFC3447 + modBits = Cryptodome.Util.number.size(self._key.n) + k = ceil_div(modBits, 8) # Convert from bits to bytes + hLen = self._hashObj.digest_size + mLen = len(message) + + # Step 1b + ps_len = k - mLen - 2 * hLen - 2 + if ps_len < 0: + raise ValueError("Plaintext is too long.") + # Step 2a + lHash = self._hashObj.new(self._label).digest() + # Step 2b + ps = b'\x00' * ps_len + # Step 2c + db = lHash + ps + b'\x01' + _copy_bytes(None, None, message) + # Step 2d + ros = self._randfunc(hLen) + # Step 2e + dbMask = self._mgf(ros, k-hLen-1) + # Step 2f + maskedDB = strxor(db, dbMask) + # Step 2g + seedMask = self._mgf(maskedDB, hLen) + # Step 2h + maskedSeed = strxor(ros, seedMask) + # Step 2i + em = b'\x00' + maskedSeed + maskedDB + # Step 3a (OS2IP) + em_int = bytes_to_long(em) + # Step 3b (RSAEP) + m_int = self._key._encrypt(em_int) + # Step 3c (I2OSP) + c = long_to_bytes(m_int, k) + return c + + def decrypt(self, ciphertext): + """Decrypt a message with PKCS#1 OAEP. + + :param ciphertext: The encrypted message. + :type ciphertext: bytes/bytearray/memoryview + + :returns: The original message (plaintext). + :rtype: bytes + + :raises ValueError: + if the ciphertext has the wrong length, or if decryption + fails the integrity check (in which case, the decryption + key is probably wrong). + :raises TypeError: + if the RSA key has no private half (i.e. you are trying + to decrypt using a public key). + """ + + # See 7.1.2 in RFC3447 + modBits = Cryptodome.Util.number.size(self._key.n) + k = ceil_div(modBits, 8) # Convert from bits to bytes + hLen = self._hashObj.digest_size + + # Step 1b and 1c + if len(ciphertext) != k or k < hLen+2: + raise ValueError("Ciphertext with incorrect length.") + # Step 2a (O2SIP) + ct_int = bytes_to_long(ciphertext) + # Step 2b (RSADP) and step 2c (I2OSP) + em = self._key._decrypt_to_bytes(ct_int) + # Step 3a + lHash = self._hashObj.new(self._label).digest() + # y must be 0, but we MUST NOT check it here in order not to + # allow attacks like Manger's (http://dl.acm.org/citation.cfm?id=704143) + maskedSeed = em[1:hLen+1] + maskedDB = em[hLen+1:] + # Step 3c + seedMask = self._mgf(maskedDB, hLen) + # Step 3d + seed = strxor(maskedSeed, seedMask) + # Step 3e + dbMask = self._mgf(seed, k-hLen-1) + # Step 3f + db = strxor(maskedDB, dbMask) + # Step 3b + 3g + res = oaep_decode(em, lHash, db) + if res <= 0: + raise ValueError("Incorrect decryption.") + # Step 4 + return db[res:] + + +def new(key, hashAlgo=None, mgfunc=None, label=b'', randfunc=None): + """Return a cipher object :class:`PKCS1OAEP_Cipher` + that can be used to perform PKCS#1 OAEP encryption or decryption. + + :param key: + The key object to use to encrypt or decrypt the message. + Decryption is only possible with a private RSA key. + :type key: RSA key object + + :param hashAlgo: + The hash function to use. This can be a module under `Cryptodome.Hash` + or an existing hash object created from any of such modules. + If not specified, `Cryptodome.Hash.SHA1` is used. + :type hashAlgo: hash object + + :param mgfunc: + A mask generation function that accepts two parameters: a string to + use as seed, and the lenth of the mask to generate, in bytes. + If not specified, the standard MGF1 consistent with ``hashAlgo`` is used (a safe choice). + :type mgfunc: callable + + :param label: + A label to apply to this particular encryption. If not specified, + an empty string is used. Specifying a label does not improve + security. + :type label: bytes/bytearray/memoryview + + :param randfunc: + A function that returns random bytes. + The default is `Random.get_random_bytes`. + :type randfunc: callable + """ + + if randfunc is None: + randfunc = Random.get_random_bytes + return PKCS1OAEP_Cipher(key, hashAlgo, mgfunc, label, randfunc) diff --git a/venv/Lib/site-packages/Cryptodome/Cipher/PKCS1_OAEP.pyi b/venv/Lib/site-packages/Cryptodome/Cipher/PKCS1_OAEP.pyi new file mode 100644 index 0000000..b54cd3f --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Cipher/PKCS1_OAEP.pyi @@ -0,0 +1,35 @@ +from typing import Optional, Union, Callable, Any, overload +from typing_extensions import Protocol + +from Cryptodome.PublicKey.RSA import RsaKey + +class HashLikeClass(Protocol): + digest_size : int + def new(self, data: Optional[bytes] = ...) -> Any: ... + +class HashLikeModule(Protocol): + digest_size : int + @staticmethod + def new(data: Optional[bytes] = ...) -> Any: ... + +HashLike = Union[HashLikeClass, HashLikeModule] + +Buffer = Union[bytes, bytearray, memoryview] + +class PKCS1OAEP_Cipher: + def __init__(self, + key: RsaKey, + hashAlgo: HashLike, + mgfunc: Callable[[bytes, int], bytes], + label: Buffer, + randfunc: Callable[[int], bytes]) -> None: ... + def can_encrypt(self) -> bool: ... + def can_decrypt(self) -> bool: ... + def encrypt(self, message: Buffer) -> bytes: ... + def decrypt(self, ciphertext: Buffer) -> bytes: ... + +def new(key: RsaKey, + hashAlgo: Optional[HashLike] = ..., + mgfunc: Optional[Callable[[bytes, int], bytes]] = ..., + label: Optional[Buffer] = ..., + randfunc: Optional[Callable[[int], bytes]] = ...) -> PKCS1OAEP_Cipher: ... diff --git a/venv/Lib/site-packages/Cryptodome/Cipher/PKCS1_v1_5.py b/venv/Lib/site-packages/Cryptodome/Cipher/PKCS1_v1_5.py new file mode 100644 index 0000000..d7a9b79 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Cipher/PKCS1_v1_5.py @@ -0,0 +1,189 @@ +# -*- coding: utf-8 -*- +# +# Cipher/PKCS1-v1_5.py : PKCS#1 v1.5 +# +# =================================================================== +# The contents of this file are dedicated to the public domain. To +# the extent that dedication to the public domain is not available, +# everyone is granted a worldwide, perpetual, royalty-free, +# non-exclusive license to exercise all rights associated with the +# contents of this file for any purpose whatsoever. +# No rights are reserved. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# =================================================================== + +__all__ = ['new', 'PKCS115_Cipher'] + +from Cryptodome import Random +from Cryptodome.Util.number import bytes_to_long, long_to_bytes +from Cryptodome.Util.py3compat import bord, is_bytes, _copy_bytes +from ._pkcs1_oaep_decode import pkcs1_decode + + +class PKCS115_Cipher: + """This cipher can perform PKCS#1 v1.5 RSA encryption or decryption. + Do not instantiate directly. Use :func:`Cryptodome.Cipher.PKCS1_v1_5.new` instead.""" + + def __init__(self, key, randfunc): + """Initialize this PKCS#1 v1.5 cipher object. + + :Parameters: + key : an RSA key object + If a private half is given, both encryption and decryption are possible. + If a public half is given, only encryption is possible. + randfunc : callable + Function that returns random bytes. + """ + + self._key = key + self._randfunc = randfunc + + def can_encrypt(self): + """Return True if this cipher object can be used for encryption.""" + return self._key.can_encrypt() + + def can_decrypt(self): + """Return True if this cipher object can be used for decryption.""" + return self._key.can_decrypt() + + def encrypt(self, message): + """Produce the PKCS#1 v1.5 encryption of a message. + + This function is named ``RSAES-PKCS1-V1_5-ENCRYPT``, and it is specified in + `section 7.2.1 of RFC8017 + `_. + + :param message: + The message to encrypt, also known as plaintext. It can be of + variable length, but not longer than the RSA modulus (in bytes) minus 11. + :type message: bytes/bytearray/memoryview + + :Returns: A byte string, the ciphertext in which the message is encrypted. + It is as long as the RSA modulus (in bytes). + + :Raises ValueError: + If the RSA key length is not sufficiently long to deal with the given + message. + """ + + # See 7.2.1 in RFC8017 + k = self._key.size_in_bytes() + mLen = len(message) + + # Step 1 + if mLen > k - 11: + raise ValueError("Plaintext is too long.") + # Step 2a + ps = [] + while len(ps) != k - mLen - 3: + new_byte = self._randfunc(1) + if bord(new_byte[0]) == 0x00: + continue + ps.append(new_byte) + ps = b"".join(ps) + # Step 2b + em = b'\x00\x02' + ps + b'\x00' + _copy_bytes(None, None, message) + # Step 3a (OS2IP) + em_int = bytes_to_long(em) + # Step 3b (RSAEP) + m_int = self._key._encrypt(em_int) + # Step 3c (I2OSP) + c = long_to_bytes(m_int, k) + return c + + def decrypt(self, ciphertext, sentinel, expected_pt_len=0): + r"""Decrypt a PKCS#1 v1.5 ciphertext. + + This is the function ``RSAES-PKCS1-V1_5-DECRYPT`` specified in + `section 7.2.2 of RFC8017 + `_. + + Args: + ciphertext (bytes/bytearray/memoryview): + The ciphertext that contains the message to recover. + sentinel (any type): + The object to return whenever an error is detected. + expected_pt_len (integer): + The length the plaintext is known to have, or 0 if unknown. + + Returns (byte string): + It is either the original message or the ``sentinel`` (in case of an error). + + .. warning:: + PKCS#1 v1.5 decryption is intrinsically vulnerable to timing + attacks (see `Bleichenbacher's`__ attack). + **Use PKCS#1 OAEP instead**. + + This implementation attempts to mitigate the risk + with some constant-time constructs. + However, they are not sufficient by themselves: the type of protocol you + implement and the way you handle errors make a big difference. + + Specifically, you should make it very hard for the (malicious) + party that submitted the ciphertext to quickly understand if decryption + succeeded or not. + + To this end, it is recommended that your protocol only encrypts + plaintexts of fixed length (``expected_pt_len``), + that ``sentinel`` is a random byte string of the same length, + and that processing continues for as long + as possible even if ``sentinel`` is returned (i.e. in case of + incorrect decryption). + + .. __: https://dx.doi.org/10.1007/BFb0055716 + """ + + # See 7.2.2 in RFC8017 + k = self._key.size_in_bytes() + + # Step 1 + if len(ciphertext) != k: + raise ValueError("Ciphertext with incorrect length (not %d bytes)" % k) + + # Step 2a (O2SIP) + ct_int = bytes_to_long(ciphertext) + + # Step 2b (RSADP) and Step 2c (I2OSP) + em = self._key._decrypt_to_bytes(ct_int) + + # Step 3 (not constant time when the sentinel is not a byte string) + output = bytes(bytearray(k)) + if not is_bytes(sentinel) or len(sentinel) > k: + size = pkcs1_decode(em, b'', expected_pt_len, output) + if size < 0: + return sentinel + else: + return output[size:] + + # Step 3 (somewhat constant time) + size = pkcs1_decode(em, sentinel, expected_pt_len, output) + return output[size:] + + +def new(key, randfunc=None): + """Create a cipher for performing PKCS#1 v1.5 encryption or decryption. + + :param key: + The key to use to encrypt or decrypt the message. This is a `Cryptodome.PublicKey.RSA` object. + Decryption is only possible if *key* is a private RSA key. + :type key: RSA key object + + :param randfunc: + Function that return random bytes. + The default is :func:`Cryptodome.Random.get_random_bytes`. + :type randfunc: callable + + :returns: A cipher object `PKCS115_Cipher`. + """ + + if randfunc is None: + randfunc = Random.get_random_bytes + return PKCS115_Cipher(key, randfunc) diff --git a/venv/Lib/site-packages/Cryptodome/Cipher/PKCS1_v1_5.pyi b/venv/Lib/site-packages/Cryptodome/Cipher/PKCS1_v1_5.pyi new file mode 100644 index 0000000..b69f509 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Cipher/PKCS1_v1_5.pyi @@ -0,0 +1,20 @@ +from typing import Callable, Union, Any, Optional, TypeVar + +from Cryptodome.PublicKey.RSA import RsaKey + +Buffer = Union[bytes, bytearray, memoryview] +T = TypeVar('T') + +class PKCS115_Cipher: + def __init__(self, + key: RsaKey, + randfunc: Callable[[int], bytes]) -> None: ... + def can_encrypt(self) -> bool: ... + def can_decrypt(self) -> bool: ... + def encrypt(self, message: Buffer) -> bytes: ... + def decrypt(self, ciphertext: Buffer, + sentinel: T, + expected_pt_len: Optional[int] = ...) -> Union[bytes, T]: ... + +def new(key: RsaKey, + randfunc: Optional[Callable[[int], bytes]] = ...) -> PKCS115_Cipher: ... diff --git a/venv/Lib/site-packages/Cryptodome/Cipher/Salsa20.py b/venv/Lib/site-packages/Cryptodome/Cipher/Salsa20.py new file mode 100644 index 0000000..79e6701 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Cipher/Salsa20.py @@ -0,0 +1,167 @@ +# -*- coding: utf-8 -*- +# +# Cipher/Salsa20.py : Salsa20 stream cipher (http://cr.yp.to/snuffle.html) +# +# Contributed by Fabrizio Tarizzo . +# +# =================================================================== +# The contents of this file are dedicated to the public domain. To +# the extent that dedication to the public domain is not available, +# everyone is granted a worldwide, perpetual, royalty-free, +# non-exclusive license to exercise all rights associated with the +# contents of this file for any purpose whatsoever. +# No rights are reserved. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# =================================================================== + +from Cryptodome.Util.py3compat import _copy_bytes +from Cryptodome.Util._raw_api import (load_pycryptodome_raw_lib, + create_string_buffer, + get_raw_buffer, VoidPointer, + SmartPointer, c_size_t, + c_uint8_ptr, is_writeable_buffer) + +from Cryptodome.Random import get_random_bytes + +_raw_salsa20_lib = load_pycryptodome_raw_lib("Cryptodome.Cipher._Salsa20", + """ + int Salsa20_stream_init(uint8_t *key, size_t keylen, + uint8_t *nonce, size_t nonce_len, + void **pSalsaState); + int Salsa20_stream_destroy(void *salsaState); + int Salsa20_stream_encrypt(void *salsaState, + const uint8_t in[], + uint8_t out[], size_t len); + """) + + +class Salsa20Cipher: + """Salsa20 cipher object. Do not create it directly. Use :py:func:`new` + instead. + + :var nonce: The nonce with length 8 + :vartype nonce: byte string + """ + + def __init__(self, key, nonce): + """Initialize a Salsa20 cipher object + + See also `new()` at the module level.""" + + if len(key) not in key_size: + raise ValueError("Incorrect key length for Salsa20 (%d bytes)" % len(key)) + + if len(nonce) != 8: + raise ValueError("Incorrect nonce length for Salsa20 (%d bytes)" % + len(nonce)) + + self.nonce = _copy_bytes(None, None, nonce) + + self._state = VoidPointer() + result = _raw_salsa20_lib.Salsa20_stream_init( + c_uint8_ptr(key), + c_size_t(len(key)), + c_uint8_ptr(nonce), + c_size_t(len(nonce)), + self._state.address_of()) + if result: + raise ValueError("Error %d instantiating a Salsa20 cipher") + self._state = SmartPointer(self._state.get(), + _raw_salsa20_lib.Salsa20_stream_destroy) + + self.block_size = 1 + self.key_size = len(key) + + def encrypt(self, plaintext, output=None): + """Encrypt a piece of data. + + Args: + plaintext(bytes/bytearray/memoryview): The data to encrypt, of any size. + Keyword Args: + output(bytes/bytearray/memoryview): The location where the ciphertext + is written to. If ``None``, the ciphertext is returned. + Returns: + If ``output`` is ``None``, the ciphertext is returned as ``bytes``. + Otherwise, ``None``. + """ + + if output is None: + ciphertext = create_string_buffer(len(plaintext)) + else: + ciphertext = output + + if not is_writeable_buffer(output): + raise TypeError("output must be a bytearray or a writeable memoryview") + + if len(plaintext) != len(output): + raise ValueError("output must have the same length as the input" + " (%d bytes)" % len(plaintext)) + + result = _raw_salsa20_lib.Salsa20_stream_encrypt( + self._state.get(), + c_uint8_ptr(plaintext), + c_uint8_ptr(ciphertext), + c_size_t(len(plaintext))) + if result: + raise ValueError("Error %d while encrypting with Salsa20" % result) + + if output is None: + return get_raw_buffer(ciphertext) + else: + return None + + def decrypt(self, ciphertext, output=None): + """Decrypt a piece of data. + + Args: + ciphertext(bytes/bytearray/memoryview): The data to decrypt, of any size. + Keyword Args: + output(bytes/bytearray/memoryview): The location where the plaintext + is written to. If ``None``, the plaintext is returned. + Returns: + If ``output`` is ``None``, the plaintext is returned as ``bytes``. + Otherwise, ``None``. + """ + + try: + return self.encrypt(ciphertext, output=output) + except ValueError as e: + raise ValueError(str(e).replace("enc", "dec")) + + +def new(key, nonce=None): + """Create a new Salsa20 cipher + + :keyword key: The secret key to use. It must be 16 or 32 bytes long. + :type key: bytes/bytearray/memoryview + + :keyword nonce: + A value that must never be reused for any other encryption + done with this key. It must be 8 bytes long. + + If not provided, a random byte string will be generated (you can read + it back via the ``nonce`` attribute of the returned object). + :type nonce: bytes/bytearray/memoryview + + :Return: a :class:`Cryptodome.Cipher.Salsa20.Salsa20Cipher` object + """ + + if nonce is None: + nonce = get_random_bytes(8) + + return Salsa20Cipher(key, nonce) + +# Size of a data block (in bytes) +block_size = 1 + +# Size of a key (in bytes) +key_size = (16, 32) + diff --git a/venv/Lib/site-packages/Cryptodome/Cipher/Salsa20.pyi b/venv/Lib/site-packages/Cryptodome/Cipher/Salsa20.pyi new file mode 100644 index 0000000..cf8690e --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Cipher/Salsa20.pyi @@ -0,0 +1,26 @@ +from typing import Union, Tuple, Optional, overload, Optional + +Buffer = bytes|bytearray|memoryview + +class Salsa20Cipher: + nonce: bytes + block_size: int + key_size: int + + def __init__(self, + key: Buffer, + nonce: Buffer) -> None: ... + @overload + def encrypt(self, plaintext: Buffer) -> bytes: ... + @overload + def encrypt(self, plaintext: Buffer, output: Union[bytearray, memoryview]) -> None: ... + @overload + def decrypt(self, plaintext: Buffer) -> bytes: ... + @overload + def decrypt(self, plaintext: Buffer, output: Union[bytearray, memoryview]) -> None: ... + +def new(key: Buffer, nonce: Optional[Buffer] = ...) -> Salsa20Cipher: ... + +block_size: int +key_size: Tuple[int, int] + diff --git a/venv/Lib/site-packages/Cryptodome/Cipher/_ARC4.pyd b/venv/Lib/site-packages/Cryptodome/Cipher/_ARC4.pyd new file mode 100644 index 0000000..37e083a Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Cipher/_ARC4.pyd differ diff --git a/venv/Lib/site-packages/Cryptodome/Cipher/_EKSBlowfish.py b/venv/Lib/site-packages/Cryptodome/Cipher/_EKSBlowfish.py new file mode 100644 index 0000000..c1c3249 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Cipher/_EKSBlowfish.py @@ -0,0 +1,131 @@ +# =================================================================== +# +# Copyright (c) 2019, Legrandin +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# =================================================================== + +import sys + +from Cryptodome.Cipher import _create_cipher +from Cryptodome.Util._raw_api import (load_pycryptodome_raw_lib, + VoidPointer, SmartPointer, c_size_t, + c_uint8_ptr, c_uint) + +_raw_blowfish_lib = load_pycryptodome_raw_lib( + "Cryptodome.Cipher._raw_eksblowfish", + """ + int EKSBlowfish_start_operation(const uint8_t key[], + size_t key_len, + const uint8_t salt[16], + size_t salt_len, + unsigned cost, + unsigned invert, + void **pResult); + int EKSBlowfish_encrypt(const void *state, + const uint8_t *in, + uint8_t *out, + size_t data_len); + int EKSBlowfish_decrypt(const void *state, + const uint8_t *in, + uint8_t *out, + size_t data_len); + int EKSBlowfish_stop_operation(void *state); + """ + ) + + +def _create_base_cipher(dict_parameters): + """This method instantiates and returns a smart pointer to + a low-level base cipher. It will absorb named parameters in + the process.""" + + try: + key = dict_parameters.pop("key") + salt = dict_parameters.pop("salt") + cost = dict_parameters.pop("cost") + except KeyError as e: + raise TypeError("Missing EKSBlowfish parameter: " + str(e)) + invert = dict_parameters.pop("invert", True) + + if len(key) not in key_size: + raise ValueError("Incorrect EKSBlowfish key length (%d bytes)" % len(key)) + + start_operation = _raw_blowfish_lib.EKSBlowfish_start_operation + stop_operation = _raw_blowfish_lib.EKSBlowfish_stop_operation + + void_p = VoidPointer() + result = start_operation(c_uint8_ptr(key), + c_size_t(len(key)), + c_uint8_ptr(salt), + c_size_t(len(salt)), + c_uint(cost), + c_uint(int(invert)), + void_p.address_of()) + if result: + raise ValueError("Error %X while instantiating the EKSBlowfish cipher" + % result) + return SmartPointer(void_p.get(), stop_operation) + + +def new(key, mode, salt, cost, invert): + """Create a new EKSBlowfish cipher + + Args: + + key (bytes, bytearray, memoryview): + The secret key to use in the symmetric cipher. + Its length can vary from 0 to 72 bytes. + + mode (one of the supported ``MODE_*`` constants): + The chaining mode to use for encryption or decryption. + + salt (bytes, bytearray, memoryview): + The salt that bcrypt uses to thwart rainbow table attacks + + cost (integer): + The complexity factor in bcrypt + + invert (bool): + If ``False``, in the inner loop use ``ExpandKey`` first over the salt + and then over the key, as defined in + the `original bcrypt specification `_. + If ``True``, reverse the order, as in the first implementation of + `bcrypt` in OpenBSD. + + :Return: an EKSBlowfish object + """ + + kwargs = { 'salt':salt, 'cost':cost, 'invert':invert } + return _create_cipher(sys.modules[__name__], key, mode, **kwargs) + + +MODE_ECB = 1 + +# Size of a data block (in bytes) +block_size = 8 +# Size of a key (in bytes) +key_size = range(0, 72 + 1) diff --git a/venv/Lib/site-packages/Cryptodome/Cipher/_EKSBlowfish.pyi b/venv/Lib/site-packages/Cryptodome/Cipher/_EKSBlowfish.pyi new file mode 100644 index 0000000..49c8448 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Cipher/_EKSBlowfish.pyi @@ -0,0 +1,15 @@ +from typing import Union, Iterable + +from Cryptodome.Cipher._mode_ecb import EcbMode + +MODE_ECB: int + +Buffer = Union[bytes, bytearray, memoryview] + +def new(key: Buffer, + mode: int, + salt: Buffer, + cost: int) -> EcbMode: ... + +block_size: int +key_size: Iterable[int] diff --git a/venv/Lib/site-packages/Cryptodome/Cipher/_Salsa20.pyd b/venv/Lib/site-packages/Cryptodome/Cipher/_Salsa20.pyd new file mode 100644 index 0000000..1f77d38 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Cipher/_Salsa20.pyd differ diff --git a/venv/Lib/site-packages/Cryptodome/Cipher/__init__.py b/venv/Lib/site-packages/Cryptodome/Cipher/__init__.py new file mode 100644 index 0000000..8823711 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Cipher/__init__.py @@ -0,0 +1,91 @@ +# +# A block cipher is instantiated as a combination of: +# 1. A base cipher (such as AES) +# 2. A mode of operation (such as CBC) +# +# Both items are implemented as C modules. +# +# The API of #1 is (replace "AES" with the name of the actual cipher): +# - AES_start_operaion(key) --> base_cipher_state +# - AES_encrypt(base_cipher_state, in, out, length) +# - AES_decrypt(base_cipher_state, in, out, length) +# - AES_stop_operation(base_cipher_state) +# +# Where base_cipher_state is AES_State, a struct with BlockBase (set of +# pointers to encrypt/decrypt/stop) followed by cipher-specific data. +# +# The API of #2 is (replace "CBC" with the name of the actual mode): +# - CBC_start_operation(base_cipher_state) --> mode_state +# - CBC_encrypt(mode_state, in, out, length) +# - CBC_decrypt(mode_state, in, out, length) +# - CBC_stop_operation(mode_state) +# +# where mode_state is a a pointer to base_cipher_state plus mode-specific data. + +def _create_cipher(factory, key, mode, *args, **kwargs): + + kwargs["key"] = key + + if args: + if mode in (8, 9, 10, 11, 12): + if len(args) > 1: + raise TypeError("Too many arguments for this mode") + kwargs["nonce"] = args[0] + elif mode in (2, 3, 5, 7): + if len(args) > 1: + raise TypeError("Too many arguments for this mode") + kwargs["IV"] = args[0] + elif mode == 6: + if len(args) > 0: + raise TypeError("Too many arguments for this mode") + elif mode == 1: + raise TypeError("IV is not meaningful for the ECB mode") + + res = None + extra_modes = kwargs.pop("add_aes_modes", False) + + if mode == 1: + from Cryptodome.Cipher._mode_ecb import _create_ecb_cipher + res = _create_ecb_cipher(factory, **kwargs) + elif mode == 2: + from Cryptodome.Cipher._mode_cbc import _create_cbc_cipher + res = _create_cbc_cipher(factory, **kwargs) + elif mode == 3: + from Cryptodome.Cipher._mode_cfb import _create_cfb_cipher + res = _create_cfb_cipher(factory, **kwargs) + elif mode == 5: + from Cryptodome.Cipher._mode_ofb import _create_ofb_cipher + res = _create_ofb_cipher(factory, **kwargs) + elif mode == 6: + from Cryptodome.Cipher._mode_ctr import _create_ctr_cipher + res = _create_ctr_cipher(factory, **kwargs) + elif mode == 7: + from Cryptodome.Cipher._mode_openpgp import _create_openpgp_cipher + res = _create_openpgp_cipher(factory, **kwargs) + elif mode == 9: + from Cryptodome.Cipher._mode_eax import _create_eax_cipher + res = _create_eax_cipher(factory, **kwargs) + elif extra_modes: + if mode == 8: + from Cryptodome.Cipher._mode_ccm import _create_ccm_cipher + res = _create_ccm_cipher(factory, **kwargs) + elif mode == 10: + from Cryptodome.Cipher._mode_siv import _create_siv_cipher + res = _create_siv_cipher(factory, **kwargs) + elif mode == 11: + from Cryptodome.Cipher._mode_gcm import _create_gcm_cipher + res = _create_gcm_cipher(factory, **kwargs) + elif mode == 12: + from Cryptodome.Cipher._mode_ocb import _create_ocb_cipher + res = _create_ocb_cipher(factory, **kwargs) + elif mode == 13: + from Cryptodome.Cipher._mode_kw import _create_kw_cipher + res = _create_kw_cipher(factory, **kwargs) + elif mode == 14: + from Cryptodome.Cipher._mode_kwp import _create_kwp_cipher + res = _create_kwp_cipher(factory, **kwargs) + + if res is None: + raise ValueError("Mode not supported") + + return res diff --git a/venv/Lib/site-packages/pillow-12.1.0.dist-info/REQUESTED b/venv/Lib/site-packages/Cryptodome/Cipher/__init__.pyi similarity index 100% rename from venv/Lib/site-packages/pillow-12.1.0.dist-info/REQUESTED rename to venv/Lib/site-packages/Cryptodome/Cipher/__init__.pyi diff --git a/venv/Lib/site-packages/Cryptodome/Cipher/__pycache__/AES.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/Cipher/__pycache__/AES.cpython-312.pyc new file mode 100644 index 0000000..095bc10 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Cipher/__pycache__/AES.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/Cipher/__pycache__/ARC2.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/Cipher/__pycache__/ARC2.cpython-312.pyc new file mode 100644 index 0000000..95b4e72 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Cipher/__pycache__/ARC2.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/Cipher/__pycache__/ARC4.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/Cipher/__pycache__/ARC4.cpython-312.pyc new file mode 100644 index 0000000..a3964f9 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Cipher/__pycache__/ARC4.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/Cipher/__pycache__/Blowfish.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/Cipher/__pycache__/Blowfish.cpython-312.pyc new file mode 100644 index 0000000..6b4bf2b Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Cipher/__pycache__/Blowfish.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/Cipher/__pycache__/CAST.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/Cipher/__pycache__/CAST.cpython-312.pyc new file mode 100644 index 0000000..ffe59d0 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Cipher/__pycache__/CAST.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/Cipher/__pycache__/ChaCha20.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/Cipher/__pycache__/ChaCha20.cpython-312.pyc new file mode 100644 index 0000000..9ffc197 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Cipher/__pycache__/ChaCha20.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/Cipher/__pycache__/ChaCha20_Poly1305.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/Cipher/__pycache__/ChaCha20_Poly1305.cpython-312.pyc new file mode 100644 index 0000000..add3c3d Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Cipher/__pycache__/ChaCha20_Poly1305.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/Cipher/__pycache__/DES.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/Cipher/__pycache__/DES.cpython-312.pyc new file mode 100644 index 0000000..f689b1d Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Cipher/__pycache__/DES.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/Cipher/__pycache__/DES3.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/Cipher/__pycache__/DES3.cpython-312.pyc new file mode 100644 index 0000000..8b18aea Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Cipher/__pycache__/DES3.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/Cipher/__pycache__/PKCS1_OAEP.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/Cipher/__pycache__/PKCS1_OAEP.cpython-312.pyc new file mode 100644 index 0000000..5b4f0ae Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Cipher/__pycache__/PKCS1_OAEP.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/Cipher/__pycache__/PKCS1_v1_5.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/Cipher/__pycache__/PKCS1_v1_5.cpython-312.pyc new file mode 100644 index 0000000..2fb597c Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Cipher/__pycache__/PKCS1_v1_5.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/Cipher/__pycache__/Salsa20.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/Cipher/__pycache__/Salsa20.cpython-312.pyc new file mode 100644 index 0000000..2f4ee27 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Cipher/__pycache__/Salsa20.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/Cipher/__pycache__/_EKSBlowfish.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/Cipher/__pycache__/_EKSBlowfish.cpython-312.pyc new file mode 100644 index 0000000..c6a7437 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Cipher/__pycache__/_EKSBlowfish.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/Cipher/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/Cipher/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000..c643bce Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Cipher/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/Cipher/__pycache__/_mode_cbc.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/Cipher/__pycache__/_mode_cbc.cpython-312.pyc new file mode 100644 index 0000000..347ef2d Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Cipher/__pycache__/_mode_cbc.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/Cipher/__pycache__/_mode_ccm.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/Cipher/__pycache__/_mode_ccm.cpython-312.pyc new file mode 100644 index 0000000..009dd33 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Cipher/__pycache__/_mode_ccm.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/Cipher/__pycache__/_mode_cfb.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/Cipher/__pycache__/_mode_cfb.cpython-312.pyc new file mode 100644 index 0000000..49c11ca Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Cipher/__pycache__/_mode_cfb.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/Cipher/__pycache__/_mode_ctr.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/Cipher/__pycache__/_mode_ctr.cpython-312.pyc new file mode 100644 index 0000000..52a5049 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Cipher/__pycache__/_mode_ctr.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/Cipher/__pycache__/_mode_eax.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/Cipher/__pycache__/_mode_eax.cpython-312.pyc new file mode 100644 index 0000000..20323e0 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Cipher/__pycache__/_mode_eax.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/Cipher/__pycache__/_mode_ecb.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/Cipher/__pycache__/_mode_ecb.cpython-312.pyc new file mode 100644 index 0000000..4d42133 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Cipher/__pycache__/_mode_ecb.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/Cipher/__pycache__/_mode_gcm.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/Cipher/__pycache__/_mode_gcm.cpython-312.pyc new file mode 100644 index 0000000..76632a0 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Cipher/__pycache__/_mode_gcm.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/Cipher/__pycache__/_mode_kw.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/Cipher/__pycache__/_mode_kw.cpython-312.pyc new file mode 100644 index 0000000..43d97c0 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Cipher/__pycache__/_mode_kw.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/Cipher/__pycache__/_mode_kwp.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/Cipher/__pycache__/_mode_kwp.cpython-312.pyc new file mode 100644 index 0000000..62f6084 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Cipher/__pycache__/_mode_kwp.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/Cipher/__pycache__/_mode_ocb.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/Cipher/__pycache__/_mode_ocb.cpython-312.pyc new file mode 100644 index 0000000..80415c4 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Cipher/__pycache__/_mode_ocb.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/Cipher/__pycache__/_mode_ofb.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/Cipher/__pycache__/_mode_ofb.cpython-312.pyc new file mode 100644 index 0000000..94e6a54 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Cipher/__pycache__/_mode_ofb.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/Cipher/__pycache__/_mode_openpgp.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/Cipher/__pycache__/_mode_openpgp.cpython-312.pyc new file mode 100644 index 0000000..ff2f1de Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Cipher/__pycache__/_mode_openpgp.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/Cipher/__pycache__/_mode_siv.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/Cipher/__pycache__/_mode_siv.cpython-312.pyc new file mode 100644 index 0000000..509d879 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Cipher/__pycache__/_mode_siv.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/Cipher/__pycache__/_pkcs1_oaep_decode.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/Cipher/__pycache__/_pkcs1_oaep_decode.cpython-312.pyc new file mode 100644 index 0000000..d0f023d Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Cipher/__pycache__/_pkcs1_oaep_decode.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/Cipher/_chacha20.pyd b/venv/Lib/site-packages/Cryptodome/Cipher/_chacha20.pyd new file mode 100644 index 0000000..6d16bb1 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Cipher/_chacha20.pyd differ diff --git a/venv/Lib/site-packages/Cryptodome/Cipher/_mode_cbc.py b/venv/Lib/site-packages/Cryptodome/Cipher/_mode_cbc.py new file mode 100644 index 0000000..94d02e7 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Cipher/_mode_cbc.py @@ -0,0 +1,293 @@ +# =================================================================== +# +# Copyright (c) 2014, Legrandin +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# =================================================================== + +""" +Ciphertext Block Chaining (CBC) mode. +""" + +__all__ = ['CbcMode'] + +from Cryptodome.Util.py3compat import _copy_bytes +from Cryptodome.Util._raw_api import (load_pycryptodome_raw_lib, VoidPointer, + create_string_buffer, get_raw_buffer, + SmartPointer, c_size_t, c_uint8_ptr, + is_writeable_buffer) + +from Cryptodome.Random import get_random_bytes + +raw_cbc_lib = load_pycryptodome_raw_lib("Cryptodome.Cipher._raw_cbc", """ + int CBC_start_operation(void *cipher, + const uint8_t iv[], + size_t iv_len, + void **pResult); + int CBC_encrypt(void *cbcState, + const uint8_t *in, + uint8_t *out, + size_t data_len); + int CBC_decrypt(void *cbcState, + const uint8_t *in, + uint8_t *out, + size_t data_len); + int CBC_stop_operation(void *state); + """ + ) + + +class CbcMode(object): + """*Cipher-Block Chaining (CBC)*. + + Each of the ciphertext blocks depends on the current + and all previous plaintext blocks. + + An Initialization Vector (*IV*) is required. + + See `NIST SP800-38A`_ , Section 6.2 . + + .. _`NIST SP800-38A` : http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf + + :undocumented: __init__ + """ + + def __init__(self, block_cipher, iv): + """Create a new block cipher, configured in CBC mode. + + :Parameters: + block_cipher : C pointer + A smart pointer to the low-level block cipher instance. + + iv : bytes/bytearray/memoryview + The initialization vector to use for encryption or decryption. + It is as long as the cipher block. + + **The IV must be unpredictable**. Ideally it is picked randomly. + + Reusing the *IV* for encryptions performed with the same key + compromises confidentiality. + """ + + self._state = VoidPointer() + result = raw_cbc_lib.CBC_start_operation(block_cipher.get(), + c_uint8_ptr(iv), + c_size_t(len(iv)), + self._state.address_of()) + if result: + raise ValueError("Error %d while instantiating the CBC mode" + % result) + + # Ensure that object disposal of this Python object will (eventually) + # free the memory allocated by the raw library for the cipher mode + self._state = SmartPointer(self._state.get(), + raw_cbc_lib.CBC_stop_operation) + + # Memory allocated for the underlying block cipher is now owed + # by the cipher mode + block_cipher.release() + + self.block_size = len(iv) + """The block size of the underlying cipher, in bytes.""" + + self.iv = _copy_bytes(None, None, iv) + """The Initialization Vector originally used to create the object. + The value does not change.""" + + self.IV = self.iv + """Alias for `iv`""" + + self._next = ["encrypt", "decrypt"] + + def encrypt(self, plaintext, output=None): + """Encrypt data with the key and the parameters set at initialization. + + A cipher object is stateful: once you have encrypted a message + you cannot encrypt (or decrypt) another message using the same + object. + + The data to encrypt can be broken up in two or + more pieces and `encrypt` can be called multiple times. + + That is, the statement: + + >>> c.encrypt(a) + c.encrypt(b) + + is equivalent to: + + >>> c.encrypt(a+b) + + That also means that you cannot reuse an object for encrypting + or decrypting other data with the same key. + + This function does not add any padding to the plaintext. + + :Parameters: + plaintext : bytes/bytearray/memoryview + The piece of data to encrypt. + Its lenght must be multiple of the cipher block size. + :Keywords: + output : bytearray/memoryview + The location where the ciphertext must be written to. + If ``None``, the ciphertext is returned. + :Return: + If ``output`` is ``None``, the ciphertext is returned as ``bytes``. + Otherwise, ``None``. + """ + + if "encrypt" not in self._next: + raise TypeError("encrypt() cannot be called after decrypt()") + self._next = ["encrypt"] + + if output is None: + ciphertext = create_string_buffer(len(plaintext)) + else: + ciphertext = output + + if not is_writeable_buffer(output): + raise TypeError("output must be a bytearray or a writeable memoryview") + + if len(plaintext) != len(output): + raise ValueError("output must have the same length as the input" + " (%d bytes)" % len(plaintext)) + + result = raw_cbc_lib.CBC_encrypt(self._state.get(), + c_uint8_ptr(plaintext), + c_uint8_ptr(ciphertext), + c_size_t(len(plaintext))) + if result: + if result == 3: + raise ValueError("Data must be padded to %d byte boundary in CBC mode" % self.block_size) + raise ValueError("Error %d while encrypting in CBC mode" % result) + + if output is None: + return get_raw_buffer(ciphertext) + else: + return None + + def decrypt(self, ciphertext, output=None): + """Decrypt data with the key and the parameters set at initialization. + + A cipher object is stateful: once you have decrypted a message + you cannot decrypt (or encrypt) another message with the same + object. + + The data to decrypt can be broken up in two or + more pieces and `decrypt` can be called multiple times. + + That is, the statement: + + >>> c.decrypt(a) + c.decrypt(b) + + is equivalent to: + + >>> c.decrypt(a+b) + + This function does not remove any padding from the plaintext. + + :Parameters: + ciphertext : bytes/bytearray/memoryview + The piece of data to decrypt. + Its length must be multiple of the cipher block size. + :Keywords: + output : bytearray/memoryview + The location where the plaintext must be written to. + If ``None``, the plaintext is returned. + :Return: + If ``output`` is ``None``, the plaintext is returned as ``bytes``. + Otherwise, ``None``. + """ + + if "decrypt" not in self._next: + raise TypeError("decrypt() cannot be called after encrypt()") + self._next = ["decrypt"] + + if output is None: + plaintext = create_string_buffer(len(ciphertext)) + else: + plaintext = output + + if not is_writeable_buffer(output): + raise TypeError("output must be a bytearray or a writeable memoryview") + + if len(ciphertext) != len(output): + raise ValueError("output must have the same length as the input" + " (%d bytes)" % len(plaintext)) + + result = raw_cbc_lib.CBC_decrypt(self._state.get(), + c_uint8_ptr(ciphertext), + c_uint8_ptr(plaintext), + c_size_t(len(ciphertext))) + if result: + if result == 3: + raise ValueError("Data must be padded to %d byte boundary in CBC mode" % self.block_size) + raise ValueError("Error %d while decrypting in CBC mode" % result) + + if output is None: + return get_raw_buffer(plaintext) + else: + return None + + +def _create_cbc_cipher(factory, **kwargs): + """Instantiate a cipher object that performs CBC encryption/decryption. + + :Parameters: + factory : module + The underlying block cipher, a module from ``Cryptodome.Cipher``. + + :Keywords: + iv : bytes/bytearray/memoryview + The IV to use for CBC. + + IV : bytes/bytearray/memoryview + Alias for ``iv``. + + Any other keyword will be passed to the underlying block cipher. + See the relevant documentation for details (at least ``key`` will need + to be present). + """ + + cipher_state = factory._create_base_cipher(kwargs) + iv = kwargs.pop("IV", None) + IV = kwargs.pop("iv", None) + + if (None, None) == (iv, IV): + iv = get_random_bytes(factory.block_size) + if iv is not None: + if IV is not None: + raise TypeError("You must either use 'iv' or 'IV', not both") + else: + iv = IV + + if len(iv) != factory.block_size: + raise ValueError("Incorrect IV length (it must be %d bytes long)" % + factory.block_size) + + if kwargs: + raise TypeError("Unknown parameters for CBC: %s" % str(kwargs)) + + return CbcMode(cipher_state, iv) diff --git a/venv/Lib/site-packages/Cryptodome/Cipher/_mode_cbc.pyi b/venv/Lib/site-packages/Cryptodome/Cipher/_mode_cbc.pyi new file mode 100644 index 0000000..526632e --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Cipher/_mode_cbc.pyi @@ -0,0 +1,25 @@ +from typing import Union, overload + +from Cryptodome.Util._raw_api import SmartPointer + +Buffer = Union[bytes, bytearray, memoryview] + +__all__ = ['CbcMode'] + +class CbcMode(object): + block_size: int + iv: Buffer + IV: Buffer + + def __init__(self, + block_cipher: SmartPointer, + iv: Buffer) -> None: ... + @overload + def encrypt(self, plaintext: Buffer) -> bytes: ... + @overload + def encrypt(self, plaintext: Buffer, output: Union[bytearray, memoryview]) -> None: ... + @overload + def decrypt(self, plaintext: Buffer) -> bytes: ... + @overload + def decrypt(self, plaintext: Buffer, output: Union[bytearray, memoryview]) -> None: ... + diff --git a/venv/Lib/site-packages/Cryptodome/Cipher/_mode_ccm.py b/venv/Lib/site-packages/Cryptodome/Cipher/_mode_ccm.py new file mode 100644 index 0000000..ac27221 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Cipher/_mode_ccm.py @@ -0,0 +1,671 @@ +# =================================================================== +# +# Copyright (c) 2014, Legrandin +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# =================================================================== + +""" +Counter with CBC-MAC (CCM) mode. +""" + +__all__ = ['CcmMode'] + +import struct +from binascii import unhexlify + +from Cryptodome.Util.py3compat import (byte_string, bord, + _copy_bytes) +from Cryptodome.Util._raw_api import is_writeable_buffer + +from Cryptodome.Util.strxor import strxor +from Cryptodome.Util.number import long_to_bytes + +from Cryptodome.Hash import BLAKE2s +from Cryptodome.Random import get_random_bytes + + +def enum(**enums): + return type('Enum', (), enums) + +MacStatus = enum(NOT_STARTED=0, PROCESSING_AUTH_DATA=1, PROCESSING_PLAINTEXT=2) + + +class CCMMessageTooLongError(ValueError): + pass + + +class CcmMode(object): + """Counter with CBC-MAC (CCM). + + This is an Authenticated Encryption with Associated Data (`AEAD`_) mode. + It provides both confidentiality and authenticity. + + The header of the message may be left in the clear, if needed, and it will + still be subject to authentication. The decryption step tells the receiver + if the message comes from a source that really knowns the secret key. + Additionally, decryption detects if any part of the message - including the + header - has been modified or corrupted. + + This mode requires a nonce. The nonce shall never repeat for two + different messages encrypted with the same key, but it does not need + to be random. + Note that there is a trade-off between the size of the nonce and the + maximum size of a single message you can encrypt. + + It is important to use a large nonce if the key is reused across several + messages and the nonce is chosen randomly. + + It is acceptable to us a short nonce if the key is only used a few times or + if the nonce is taken from a counter. + + The following table shows the trade-off when the nonce is chosen at + random. The column on the left shows how many messages it takes + for the keystream to repeat **on average**. In practice, you will want to + stop using the key way before that. + + +--------------------+---------------+-------------------+ + | Avg. # of messages | nonce | Max. message | + | before keystream | size | size | + | repeats | (bytes) | (bytes) | + +====================+===============+===================+ + | 2^52 | 13 | 64K | + +--------------------+---------------+-------------------+ + | 2^48 | 12 | 16M | + +--------------------+---------------+-------------------+ + | 2^44 | 11 | 4G | + +--------------------+---------------+-------------------+ + | 2^40 | 10 | 1T | + +--------------------+---------------+-------------------+ + | 2^36 | 9 | 64P | + +--------------------+---------------+-------------------+ + | 2^32 | 8 | 16E | + +--------------------+---------------+-------------------+ + + This mode is only available for ciphers that operate on 128 bits blocks + (e.g. AES but not TDES). + + See `NIST SP800-38C`_ or RFC3610_. + + .. _`NIST SP800-38C`: http://csrc.nist.gov/publications/nistpubs/800-38C/SP800-38C.pdf + .. _RFC3610: https://tools.ietf.org/html/rfc3610 + .. _AEAD: http://blog.cryptographyengineering.com/2012/05/how-to-choose-authenticated-encryption.html + + :undocumented: __init__ + """ + + def __init__(self, factory, key, nonce, mac_len, msg_len, assoc_len, + cipher_params): + + self.block_size = factory.block_size + """The block size of the underlying cipher, in bytes.""" + + self.nonce = _copy_bytes(None, None, nonce) + """The nonce used for this cipher instance""" + + self._factory = factory + self._key = _copy_bytes(None, None, key) + self._mac_len = mac_len + self._msg_len = msg_len + self._assoc_len = assoc_len + self._cipher_params = cipher_params + + self._mac_tag = None # Cache for MAC tag + + if self.block_size != 16: + raise ValueError("CCM mode is only available for ciphers" + " that operate on 128 bits blocks") + + # MAC tag length (Tlen) + if mac_len not in (4, 6, 8, 10, 12, 14, 16): + raise ValueError("Parameter 'mac_len' must be even" + " and in the range 4..16 (not %d)" % mac_len) + + # Nonce value + if not (7 <= len(nonce) <= 13): + raise ValueError("Length of parameter 'nonce' must be" + " in the range 7..13 bytes") + + # Message length (if known already) + q = 15 - len(nonce) # length of Q, the encoded message length + if msg_len and len(long_to_bytes(msg_len)) > q: + raise CCMMessageTooLongError("Message too long for a %u-byte nonce" % len(nonce)) + + # Create MAC object (the tag will be the last block + # bytes worth of ciphertext) + self._mac = self._factory.new(key, + factory.MODE_CBC, + iv=b'\x00' * 16, + **cipher_params) + self._mac_status = MacStatus.NOT_STARTED + self._t = None + + # Allowed transitions after initialization + self._next = ["update", "encrypt", "decrypt", + "digest", "verify"] + + # Cumulative lengths + self._cumul_assoc_len = 0 + self._cumul_msg_len = 0 + + # Cache for unaligned associated data/plaintext. + # This is a list with byte strings, but when the MAC starts, + # it will become a binary string no longer than the block size. + self._cache = [] + + # Start CTR cipher, by formatting the counter (A.3) + self._cipher = self._factory.new(key, + self._factory.MODE_CTR, + nonce=struct.pack("B", q - 1) + self.nonce, + **cipher_params) + + # S_0, step 6 in 6.1 for j=0 + self._s_0 = self._cipher.encrypt(b'\x00' * 16) + + # Try to start the MAC + if None not in (assoc_len, msg_len): + self._start_mac() + + def _start_mac(self): + + assert(self._mac_status == MacStatus.NOT_STARTED) + assert(None not in (self._assoc_len, self._msg_len)) + assert(isinstance(self._cache, list)) + + # Formatting control information and nonce (A.2.1) + q = 15 - len(self.nonce) # length of Q, the encoded message length (2..8) + flags = (self._assoc_len > 0) << 6 + flags |= ((self._mac_len - 2) // 2) << 3 + flags |= q - 1 + b_0 = struct.pack("B", flags) + self.nonce + long_to_bytes(self._msg_len, q) + + # Formatting associated data (A.2.2) + # Encoded 'a' is concatenated with the associated data 'A' + assoc_len_encoded = b'' + if self._assoc_len > 0: + if self._assoc_len < (2 ** 16 - 2 ** 8): + enc_size = 2 + elif self._assoc_len < (2 ** 32): + assoc_len_encoded = b'\xFF\xFE' + enc_size = 4 + else: + assoc_len_encoded = b'\xFF\xFF' + enc_size = 8 + assoc_len_encoded += long_to_bytes(self._assoc_len, enc_size) + + # b_0 and assoc_len_encoded must be processed first + self._cache.insert(0, b_0) + self._cache.insert(1, assoc_len_encoded) + + # Process all the data cached so far + first_data_to_mac = b"".join(self._cache) + self._cache = b"" + self._mac_status = MacStatus.PROCESSING_AUTH_DATA + self._update(first_data_to_mac) + + def _pad_cache_and_update(self): + + assert(self._mac_status != MacStatus.NOT_STARTED) + assert(len(self._cache) < self.block_size) + + # Associated data is concatenated with the least number + # of zero bytes (possibly none) to reach alignment to + # the 16 byte boundary (A.2.3) + len_cache = len(self._cache) + if len_cache > 0: + self._update(b'\x00' * (self.block_size - len_cache)) + + def update(self, assoc_data): + """Protect associated data + + If there is any associated data, the caller has to invoke + this function one or more times, before using + ``decrypt`` or ``encrypt``. + + By *associated data* it is meant any data (e.g. packet headers) that + will not be encrypted and will be transmitted in the clear. + However, the receiver is still able to detect any modification to it. + In CCM, the *associated data* is also called + *additional authenticated data* (AAD). + + If there is no associated data, this method must not be called. + + The caller may split associated data in segments of any size, and + invoke this method multiple times, each time with the next segment. + + :Parameters: + assoc_data : bytes/bytearray/memoryview + A piece of associated data. There are no restrictions on its size. + """ + + if "update" not in self._next: + raise TypeError("update() can only be called" + " immediately after initialization") + + self._next = ["update", "encrypt", "decrypt", + "digest", "verify"] + + self._cumul_assoc_len += len(assoc_data) + if self._assoc_len is not None and \ + self._cumul_assoc_len > self._assoc_len: + raise ValueError("Associated data is too long") + + self._update(assoc_data) + return self + + def _update(self, assoc_data_pt=b""): + """Update the MAC with associated data or plaintext + (without FSM checks)""" + + # If MAC has not started yet, we just park the data into a list. + # If the data is mutable, we create a copy and store that instead. + if self._mac_status == MacStatus.NOT_STARTED: + if is_writeable_buffer(assoc_data_pt): + assoc_data_pt = _copy_bytes(None, None, assoc_data_pt) + self._cache.append(assoc_data_pt) + return + + assert(len(self._cache) < self.block_size) + + if len(self._cache) > 0: + filler = min(self.block_size - len(self._cache), + len(assoc_data_pt)) + self._cache += _copy_bytes(None, filler, assoc_data_pt) + assoc_data_pt = _copy_bytes(filler, None, assoc_data_pt) + + if len(self._cache) < self.block_size: + return + + # The cache is exactly one block + self._t = self._mac.encrypt(self._cache) + self._cache = b"" + + update_len = len(assoc_data_pt) // self.block_size * self.block_size + self._cache = _copy_bytes(update_len, None, assoc_data_pt) + if update_len > 0: + self._t = self._mac.encrypt(assoc_data_pt[:update_len])[-16:] + + def encrypt(self, plaintext, output=None): + """Encrypt data with the key set at initialization. + + A cipher object is stateful: once you have encrypted a message + you cannot encrypt (or decrypt) another message using the same + object. + + This method can be called only **once** if ``msg_len`` was + not passed at initialization. + + If ``msg_len`` was given, the data to encrypt can be broken + up in two or more pieces and `encrypt` can be called + multiple times. + + That is, the statement: + + >>> c.encrypt(a) + c.encrypt(b) + + is equivalent to: + + >>> c.encrypt(a+b) + + This function does not add any padding to the plaintext. + + :Parameters: + plaintext : bytes/bytearray/memoryview + The piece of data to encrypt. + It can be of any length. + :Keywords: + output : bytearray/memoryview + The location where the ciphertext must be written to. + If ``None``, the ciphertext is returned. + :Return: + If ``output`` is ``None``, the ciphertext as ``bytes``. + Otherwise, ``None``. + """ + + if "encrypt" not in self._next: + raise TypeError("encrypt() can only be called after" + " initialization or an update()") + self._next = ["encrypt", "digest"] + + # No more associated data allowed from now + if self._assoc_len is None: + assert(isinstance(self._cache, list)) + self._assoc_len = sum([len(x) for x in self._cache]) + if self._msg_len is not None: + self._start_mac() + else: + if self._cumul_assoc_len < self._assoc_len: + raise ValueError("Associated data is too short") + + # Only once piece of plaintext accepted if message length was + # not declared in advance + if self._msg_len is None: + q = 15 - len(self.nonce) + if len(long_to_bytes(len(plaintext))) > q: + raise CCMMessageTooLongError("Message too long for a %u-byte nonce" % len(self.nonce)) + + self._msg_len = len(plaintext) + self._start_mac() + self._next = ["digest"] + + self._cumul_msg_len += len(plaintext) + if self._cumul_msg_len > self._msg_len: + msg = "Message longer than declared for (%u bytes vs %u bytes" % \ + (self._cumul_msg_len, self._msg_len) + raise CCMMessageTooLongError(msg) + + if self._mac_status == MacStatus.PROCESSING_AUTH_DATA: + # Associated data is concatenated with the least number + # of zero bytes (possibly none) to reach alignment to + # the 16 byte boundary (A.2.3) + self._pad_cache_and_update() + self._mac_status = MacStatus.PROCESSING_PLAINTEXT + + self._update(plaintext) + return self._cipher.encrypt(plaintext, output=output) + + def decrypt(self, ciphertext, output=None): + """Decrypt data with the key set at initialization. + + A cipher object is stateful: once you have decrypted a message + you cannot decrypt (or encrypt) another message with the same + object. + + This method can be called only **once** if ``msg_len`` was + not passed at initialization. + + If ``msg_len`` was given, the data to decrypt can be + broken up in two or more pieces and `decrypt` can be + called multiple times. + + That is, the statement: + + >>> c.decrypt(a) + c.decrypt(b) + + is equivalent to: + + >>> c.decrypt(a+b) + + This function does not remove any padding from the plaintext. + + :Parameters: + ciphertext : bytes/bytearray/memoryview + The piece of data to decrypt. + It can be of any length. + :Keywords: + output : bytearray/memoryview + The location where the plaintext must be written to. + If ``None``, the plaintext is returned. + :Return: + If ``output`` is ``None``, the plaintext as ``bytes``. + Otherwise, ``None``. + """ + + if "decrypt" not in self._next: + raise TypeError("decrypt() can only be called" + " after initialization or an update()") + self._next = ["decrypt", "verify"] + + # No more associated data allowed from now + if self._assoc_len is None: + assert(isinstance(self._cache, list)) + self._assoc_len = sum([len(x) for x in self._cache]) + if self._msg_len is not None: + self._start_mac() + else: + if self._cumul_assoc_len < self._assoc_len: + raise ValueError("Associated data is too short") + + # Only once piece of ciphertext accepted if message length was + # not declared in advance + if self._msg_len is None: + q = 15 - len(self.nonce) + if len(long_to_bytes(len(ciphertext))) > q: + raise CCMMessageTooLongError("Message too long for a %u-byte nonce" % len(self.nonce)) + + self._msg_len = len(ciphertext) + self._start_mac() + self._next = ["verify"] + + self._cumul_msg_len += len(ciphertext) + if self._cumul_msg_len > self._msg_len: + msg = "Message longer than declared for (%u bytes vs %u bytes" % \ + (self._cumul_msg_len, self._msg_len) + raise CCMMessageTooLongError(msg) + + if self._mac_status == MacStatus.PROCESSING_AUTH_DATA: + # Associated data is concatenated with the least number + # of zero bytes (possibly none) to reach alignment to + # the 16 byte boundary (A.2.3) + self._pad_cache_and_update() + self._mac_status = MacStatus.PROCESSING_PLAINTEXT + + # Encrypt is equivalent to decrypt with the CTR mode + plaintext = self._cipher.encrypt(ciphertext, output=output) + if output is None: + self._update(plaintext) + else: + self._update(output) + return plaintext + + def digest(self): + """Compute the *binary* MAC tag. + + The caller invokes this function at the very end. + + This method returns the MAC that shall be sent to the receiver, + together with the ciphertext. + + :Return: the MAC, as a byte string. + """ + + if "digest" not in self._next: + raise TypeError("digest() cannot be called when decrypting" + " or validating a message") + self._next = ["digest"] + return self._digest() + + def _digest(self): + if self._mac_tag: + return self._mac_tag + + if self._assoc_len is None: + assert(isinstance(self._cache, list)) + self._assoc_len = sum([len(x) for x in self._cache]) + if self._msg_len is not None: + self._start_mac() + else: + if self._cumul_assoc_len < self._assoc_len: + raise ValueError("Associated data is too short") + + if self._msg_len is None: + self._msg_len = 0 + self._start_mac() + + if self._cumul_msg_len != self._msg_len: + raise ValueError("Message is too short") + + # Both associated data and payload are concatenated with the least + # number of zero bytes (possibly none) that align it to the + # 16 byte boundary (A.2.2 and A.2.3) + self._pad_cache_and_update() + + # Step 8 in 6.1 (T xor MSB_Tlen(S_0)) + self._mac_tag = strxor(self._t, self._s_0)[:self._mac_len] + + return self._mac_tag + + def hexdigest(self): + """Compute the *printable* MAC tag. + + This method is like `digest`. + + :Return: the MAC, as a hexadecimal string. + """ + return "".join(["%02x" % bord(x) for x in self.digest()]) + + def verify(self, received_mac_tag): + """Validate the *binary* MAC tag. + + The caller invokes this function at the very end. + + This method checks if the decrypted message is indeed valid + (that is, if the key is correct) and it has not been + tampered with while in transit. + + :Parameters: + received_mac_tag : bytes/bytearray/memoryview + This is the *binary* MAC, as received from the sender. + :Raises ValueError: + if the MAC does not match. The message has been tampered with + or the key is incorrect. + """ + + if "verify" not in self._next: + raise TypeError("verify() cannot be called" + " when encrypting a message") + self._next = ["verify"] + + self._digest() + secret = get_random_bytes(16) + + mac1 = BLAKE2s.new(digest_bits=160, key=secret, data=self._mac_tag) + mac2 = BLAKE2s.new(digest_bits=160, key=secret, data=received_mac_tag) + + if mac1.digest() != mac2.digest(): + raise ValueError("MAC check failed") + + def hexverify(self, hex_mac_tag): + """Validate the *printable* MAC tag. + + This method is like `verify`. + + :Parameters: + hex_mac_tag : string + This is the *printable* MAC, as received from the sender. + :Raises ValueError: + if the MAC does not match. The message has been tampered with + or the key is incorrect. + """ + + self.verify(unhexlify(hex_mac_tag)) + + def encrypt_and_digest(self, plaintext, output=None): + """Perform encrypt() and digest() in one step. + + :Parameters: + plaintext : bytes/bytearray/memoryview + The piece of data to encrypt. + :Keywords: + output : bytearray/memoryview + The location where the ciphertext must be written to. + If ``None``, the ciphertext is returned. + :Return: + a tuple with two items: + + - the ciphertext, as ``bytes`` + - the MAC tag, as ``bytes`` + + The first item becomes ``None`` when the ``output`` parameter + specified a location for the result. + """ + + return self.encrypt(plaintext, output=output), self.digest() + + def decrypt_and_verify(self, ciphertext, received_mac_tag, output=None): + """Perform decrypt() and verify() in one step. + + :Parameters: + ciphertext : bytes/bytearray/memoryview + The piece of data to decrypt. + received_mac_tag : bytes/bytearray/memoryview + This is the *binary* MAC, as received from the sender. + :Keywords: + output : bytearray/memoryview + The location where the plaintext must be written to. + If ``None``, the plaintext is returned. + :Return: the plaintext as ``bytes`` or ``None`` when the ``output`` + parameter specified a location for the result. + :Raises ValueError: + if the MAC does not match. The message has been tampered with + or the key is incorrect. + """ + + plaintext = self.decrypt(ciphertext, output=output) + self.verify(received_mac_tag) + return plaintext + + +def _create_ccm_cipher(factory, **kwargs): + """Create a new block cipher, configured in CCM mode. + + :Parameters: + factory : module + A symmetric cipher module from `Cryptodome.Cipher` (like + `Cryptodome.Cipher.AES`). + + :Keywords: + key : bytes/bytearray/memoryview + The secret key to use in the symmetric cipher. + + nonce : bytes/bytearray/memoryview + A value that must never be reused for any other encryption. + + Its length must be in the range ``[7..13]``. + 11 or 12 bytes are reasonable values in general. Bear in + mind that with CCM there is a trade-off between nonce length and + maximum message size. + + If not specified, a 11 byte long random string is used. + + mac_len : integer + Length of the MAC, in bytes. It must be even and in + the range ``[4..16]``. The default is 16. + + msg_len : integer + Length of the message to (de)cipher. + If not specified, ``encrypt`` or ``decrypt`` may only be called once. + + assoc_len : integer + Length of the associated data. + If not specified, all data is internally buffered. + """ + + try: + key = key = kwargs.pop("key") + except KeyError as e: + raise TypeError("Missing parameter: " + str(e)) + + nonce = kwargs.pop("nonce", None) # N + if nonce is None: + nonce = get_random_bytes(11) + mac_len = kwargs.pop("mac_len", factory.block_size) + msg_len = kwargs.pop("msg_len", None) # p + assoc_len = kwargs.pop("assoc_len", None) # a + cipher_params = dict(kwargs) + + return CcmMode(factory, key, nonce, mac_len, msg_len, + assoc_len, cipher_params) diff --git a/venv/Lib/site-packages/Cryptodome/Cipher/_mode_ccm.pyi b/venv/Lib/site-packages/Cryptodome/Cipher/_mode_ccm.pyi new file mode 100644 index 0000000..98af96a --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Cipher/_mode_ccm.pyi @@ -0,0 +1,52 @@ +from types import ModuleType +from typing import Union, overload, Dict, Tuple, Optional + +Buffer = Union[bytes, bytearray, memoryview] + +__all__ = ['CcmMode'] + + +class CCMMessageTooLongError(ValueError): + pass + + +class CcmMode(object): + block_size: int + nonce: bytes + + def __init__(self, + factory: ModuleType, + key: Buffer, + nonce: Buffer, + mac_len: int, + msg_len: Optional[int], + assoc_len: Optional[int], + cipher_params: Dict) -> None: ... + + def update(self, assoc_data: Buffer) -> CcmMode: ... + + @overload + def encrypt(self, plaintext: Buffer) -> bytes: ... + @overload + def encrypt(self, plaintext: Buffer, output: Union[bytearray, memoryview]) -> None: ... + @overload + def decrypt(self, plaintext: Buffer) -> bytes: ... + @overload + def decrypt(self, plaintext: Buffer, output: Union[bytearray, memoryview]) -> None: ... + + def digest(self) -> bytes: ... + def hexdigest(self) -> str: ... + def verify(self, received_mac_tag: Buffer) -> None: ... + def hexverify(self, hex_mac_tag: str) -> None: ... + + @overload + def encrypt_and_digest(self, + plaintext: Buffer) -> Tuple[bytes, bytes]: ... + @overload + def encrypt_and_digest(self, + plaintext: Buffer, + output: Buffer) -> Tuple[None, bytes]: ... + def decrypt_and_verify(self, + ciphertext: Buffer, + received_mac_tag: Buffer, + output: Optional[Union[bytearray, memoryview]] = ...) -> bytes: ... diff --git a/venv/Lib/site-packages/Cryptodome/Cipher/_mode_cfb.py b/venv/Lib/site-packages/Cryptodome/Cipher/_mode_cfb.py new file mode 100644 index 0000000..1b1b6c3 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Cipher/_mode_cfb.py @@ -0,0 +1,293 @@ +# -*- coding: utf-8 -*- +# +# Cipher/mode_cfb.py : CFB mode +# +# =================================================================== +# The contents of this file are dedicated to the public domain. To +# the extent that dedication to the public domain is not available, +# everyone is granted a worldwide, perpetual, royalty-free, +# non-exclusive license to exercise all rights associated with the +# contents of this file for any purpose whatsoever. +# No rights are reserved. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# =================================================================== + +""" +Counter Feedback (CFB) mode. +""" + +__all__ = ['CfbMode'] + +from Cryptodome.Util.py3compat import _copy_bytes +from Cryptodome.Util._raw_api import (load_pycryptodome_raw_lib, VoidPointer, + create_string_buffer, get_raw_buffer, + SmartPointer, c_size_t, c_uint8_ptr, + is_writeable_buffer) + +from Cryptodome.Random import get_random_bytes + +raw_cfb_lib = load_pycryptodome_raw_lib("Cryptodome.Cipher._raw_cfb",""" + int CFB_start_operation(void *cipher, + const uint8_t iv[], + size_t iv_len, + size_t segment_len, /* In bytes */ + void **pResult); + int CFB_encrypt(void *cfbState, + const uint8_t *in, + uint8_t *out, + size_t data_len); + int CFB_decrypt(void *cfbState, + const uint8_t *in, + uint8_t *out, + size_t data_len); + int CFB_stop_operation(void *state);""" + ) + + +class CfbMode(object): + """*Cipher FeedBack (CFB)*. + + This mode is similar to CFB, but it transforms + the underlying block cipher into a stream cipher. + + Plaintext and ciphertext are processed in *segments* + of **s** bits. The mode is therefore sometimes + labelled **s**-bit CFB. + + An Initialization Vector (*IV*) is required. + + See `NIST SP800-38A`_ , Section 6.3. + + .. _`NIST SP800-38A` : http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf + + :undocumented: __init__ + """ + + def __init__(self, block_cipher, iv, segment_size): + """Create a new block cipher, configured in CFB mode. + + :Parameters: + block_cipher : C pointer + A smart pointer to the low-level block cipher instance. + + iv : bytes/bytearray/memoryview + The initialization vector to use for encryption or decryption. + It is as long as the cipher block. + + **The IV must be unpredictable**. Ideally it is picked randomly. + + Reusing the *IV* for encryptions performed with the same key + compromises confidentiality. + + segment_size : integer + The number of bytes the plaintext and ciphertext are segmented in. + """ + + self._state = VoidPointer() + result = raw_cfb_lib.CFB_start_operation(block_cipher.get(), + c_uint8_ptr(iv), + c_size_t(len(iv)), + c_size_t(segment_size), + self._state.address_of()) + if result: + raise ValueError("Error %d while instantiating the CFB mode" % result) + + # Ensure that object disposal of this Python object will (eventually) + # free the memory allocated by the raw library for the cipher mode + self._state = SmartPointer(self._state.get(), + raw_cfb_lib.CFB_stop_operation) + + # Memory allocated for the underlying block cipher is now owed + # by the cipher mode + block_cipher.release() + + self.block_size = len(iv) + """The block size of the underlying cipher, in bytes.""" + + self.iv = _copy_bytes(None, None, iv) + """The Initialization Vector originally used to create the object. + The value does not change.""" + + self.IV = self.iv + """Alias for `iv`""" + + self._next = ["encrypt", "decrypt"] + + def encrypt(self, plaintext, output=None): + """Encrypt data with the key and the parameters set at initialization. + + A cipher object is stateful: once you have encrypted a message + you cannot encrypt (or decrypt) another message using the same + object. + + The data to encrypt can be broken up in two or + more pieces and `encrypt` can be called multiple times. + + That is, the statement: + + >>> c.encrypt(a) + c.encrypt(b) + + is equivalent to: + + >>> c.encrypt(a+b) + + This function does not add any padding to the plaintext. + + :Parameters: + plaintext : bytes/bytearray/memoryview + The piece of data to encrypt. + It can be of any length. + :Keywords: + output : bytearray/memoryview + The location where the ciphertext must be written to. + If ``None``, the ciphertext is returned. + :Return: + If ``output`` is ``None``, the ciphertext is returned as ``bytes``. + Otherwise, ``None``. + """ + + if "encrypt" not in self._next: + raise TypeError("encrypt() cannot be called after decrypt()") + self._next = ["encrypt"] + + if output is None: + ciphertext = create_string_buffer(len(plaintext)) + else: + ciphertext = output + + if not is_writeable_buffer(output): + raise TypeError("output must be a bytearray or a writeable memoryview") + + if len(plaintext) != len(output): + raise ValueError("output must have the same length as the input" + " (%d bytes)" % len(plaintext)) + + result = raw_cfb_lib.CFB_encrypt(self._state.get(), + c_uint8_ptr(plaintext), + c_uint8_ptr(ciphertext), + c_size_t(len(plaintext))) + if result: + raise ValueError("Error %d while encrypting in CFB mode" % result) + + if output is None: + return get_raw_buffer(ciphertext) + else: + return None + + def decrypt(self, ciphertext, output=None): + """Decrypt data with the key and the parameters set at initialization. + + A cipher object is stateful: once you have decrypted a message + you cannot decrypt (or encrypt) another message with the same + object. + + The data to decrypt can be broken up in two or + more pieces and `decrypt` can be called multiple times. + + That is, the statement: + + >>> c.decrypt(a) + c.decrypt(b) + + is equivalent to: + + >>> c.decrypt(a+b) + + This function does not remove any padding from the plaintext. + + :Parameters: + ciphertext : bytes/bytearray/memoryview + The piece of data to decrypt. + It can be of any length. + :Keywords: + output : bytearray/memoryview + The location where the plaintext must be written to. + If ``None``, the plaintext is returned. + :Return: + If ``output`` is ``None``, the plaintext is returned as ``bytes``. + Otherwise, ``None``. + """ + + if "decrypt" not in self._next: + raise TypeError("decrypt() cannot be called after encrypt()") + self._next = ["decrypt"] + + if output is None: + plaintext = create_string_buffer(len(ciphertext)) + else: + plaintext = output + + if not is_writeable_buffer(output): + raise TypeError("output must be a bytearray or a writeable memoryview") + + if len(ciphertext) != len(output): + raise ValueError("output must have the same length as the input" + " (%d bytes)" % len(plaintext)) + + result = raw_cfb_lib.CFB_decrypt(self._state.get(), + c_uint8_ptr(ciphertext), + c_uint8_ptr(plaintext), + c_size_t(len(ciphertext))) + if result: + raise ValueError("Error %d while decrypting in CFB mode" % result) + + if output is None: + return get_raw_buffer(plaintext) + else: + return None + + +def _create_cfb_cipher(factory, **kwargs): + """Instantiate a cipher object that performs CFB encryption/decryption. + + :Parameters: + factory : module + The underlying block cipher, a module from ``Cryptodome.Cipher``. + + :Keywords: + iv : bytes/bytearray/memoryview + The IV to use for CFB. + + IV : bytes/bytearray/memoryview + Alias for ``iv``. + + segment_size : integer + The number of bit the plaintext and ciphertext are segmented in. + If not present, the default is 8. + + Any other keyword will be passed to the underlying block cipher. + See the relevant documentation for details (at least ``key`` will need + to be present). + """ + + cipher_state = factory._create_base_cipher(kwargs) + + iv = kwargs.pop("IV", None) + IV = kwargs.pop("iv", None) + + if (None, None) == (iv, IV): + iv = get_random_bytes(factory.block_size) + if iv is not None: + if IV is not None: + raise TypeError("You must either use 'iv' or 'IV', not both") + else: + iv = IV + + if len(iv) != factory.block_size: + raise ValueError("Incorrect IV length (it must be %d bytes long)" % + factory.block_size) + + segment_size_bytes, rem = divmod(kwargs.pop("segment_size", 8), 8) + if segment_size_bytes == 0 or rem != 0: + raise ValueError("'segment_size' must be positive and multiple of 8 bits") + + if kwargs: + raise TypeError("Unknown parameters for CFB: %s" % str(kwargs)) + return CfbMode(cipher_state, iv, segment_size_bytes) diff --git a/venv/Lib/site-packages/Cryptodome/Cipher/_mode_cfb.pyi b/venv/Lib/site-packages/Cryptodome/Cipher/_mode_cfb.pyi new file mode 100644 index 0000000..228e464 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Cipher/_mode_cfb.pyi @@ -0,0 +1,26 @@ +from typing import Union, overload + +from Cryptodome.Util._raw_api import SmartPointer + +Buffer = Union[bytes, bytearray, memoryview] + +__all__ = ['CfbMode'] + + +class CfbMode(object): + block_size: int + iv: Buffer + IV: Buffer + + def __init__(self, + block_cipher: SmartPointer, + iv: Buffer, + segment_size: int) -> None: ... + @overload + def encrypt(self, plaintext: Buffer) -> bytes: ... + @overload + def encrypt(self, plaintext: Buffer, output: Union[bytearray, memoryview]) -> None: ... + @overload + def decrypt(self, plaintext: Buffer) -> bytes: ... + @overload + def decrypt(self, plaintext: Buffer, output: Union[bytearray, memoryview]) -> None: ... diff --git a/venv/Lib/site-packages/Cryptodome/Cipher/_mode_ctr.py b/venv/Lib/site-packages/Cryptodome/Cipher/_mode_ctr.py new file mode 100644 index 0000000..9ce357f --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Cipher/_mode_ctr.py @@ -0,0 +1,393 @@ +# -*- coding: utf-8 -*- +# +# Cipher/mode_ctr.py : CTR mode +# +# =================================================================== +# The contents of this file are dedicated to the public domain. To +# the extent that dedication to the public domain is not available, +# everyone is granted a worldwide, perpetual, royalty-free, +# non-exclusive license to exercise all rights associated with the +# contents of this file for any purpose whatsoever. +# No rights are reserved. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# =================================================================== + +""" +Counter (CTR) mode. +""" + +__all__ = ['CtrMode'] + +import struct + +from Cryptodome.Util._raw_api import (load_pycryptodome_raw_lib, VoidPointer, + create_string_buffer, get_raw_buffer, + SmartPointer, c_size_t, c_uint8_ptr, + is_writeable_buffer) + +from Cryptodome.Random import get_random_bytes +from Cryptodome.Util.py3compat import _copy_bytes, is_native_int +from Cryptodome.Util.number import long_to_bytes + +raw_ctr_lib = load_pycryptodome_raw_lib("Cryptodome.Cipher._raw_ctr", """ + int CTR_start_operation(void *cipher, + uint8_t initialCounterBlock[], + size_t initialCounterBlock_len, + size_t prefix_len, + unsigned counter_len, + unsigned littleEndian, + void **pResult); + int CTR_encrypt(void *ctrState, + const uint8_t *in, + uint8_t *out, + size_t data_len); + int CTR_decrypt(void *ctrState, + const uint8_t *in, + uint8_t *out, + size_t data_len); + int CTR_stop_operation(void *ctrState);""" + ) + + +class CtrMode(object): + """*CounTeR (CTR)* mode. + + This mode is very similar to ECB, in that + encryption of one block is done independently of all other blocks. + + Unlike ECB, the block *position* contributes to the encryption + and no information leaks about symbol frequency. + + Each message block is associated to a *counter* which + must be unique across all messages that get encrypted + with the same key (not just within the same message). + The counter is as big as the block size. + + Counters can be generated in several ways. The most + straightword one is to choose an *initial counter block* + (which can be made public, similarly to the *IV* for the + other modes) and increment its lowest **m** bits by one + (modulo *2^m*) for each block. In most cases, **m** is + chosen to be half the block size. + + See `NIST SP800-38A`_, Section 6.5 (for the mode) and + Appendix B (for how to manage the *initial counter block*). + + .. _`NIST SP800-38A` : http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf + + :undocumented: __init__ + """ + + def __init__(self, block_cipher, initial_counter_block, + prefix_len, counter_len, little_endian): + """Create a new block cipher, configured in CTR mode. + + :Parameters: + block_cipher : C pointer + A smart pointer to the low-level block cipher instance. + + initial_counter_block : bytes/bytearray/memoryview + The initial plaintext to use to generate the key stream. + + It is as large as the cipher block, and it embeds + the initial value of the counter. + + This value must not be reused. + It shall contain a nonce or a random component. + Reusing the *initial counter block* for encryptions + performed with the same key compromises confidentiality. + + prefix_len : integer + The amount of bytes at the beginning of the counter block + that never change. + + counter_len : integer + The length in bytes of the counter embedded in the counter + block. + + little_endian : boolean + True if the counter in the counter block is an integer encoded + in little endian mode. If False, it is big endian. + """ + + if len(initial_counter_block) == prefix_len + counter_len: + self.nonce = _copy_bytes(None, prefix_len, initial_counter_block) + """Nonce; not available if there is a fixed suffix""" + + self._state = VoidPointer() + result = raw_ctr_lib.CTR_start_operation(block_cipher.get(), + c_uint8_ptr(initial_counter_block), + c_size_t(len(initial_counter_block)), + c_size_t(prefix_len), + counter_len, + little_endian, + self._state.address_of()) + if result: + raise ValueError("Error %X while instantiating the CTR mode" + % result) + + # Ensure that object disposal of this Python object will (eventually) + # free the memory allocated by the raw library for the cipher mode + self._state = SmartPointer(self._state.get(), + raw_ctr_lib.CTR_stop_operation) + + # Memory allocated for the underlying block cipher is now owed + # by the cipher mode + block_cipher.release() + + self.block_size = len(initial_counter_block) + """The block size of the underlying cipher, in bytes.""" + + self._next = ["encrypt", "decrypt"] + + def encrypt(self, plaintext, output=None): + """Encrypt data with the key and the parameters set at initialization. + + A cipher object is stateful: once you have encrypted a message + you cannot encrypt (or decrypt) another message using the same + object. + + The data to encrypt can be broken up in two or + more pieces and `encrypt` can be called multiple times. + + That is, the statement: + + >>> c.encrypt(a) + c.encrypt(b) + + is equivalent to: + + >>> c.encrypt(a+b) + + This function does not add any padding to the plaintext. + + :Parameters: + plaintext : bytes/bytearray/memoryview + The piece of data to encrypt. + It can be of any length. + :Keywords: + output : bytearray/memoryview + The location where the ciphertext must be written to. + If ``None``, the ciphertext is returned. + :Return: + If ``output`` is ``None``, the ciphertext is returned as ``bytes``. + Otherwise, ``None``. + """ + + if "encrypt" not in self._next: + raise TypeError("encrypt() cannot be called after decrypt()") + self._next = ["encrypt"] + + if output is None: + ciphertext = create_string_buffer(len(plaintext)) + else: + ciphertext = output + + if not is_writeable_buffer(output): + raise TypeError("output must be a bytearray or a writeable memoryview") + + if len(plaintext) != len(output): + raise ValueError("output must have the same length as the input" + " (%d bytes)" % len(plaintext)) + + result = raw_ctr_lib.CTR_encrypt(self._state.get(), + c_uint8_ptr(plaintext), + c_uint8_ptr(ciphertext), + c_size_t(len(plaintext))) + if result: + if result == 0x60002: + raise OverflowError("The counter has wrapped around in" + " CTR mode") + raise ValueError("Error %X while encrypting in CTR mode" % result) + + if output is None: + return get_raw_buffer(ciphertext) + else: + return None + + def decrypt(self, ciphertext, output=None): + """Decrypt data with the key and the parameters set at initialization. + + A cipher object is stateful: once you have decrypted a message + you cannot decrypt (or encrypt) another message with the same + object. + + The data to decrypt can be broken up in two or + more pieces and `decrypt` can be called multiple times. + + That is, the statement: + + >>> c.decrypt(a) + c.decrypt(b) + + is equivalent to: + + >>> c.decrypt(a+b) + + This function does not remove any padding from the plaintext. + + :Parameters: + ciphertext : bytes/bytearray/memoryview + The piece of data to decrypt. + It can be of any length. + :Keywords: + output : bytearray/memoryview + The location where the plaintext must be written to. + If ``None``, the plaintext is returned. + :Return: + If ``output`` is ``None``, the plaintext is returned as ``bytes``. + Otherwise, ``None``. + """ + + if "decrypt" not in self._next: + raise TypeError("decrypt() cannot be called after encrypt()") + self._next = ["decrypt"] + + if output is None: + plaintext = create_string_buffer(len(ciphertext)) + else: + plaintext = output + + if not is_writeable_buffer(output): + raise TypeError("output must be a bytearray or a writeable memoryview") + + if len(ciphertext) != len(output): + raise ValueError("output must have the same length as the input" + " (%d bytes)" % len(plaintext)) + + result = raw_ctr_lib.CTR_decrypt(self._state.get(), + c_uint8_ptr(ciphertext), + c_uint8_ptr(plaintext), + c_size_t(len(ciphertext))) + if result: + if result == 0x60002: + raise OverflowError("The counter has wrapped around in" + " CTR mode") + raise ValueError("Error %X while decrypting in CTR mode" % result) + + if output is None: + return get_raw_buffer(plaintext) + else: + return None + + +def _create_ctr_cipher(factory, **kwargs): + """Instantiate a cipher object that performs CTR encryption/decryption. + + :Parameters: + factory : module + The underlying block cipher, a module from ``Cryptodome.Cipher``. + + :Keywords: + nonce : bytes/bytearray/memoryview + The fixed part at the beginning of the counter block - the rest is + the counter number that gets increased when processing the next block. + The nonce must be such that no two messages are encrypted under the + same key and the same nonce. + + The nonce must be shorter than the block size (it can have + zero length; the counter is then as long as the block). + + If this parameter is not present, a random nonce will be created with + length equal to half the block size. No random nonce shorter than + 64 bits will be created though - you must really think through all + security consequences of using such a short block size. + + initial_value : posive integer or bytes/bytearray/memoryview + The initial value for the counter. If not present, the cipher will + start counting from 0. The value is incremented by one for each block. + The counter number is encoded in big endian mode. + + counter : object + Instance of ``Cryptodome.Util.Counter``, which allows full customization + of the counter block. This parameter is incompatible to both ``nonce`` + and ``initial_value``. + + Any other keyword will be passed to the underlying block cipher. + See the relevant documentation for details (at least ``key`` will need + to be present). + """ + + cipher_state = factory._create_base_cipher(kwargs) + + counter = kwargs.pop("counter", None) + nonce = kwargs.pop("nonce", None) + initial_value = kwargs.pop("initial_value", None) + if kwargs: + raise TypeError("Invalid parameters for CTR mode: %s" % str(kwargs)) + + if counter is not None and (nonce, initial_value) != (None, None): + raise TypeError("'counter' and 'nonce'/'initial_value'" + " are mutually exclusive") + + if counter is None: + # Cryptodome.Util.Counter is not used + if nonce is None: + if factory.block_size < 16: + raise TypeError("Impossible to create a safe nonce for short" + " block sizes") + nonce = get_random_bytes(factory.block_size // 2) + else: + if len(nonce) >= factory.block_size: + raise ValueError("Nonce is too long") + + # What is not nonce is counter + counter_len = factory.block_size - len(nonce) + + if initial_value is None: + initial_value = 0 + + if is_native_int(initial_value): + if (1 << (counter_len * 8)) - 1 < initial_value: + raise ValueError("Initial counter value is too large") + initial_counter_block = nonce + long_to_bytes(initial_value, counter_len) + else: + if len(initial_value) != counter_len: + raise ValueError("Incorrect length for counter byte string (%d bytes, expected %d)" % + (len(initial_value), counter_len)) + initial_counter_block = nonce + initial_value + + return CtrMode(cipher_state, + initial_counter_block, + len(nonce), # prefix + counter_len, + False) # little_endian + + # Cryptodome.Util.Counter is used + + # 'counter' used to be a callable object, but now it is + # just a dictionary for backward compatibility. + _counter = dict(counter) + try: + counter_len = _counter.pop("counter_len") + prefix = _counter.pop("prefix") + suffix = _counter.pop("suffix") + initial_value = _counter.pop("initial_value") + little_endian = _counter.pop("little_endian") + except KeyError: + raise TypeError("Incorrect counter object" + " (use Cryptodome.Util.Counter.new)") + + # Compute initial counter block + words = [] + while initial_value > 0: + words.append(struct.pack('B', initial_value & 255)) + initial_value >>= 8 + words += [b'\x00'] * max(0, counter_len - len(words)) + if not little_endian: + words.reverse() + initial_counter_block = prefix + b"".join(words) + suffix + + if len(initial_counter_block) != factory.block_size: + raise ValueError("Size of the counter block (%d bytes) must match" + " block size (%d)" % (len(initial_counter_block), + factory.block_size)) + + return CtrMode(cipher_state, initial_counter_block, + len(prefix), counter_len, little_endian) diff --git a/venv/Lib/site-packages/Cryptodome/Cipher/_mode_ctr.pyi b/venv/Lib/site-packages/Cryptodome/Cipher/_mode_ctr.pyi new file mode 100644 index 0000000..a68a890 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Cipher/_mode_ctr.pyi @@ -0,0 +1,27 @@ +from typing import Union, overload + +from Cryptodome.Util._raw_api import SmartPointer + +Buffer = Union[bytes, bytearray, memoryview] + +__all__ = ['CtrMode'] + +class CtrMode(object): + block_size: int + nonce: bytes + + def __init__(self, + block_cipher: SmartPointer, + initial_counter_block: Buffer, + prefix_len: int, + counter_len: int, + little_endian: bool) -> None: ... + @overload + def encrypt(self, plaintext: Buffer) -> bytes: ... + @overload + def encrypt(self, plaintext: Buffer, output: Union[bytearray, memoryview]) -> None: ... + @overload + def decrypt(self, plaintext: Buffer) -> bytes: ... + @overload + def decrypt(self, plaintext: Buffer, output: Union[bytearray, memoryview]) -> None: ... + diff --git a/venv/Lib/site-packages/Cryptodome/Cipher/_mode_eax.py b/venv/Lib/site-packages/Cryptodome/Cipher/_mode_eax.py new file mode 100644 index 0000000..44ef21f --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Cipher/_mode_eax.py @@ -0,0 +1,408 @@ +# =================================================================== +# +# Copyright (c) 2014, Legrandin +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# =================================================================== + +""" +EAX mode. +""" + +__all__ = ['EaxMode'] + +import struct +from binascii import unhexlify + +from Cryptodome.Util.py3compat import byte_string, bord, _copy_bytes + +from Cryptodome.Util._raw_api import is_buffer + +from Cryptodome.Util.strxor import strxor +from Cryptodome.Util.number import long_to_bytes, bytes_to_long + +from Cryptodome.Hash import CMAC, BLAKE2s +from Cryptodome.Random import get_random_bytes + + +class EaxMode(object): + """*EAX* mode. + + This is an Authenticated Encryption with Associated Data + (`AEAD`_) mode. It provides both confidentiality and authenticity. + + The header of the message may be left in the clear, if needed, + and it will still be subject to authentication. + + The decryption step tells the receiver if the message comes + from a source that really knowns the secret key. + Additionally, decryption detects if any part of the message - + including the header - has been modified or corrupted. + + This mode requires a *nonce*. + + This mode is only available for ciphers that operate on 64 or + 128 bits blocks. + + There are no official standards defining EAX. + The implementation is based on `a proposal`__ that + was presented to NIST. + + .. _AEAD: http://blog.cryptographyengineering.com/2012/05/how-to-choose-authenticated-encryption.html + .. __: http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/eax/eax-spec.pdf + + :undocumented: __init__ + """ + + def __init__(self, factory, key, nonce, mac_len, cipher_params): + """EAX cipher mode""" + + self.block_size = factory.block_size + """The block size of the underlying cipher, in bytes.""" + + self.nonce = _copy_bytes(None, None, nonce) + """The nonce originally used to create the object.""" + + self._mac_len = mac_len + self._mac_tag = None # Cache for MAC tag + + # Allowed transitions after initialization + self._next = ["update", "encrypt", "decrypt", + "digest", "verify"] + + # MAC tag length + if not (2 <= self._mac_len <= self.block_size): + raise ValueError("'mac_len' must be at least 2 and not larger than %d" + % self.block_size) + + # Nonce cannot be empty and must be a byte string + if len(self.nonce) == 0: + raise ValueError("Nonce cannot be empty in EAX mode") + if not is_buffer(nonce): + raise TypeError("nonce must be bytes, bytearray or memoryview") + + self._omac = [ + CMAC.new(key, + b'\x00' * (self.block_size - 1) + struct.pack('B', i), + ciphermod=factory, + cipher_params=cipher_params) + for i in range(0, 3) + ] + + # Compute MAC of nonce + self._omac[0].update(self.nonce) + self._signer = self._omac[1] + + # MAC of the nonce is also the initial counter for CTR encryption + counter_int = bytes_to_long(self._omac[0].digest()) + self._cipher = factory.new(key, + factory.MODE_CTR, + initial_value=counter_int, + nonce=b"", + **cipher_params) + + def update(self, assoc_data): + """Protect associated data + + If there is any associated data, the caller has to invoke + this function one or more times, before using + ``decrypt`` or ``encrypt``. + + By *associated data* it is meant any data (e.g. packet headers) that + will not be encrypted and will be transmitted in the clear. + However, the receiver is still able to detect any modification to it. + + If there is no associated data, this method must not be called. + + The caller may split associated data in segments of any size, and + invoke this method multiple times, each time with the next segment. + + :Parameters: + assoc_data : bytes/bytearray/memoryview + A piece of associated data. There are no restrictions on its size. + """ + + if "update" not in self._next: + raise TypeError("update() can only be called" + " immediately after initialization") + + self._next = ["update", "encrypt", "decrypt", + "digest", "verify"] + + self._signer.update(assoc_data) + return self + + def encrypt(self, plaintext, output=None): + """Encrypt data with the key and the parameters set at initialization. + + A cipher object is stateful: once you have encrypted a message + you cannot encrypt (or decrypt) another message using the same + object. + + The data to encrypt can be broken up in two or + more pieces and `encrypt` can be called multiple times. + + That is, the statement: + + >>> c.encrypt(a) + c.encrypt(b) + + is equivalent to: + + >>> c.encrypt(a+b) + + This function does not add any padding to the plaintext. + + :Parameters: + plaintext : bytes/bytearray/memoryview + The piece of data to encrypt. + It can be of any length. + :Keywords: + output : bytearray/memoryview + The location where the ciphertext must be written to. + If ``None``, the ciphertext is returned. + :Return: + If ``output`` is ``None``, the ciphertext as ``bytes``. + Otherwise, ``None``. + """ + + if "encrypt" not in self._next: + raise TypeError("encrypt() can only be called after" + " initialization or an update()") + self._next = ["encrypt", "digest"] + ct = self._cipher.encrypt(plaintext, output=output) + if output is None: + self._omac[2].update(ct) + else: + self._omac[2].update(output) + return ct + + def decrypt(self, ciphertext, output=None): + """Decrypt data with the key and the parameters set at initialization. + + A cipher object is stateful: once you have decrypted a message + you cannot decrypt (or encrypt) another message with the same + object. + + The data to decrypt can be broken up in two or + more pieces and `decrypt` can be called multiple times. + + That is, the statement: + + >>> c.decrypt(a) + c.decrypt(b) + + is equivalent to: + + >>> c.decrypt(a+b) + + This function does not remove any padding from the plaintext. + + :Parameters: + ciphertext : bytes/bytearray/memoryview + The piece of data to decrypt. + It can be of any length. + :Keywords: + output : bytearray/memoryview + The location where the plaintext must be written to. + If ``None``, the plaintext is returned. + :Return: + If ``output`` is ``None``, the plaintext as ``bytes``. + Otherwise, ``None``. + """ + + if "decrypt" not in self._next: + raise TypeError("decrypt() can only be called" + " after initialization or an update()") + self._next = ["decrypt", "verify"] + self._omac[2].update(ciphertext) + return self._cipher.decrypt(ciphertext, output=output) + + def digest(self): + """Compute the *binary* MAC tag. + + The caller invokes this function at the very end. + + This method returns the MAC that shall be sent to the receiver, + together with the ciphertext. + + :Return: the MAC, as a byte string. + """ + + if "digest" not in self._next: + raise TypeError("digest() cannot be called when decrypting" + " or validating a message") + self._next = ["digest"] + + if not self._mac_tag: + tag = b'\x00' * self.block_size + for i in range(3): + tag = strxor(tag, self._omac[i].digest()) + self._mac_tag = tag[:self._mac_len] + + return self._mac_tag + + def hexdigest(self): + """Compute the *printable* MAC tag. + + This method is like `digest`. + + :Return: the MAC, as a hexadecimal string. + """ + return "".join(["%02x" % bord(x) for x in self.digest()]) + + def verify(self, received_mac_tag): + """Validate the *binary* MAC tag. + + The caller invokes this function at the very end. + + This method checks if the decrypted message is indeed valid + (that is, if the key is correct) and it has not been + tampered with while in transit. + + :Parameters: + received_mac_tag : bytes/bytearray/memoryview + This is the *binary* MAC, as received from the sender. + :Raises MacMismatchError: + if the MAC does not match. The message has been tampered with + or the key is incorrect. + """ + + if "verify" not in self._next: + raise TypeError("verify() cannot be called" + " when encrypting a message") + self._next = ["verify"] + + if not self._mac_tag: + tag = b'\x00' * self.block_size + for i in range(3): + tag = strxor(tag, self._omac[i].digest()) + self._mac_tag = tag[:self._mac_len] + + secret = get_random_bytes(16) + + mac1 = BLAKE2s.new(digest_bits=160, key=secret, data=self._mac_tag) + mac2 = BLAKE2s.new(digest_bits=160, key=secret, data=received_mac_tag) + + if mac1.digest() != mac2.digest(): + raise ValueError("MAC check failed") + + def hexverify(self, hex_mac_tag): + """Validate the *printable* MAC tag. + + This method is like `verify`. + + :Parameters: + hex_mac_tag : string + This is the *printable* MAC, as received from the sender. + :Raises MacMismatchError: + if the MAC does not match. The message has been tampered with + or the key is incorrect. + """ + + self.verify(unhexlify(hex_mac_tag)) + + def encrypt_and_digest(self, plaintext, output=None): + """Perform encrypt() and digest() in one step. + + :Parameters: + plaintext : bytes/bytearray/memoryview + The piece of data to encrypt. + :Keywords: + output : bytearray/memoryview + The location where the ciphertext must be written to. + If ``None``, the ciphertext is returned. + :Return: + a tuple with two items: + + - the ciphertext, as ``bytes`` + - the MAC tag, as ``bytes`` + + The first item becomes ``None`` when the ``output`` parameter + specified a location for the result. + """ + + return self.encrypt(plaintext, output=output), self.digest() + + def decrypt_and_verify(self, ciphertext, received_mac_tag, output=None): + """Perform decrypt() and verify() in one step. + + :Parameters: + ciphertext : bytes/bytearray/memoryview + The piece of data to decrypt. + received_mac_tag : bytes/bytearray/memoryview + This is the *binary* MAC, as received from the sender. + :Keywords: + output : bytearray/memoryview + The location where the plaintext must be written to. + If ``None``, the plaintext is returned. + :Return: the plaintext as ``bytes`` or ``None`` when the ``output`` + parameter specified a location for the result. + :Raises MacMismatchError: + if the MAC does not match. The message has been tampered with + or the key is incorrect. + """ + + pt = self.decrypt(ciphertext, output=output) + self.verify(received_mac_tag) + return pt + + +def _create_eax_cipher(factory, **kwargs): + """Create a new block cipher, configured in EAX mode. + + :Parameters: + factory : module + A symmetric cipher module from `Cryptodome.Cipher` (like + `Cryptodome.Cipher.AES`). + + :Keywords: + key : bytes/bytearray/memoryview + The secret key to use in the symmetric cipher. + + nonce : bytes/bytearray/memoryview + A value that must never be reused for any other encryption. + There are no restrictions on its length, but it is recommended to use + at least 16 bytes. + + The nonce shall never repeat for two different messages encrypted with + the same key, but it does not need to be random. + + If not specified, a 16 byte long random string is used. + + mac_len : integer + Length of the MAC, in bytes. It must be no larger than the cipher + block bytes (which is the default). + """ + + try: + key = kwargs.pop("key") + nonce = kwargs.pop("nonce", None) + if nonce is None: + nonce = get_random_bytes(16) + mac_len = kwargs.pop("mac_len", factory.block_size) + except KeyError as e: + raise TypeError("Missing parameter: " + str(e)) + + return EaxMode(factory, key, nonce, mac_len, kwargs) diff --git a/venv/Lib/site-packages/Cryptodome/Cipher/_mode_eax.pyi b/venv/Lib/site-packages/Cryptodome/Cipher/_mode_eax.pyi new file mode 100644 index 0000000..cbfa467 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Cipher/_mode_eax.pyi @@ -0,0 +1,45 @@ +from types import ModuleType +from typing import Any, Union, Tuple, Dict, overload, Optional + +Buffer = Union[bytes, bytearray, memoryview] + +__all__ = ['EaxMode'] + +class EaxMode(object): + block_size: int + nonce: bytes + + def __init__(self, + factory: ModuleType, + key: Buffer, + nonce: Buffer, + mac_len: int, + cipher_params: Dict) -> None: ... + + def update(self, assoc_data: Buffer) -> EaxMode: ... + + @overload + def encrypt(self, plaintext: Buffer) -> bytes: ... + @overload + def encrypt(self, plaintext: Buffer, output: Union[bytearray, memoryview]) -> None: ... + @overload + def decrypt(self, plaintext: Buffer) -> bytes: ... + @overload + def decrypt(self, plaintext: Buffer, output: Union[bytearray, memoryview]) -> None: ... + + def digest(self) -> bytes: ... + def hexdigest(self) -> str: ... + def verify(self, received_mac_tag: Buffer) -> None: ... + def hexverify(self, hex_mac_tag: str) -> None: ... + + @overload + def encrypt_and_digest(self, + plaintext: Buffer) -> Tuple[bytes, bytes]: ... + @overload + def encrypt_and_digest(self, + plaintext: Buffer, + output: Buffer) -> Tuple[None, bytes]: ... + def decrypt_and_verify(self, + ciphertext: Buffer, + received_mac_tag: Buffer, + output: Optional[Union[bytearray, memoryview]] = ...) -> bytes: ... diff --git a/venv/Lib/site-packages/Cryptodome/Cipher/_mode_ecb.py b/venv/Lib/site-packages/Cryptodome/Cipher/_mode_ecb.py new file mode 100644 index 0000000..a01a16f --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Cipher/_mode_ecb.py @@ -0,0 +1,220 @@ +# -*- coding: utf-8 -*- +# +# Cipher/mode_ecb.py : ECB mode +# +# =================================================================== +# The contents of this file are dedicated to the public domain. To +# the extent that dedication to the public domain is not available, +# everyone is granted a worldwide, perpetual, royalty-free, +# non-exclusive license to exercise all rights associated with the +# contents of this file for any purpose whatsoever. +# No rights are reserved. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# =================================================================== + +""" +Electronic Code Book (ECB) mode. +""" + +__all__ = [ 'EcbMode' ] + +from Cryptodome.Util._raw_api import (load_pycryptodome_raw_lib, + VoidPointer, create_string_buffer, + get_raw_buffer, SmartPointer, + c_size_t, c_uint8_ptr, + is_writeable_buffer) + +raw_ecb_lib = load_pycryptodome_raw_lib("Cryptodome.Cipher._raw_ecb", """ + int ECB_start_operation(void *cipher, + void **pResult); + int ECB_encrypt(void *ecbState, + const uint8_t *in, + uint8_t *out, + size_t data_len); + int ECB_decrypt(void *ecbState, + const uint8_t *in, + uint8_t *out, + size_t data_len); + int ECB_stop_operation(void *state); + """ + ) + + +class EcbMode(object): + """*Electronic Code Book (ECB)*. + + This is the simplest encryption mode. Each of the plaintext blocks + is directly encrypted into a ciphertext block, independently of + any other block. + + This mode is dangerous because it exposes frequency of symbols + in your plaintext. Other modes (e.g. *CBC*) should be used instead. + + See `NIST SP800-38A`_ , Section 6.1. + + .. _`NIST SP800-38A` : http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf + + :undocumented: __init__ + """ + + def __init__(self, block_cipher): + """Create a new block cipher, configured in ECB mode. + + :Parameters: + block_cipher : C pointer + A smart pointer to the low-level block cipher instance. + """ + self.block_size = block_cipher.block_size + + self._state = VoidPointer() + result = raw_ecb_lib.ECB_start_operation(block_cipher.get(), + self._state.address_of()) + if result: + raise ValueError("Error %d while instantiating the ECB mode" + % result) + + # Ensure that object disposal of this Python object will (eventually) + # free the memory allocated by the raw library for the cipher + # mode + self._state = SmartPointer(self._state.get(), + raw_ecb_lib.ECB_stop_operation) + + # Memory allocated for the underlying block cipher is now owned + # by the cipher mode + block_cipher.release() + + def encrypt(self, plaintext, output=None): + """Encrypt data with the key set at initialization. + + The data to encrypt can be broken up in two or + more pieces and `encrypt` can be called multiple times. + + That is, the statement: + + >>> c.encrypt(a) + c.encrypt(b) + + is equivalent to: + + >>> c.encrypt(a+b) + + This function does not add any padding to the plaintext. + + :Parameters: + plaintext : bytes/bytearray/memoryview + The piece of data to encrypt. + The length must be multiple of the cipher block length. + :Keywords: + output : bytearray/memoryview + The location where the ciphertext must be written to. + If ``None``, the ciphertext is returned. + :Return: + If ``output`` is ``None``, the ciphertext is returned as ``bytes``. + Otherwise, ``None``. + """ + + if output is None: + ciphertext = create_string_buffer(len(plaintext)) + else: + ciphertext = output + + if not is_writeable_buffer(output): + raise TypeError("output must be a bytearray or a writeable memoryview") + + if len(plaintext) != len(output): + raise ValueError("output must have the same length as the input" + " (%d bytes)" % len(plaintext)) + + result = raw_ecb_lib.ECB_encrypt(self._state.get(), + c_uint8_ptr(plaintext), + c_uint8_ptr(ciphertext), + c_size_t(len(plaintext))) + if result: + if result == 3: + raise ValueError("Data must be aligned to block boundary in ECB mode") + raise ValueError("Error %d while encrypting in ECB mode" % result) + + if output is None: + return get_raw_buffer(ciphertext) + else: + return None + + def decrypt(self, ciphertext, output=None): + """Decrypt data with the key set at initialization. + + The data to decrypt can be broken up in two or + more pieces and `decrypt` can be called multiple times. + + That is, the statement: + + >>> c.decrypt(a) + c.decrypt(b) + + is equivalent to: + + >>> c.decrypt(a+b) + + This function does not remove any padding from the plaintext. + + :Parameters: + ciphertext : bytes/bytearray/memoryview + The piece of data to decrypt. + The length must be multiple of the cipher block length. + :Keywords: + output : bytearray/memoryview + The location where the plaintext must be written to. + If ``None``, the plaintext is returned. + :Return: + If ``output`` is ``None``, the plaintext is returned as ``bytes``. + Otherwise, ``None``. + """ + + if output is None: + plaintext = create_string_buffer(len(ciphertext)) + else: + plaintext = output + + if not is_writeable_buffer(output): + raise TypeError("output must be a bytearray or a writeable memoryview") + + if len(ciphertext) != len(output): + raise ValueError("output must have the same length as the input" + " (%d bytes)" % len(plaintext)) + + result = raw_ecb_lib.ECB_decrypt(self._state.get(), + c_uint8_ptr(ciphertext), + c_uint8_ptr(plaintext), + c_size_t(len(ciphertext))) + if result: + if result == 3: + raise ValueError("Data must be aligned to block boundary in ECB mode") + raise ValueError("Error %d while decrypting in ECB mode" % result) + + if output is None: + return get_raw_buffer(plaintext) + else: + return None + + +def _create_ecb_cipher(factory, **kwargs): + """Instantiate a cipher object that performs ECB encryption/decryption. + + :Parameters: + factory : module + The underlying block cipher, a module from ``Cryptodome.Cipher``. + + All keywords are passed to the underlying block cipher. + See the relevant documentation for details (at least ``key`` will need + to be present""" + + cipher_state = factory._create_base_cipher(kwargs) + cipher_state.block_size = factory.block_size + if kwargs: + raise TypeError("Unknown parameters for ECB: %s" % str(kwargs)) + return EcbMode(cipher_state) diff --git a/venv/Lib/site-packages/Cryptodome/Cipher/_mode_ecb.pyi b/venv/Lib/site-packages/Cryptodome/Cipher/_mode_ecb.pyi new file mode 100644 index 0000000..936195f --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Cipher/_mode_ecb.pyi @@ -0,0 +1,19 @@ +from typing import Union, overload + +from Cryptodome.Util._raw_api import SmartPointer + +Buffer = Union[bytes, bytearray, memoryview] + +__all__ = [ 'EcbMode' ] + +class EcbMode(object): + def __init__(self, block_cipher: SmartPointer) -> None: ... + @overload + def encrypt(self, plaintext: Buffer) -> bytes: ... + @overload + def encrypt(self, plaintext: Buffer, output: Union[bytearray, memoryview]) -> None: ... + @overload + def decrypt(self, plaintext: Buffer) -> bytes: ... + @overload + def decrypt(self, plaintext: Buffer, output: Union[bytearray, memoryview]) -> None: ... + diff --git a/venv/Lib/site-packages/Cryptodome/Cipher/_mode_gcm.py b/venv/Lib/site-packages/Cryptodome/Cipher/_mode_gcm.py new file mode 100644 index 0000000..9914400 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Cipher/_mode_gcm.py @@ -0,0 +1,620 @@ +# =================================================================== +# +# Copyright (c) 2014, Legrandin +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# =================================================================== + +""" +Galois/Counter Mode (GCM). +""" + +__all__ = ['GcmMode'] + +from binascii import unhexlify + +from Cryptodome.Util.py3compat import bord, _copy_bytes + +from Cryptodome.Util._raw_api import is_buffer + +from Cryptodome.Util.number import long_to_bytes, bytes_to_long +from Cryptodome.Hash import BLAKE2s +from Cryptodome.Random import get_random_bytes + +from Cryptodome.Util._raw_api import (load_pycryptodome_raw_lib, VoidPointer, + create_string_buffer, get_raw_buffer, + SmartPointer, c_size_t, c_uint8_ptr) + +from Cryptodome.Util import _cpu_features + + +# C API by module implementing GHASH +_ghash_api_template = """ + int ghash_%imp%(uint8_t y_out[16], + const uint8_t block_data[], + size_t len, + const uint8_t y_in[16], + const void *exp_key); + int ghash_expand_%imp%(const uint8_t h[16], + void **ghash_tables); + int ghash_destroy_%imp%(void *ghash_tables); +""" + +def _build_impl(lib, postfix): + from collections import namedtuple + + funcs = ( "ghash", "ghash_expand", "ghash_destroy" ) + GHASH_Imp = namedtuple('_GHash_Imp', funcs) + try: + imp_funcs = [ getattr(lib, x + "_" + postfix) for x in funcs ] + except AttributeError: # Make sphinx stop complaining with its mocklib + imp_funcs = [ None ] * 3 + params = dict(zip(funcs, imp_funcs)) + return GHASH_Imp(**params) + + +def _get_ghash_portable(): + api = _ghash_api_template.replace("%imp%", "portable") + lib = load_pycryptodome_raw_lib("Cryptodome.Hash._ghash_portable", api) + result = _build_impl(lib, "portable") + return result +_ghash_portable = _get_ghash_portable() + + +def _get_ghash_clmul(): + """Return None if CLMUL implementation is not available""" + + if not _cpu_features.have_clmul(): + return None + try: + api = _ghash_api_template.replace("%imp%", "clmul") + lib = load_pycryptodome_raw_lib("Cryptodome.Hash._ghash_clmul", api) + result = _build_impl(lib, "clmul") + except OSError: + result = None + return result +_ghash_clmul = _get_ghash_clmul() + + +class _GHASH(object): + """GHASH function defined in NIST SP 800-38D, Algorithm 2. + + If X_1, X_2, .. X_m are the blocks of input data, the function + computes: + + X_1*H^{m} + X_2*H^{m-1} + ... + X_m*H + + in the Galois field GF(2^256) using the reducing polynomial + (x^128 + x^7 + x^2 + x + 1). + """ + + def __init__(self, subkey, ghash_c): + assert len(subkey) == 16 + + self.ghash_c = ghash_c + + self._exp_key = VoidPointer() + result = ghash_c.ghash_expand(c_uint8_ptr(subkey), + self._exp_key.address_of()) + if result: + raise ValueError("Error %d while expanding the GHASH key" % result) + + self._exp_key = SmartPointer(self._exp_key.get(), + ghash_c.ghash_destroy) + + # create_string_buffer always returns a string of zeroes + self._last_y = create_string_buffer(16) + + def update(self, block_data): + assert len(block_data) % 16 == 0 + + result = self.ghash_c.ghash(self._last_y, + c_uint8_ptr(block_data), + c_size_t(len(block_data)), + self._last_y, + self._exp_key.get()) + if result: + raise ValueError("Error %d while updating GHASH" % result) + + return self + + def digest(self): + return get_raw_buffer(self._last_y) + + +def enum(**enums): + return type('Enum', (), enums) + + +MacStatus = enum(PROCESSING_AUTH_DATA=1, PROCESSING_CIPHERTEXT=2) + + +class GcmMode(object): + """Galois Counter Mode (GCM). + + This is an Authenticated Encryption with Associated Data (`AEAD`_) mode. + It provides both confidentiality and authenticity. + + The header of the message may be left in the clear, if needed, and it will + still be subject to authentication. The decryption step tells the receiver + if the message comes from a source that really knowns the secret key. + Additionally, decryption detects if any part of the message - including the + header - has been modified or corrupted. + + This mode requires a *nonce*. + + This mode is only available for ciphers that operate on 128 bits blocks + (e.g. AES but not TDES). + + See `NIST SP800-38D`_. + + .. _`NIST SP800-38D`: http://csrc.nist.gov/publications/nistpubs/800-38D/SP-800-38D.pdf + .. _AEAD: http://blog.cryptographyengineering.com/2012/05/how-to-choose-authenticated-encryption.html + + :undocumented: __init__ + """ + + def __init__(self, factory, key, nonce, mac_len, cipher_params, ghash_c): + + self.block_size = factory.block_size + if self.block_size != 16: + raise ValueError("GCM mode is only available for ciphers" + " that operate on 128 bits blocks") + + if len(nonce) == 0: + raise ValueError("Nonce cannot be empty") + + if not is_buffer(nonce): + raise TypeError("Nonce must be bytes, bytearray or memoryview") + + # See NIST SP 800 38D, 5.2.1.1 + if len(nonce) > 2**64 - 1: + raise ValueError("Nonce exceeds maximum length") + + + self.nonce = _copy_bytes(None, None, nonce) + """Nonce""" + + self._factory = factory + self._key = _copy_bytes(None, None, key) + self._tag = None # Cache for MAC tag + + self._mac_len = mac_len + if not (4 <= mac_len <= 16): + raise ValueError("Parameter 'mac_len' must be in the range 4..16") + + # Allowed transitions after initialization + self._next = ["update", "encrypt", "decrypt", + "digest", "verify"] + + self._no_more_assoc_data = False + + # Length of associated data + self._auth_len = 0 + + # Length of the ciphertext or plaintext + self._msg_len = 0 + + # Step 1 in SP800-38D, Algorithm 4 (encryption) - Compute H + # See also Algorithm 5 (decryption) + hash_subkey = factory.new(key, + self._factory.MODE_ECB, + **cipher_params + ).encrypt(b'\x00' * 16) + + # Step 2 - Compute J0 + if len(self.nonce) == 12: + j0 = self.nonce + b"\x00\x00\x00\x01" + else: + fill = (16 - (len(self.nonce) % 16)) % 16 + 8 + ghash_in = (self.nonce + + b'\x00' * fill + + long_to_bytes(8 * len(self.nonce), 8)) + j0 = _GHASH(hash_subkey, ghash_c).update(ghash_in).digest() + + # Step 3 - Prepare GCTR cipher for encryption/decryption + nonce_ctr = j0[:12] + iv_ctr = (bytes_to_long(j0) + 1) & 0xFFFFFFFF + self._cipher = factory.new(key, + self._factory.MODE_CTR, + initial_value=iv_ctr, + nonce=nonce_ctr, + **cipher_params) + + # Step 5 - Bootstrat GHASH + self._signer = _GHASH(hash_subkey, ghash_c) + + # Step 6 - Prepare GCTR cipher for GMAC + self._tag_cipher = factory.new(key, + self._factory.MODE_CTR, + initial_value=j0, + nonce=b"", + **cipher_params) + + # Cache for data to authenticate + self._cache = b"" + + self._status = MacStatus.PROCESSING_AUTH_DATA + + def update(self, assoc_data): + """Protect associated data + + If there is any associated data, the caller has to invoke + this function one or more times, before using + ``decrypt`` or ``encrypt``. + + By *associated data* it is meant any data (e.g. packet headers) that + will not be encrypted and will be transmitted in the clear. + However, the receiver is still able to detect any modification to it. + In GCM, the *associated data* is also called + *additional authenticated data* (AAD). + + If there is no associated data, this method must not be called. + + The caller may split associated data in segments of any size, and + invoke this method multiple times, each time with the next segment. + + :Parameters: + assoc_data : bytes/bytearray/memoryview + A piece of associated data. There are no restrictions on its size. + """ + + if "update" not in self._next: + raise TypeError("update() can only be called" + " immediately after initialization") + + self._next = ["update", "encrypt", "decrypt", + "digest", "verify"] + + self._update(assoc_data) + self._auth_len += len(assoc_data) + + # See NIST SP 800 38D, 5.2.1.1 + if self._auth_len > 2**64 - 1: + raise ValueError("Additional Authenticated Data exceeds maximum length") + + return self + + def _update(self, data): + assert(len(self._cache) < 16) + + if len(self._cache) > 0: + filler = min(16 - len(self._cache), len(data)) + self._cache += _copy_bytes(None, filler, data) + data = data[filler:] + + if len(self._cache) < 16: + return + + # The cache is exactly one block + self._signer.update(self._cache) + self._cache = b"" + + update_len = len(data) // 16 * 16 + self._cache = _copy_bytes(update_len, None, data) + if update_len > 0: + self._signer.update(data[:update_len]) + + def _pad_cache_and_update(self): + assert(len(self._cache) < 16) + + # The authenticated data A is concatenated to the minimum + # number of zero bytes (possibly none) such that the + # - ciphertext C is aligned to the 16 byte boundary. + # See step 5 in section 7.1 + # - ciphertext C is aligned to the 16 byte boundary. + # See step 6 in section 7.2 + len_cache = len(self._cache) + if len_cache > 0: + self._update(b'\x00' * (16 - len_cache)) + + def encrypt(self, plaintext, output=None): + """Encrypt data with the key and the parameters set at initialization. + + A cipher object is stateful: once you have encrypted a message + you cannot encrypt (or decrypt) another message using the same + object. + + The data to encrypt can be broken up in two or + more pieces and `encrypt` can be called multiple times. + + That is, the statement: + + >>> c.encrypt(a) + c.encrypt(b) + + is equivalent to: + + >>> c.encrypt(a+b) + + This function does not add any padding to the plaintext. + + :Parameters: + plaintext : bytes/bytearray/memoryview + The piece of data to encrypt. + It can be of any length. + :Keywords: + output : bytearray/memoryview + The location where the ciphertext must be written to. + If ``None``, the ciphertext is returned. + :Return: + If ``output`` is ``None``, the ciphertext as ``bytes``. + Otherwise, ``None``. + """ + + if "encrypt" not in self._next: + raise TypeError("encrypt() can only be called after" + " initialization or an update()") + self._next = ["encrypt", "digest"] + + ciphertext = self._cipher.encrypt(plaintext, output=output) + + if self._status == MacStatus.PROCESSING_AUTH_DATA: + self._pad_cache_and_update() + self._status = MacStatus.PROCESSING_CIPHERTEXT + + self._update(ciphertext if output is None else output) + self._msg_len += len(plaintext) + + # See NIST SP 800 38D, 5.2.1.1 + if self._msg_len > 2**39 - 256: + raise ValueError("Plaintext exceeds maximum length") + + return ciphertext + + def decrypt(self, ciphertext, output=None): + """Decrypt data with the key and the parameters set at initialization. + + A cipher object is stateful: once you have decrypted a message + you cannot decrypt (or encrypt) another message with the same + object. + + The data to decrypt can be broken up in two or + more pieces and `decrypt` can be called multiple times. + + That is, the statement: + + >>> c.decrypt(a) + c.decrypt(b) + + is equivalent to: + + >>> c.decrypt(a+b) + + This function does not remove any padding from the plaintext. + + :Parameters: + ciphertext : bytes/bytearray/memoryview + The piece of data to decrypt. + It can be of any length. + :Keywords: + output : bytearray/memoryview + The location where the plaintext must be written to. + If ``None``, the plaintext is returned. + :Return: + If ``output`` is ``None``, the plaintext as ``bytes``. + Otherwise, ``None``. + """ + + if "decrypt" not in self._next: + raise TypeError("decrypt() can only be called" + " after initialization or an update()") + self._next = ["decrypt", "verify"] + + if self._status == MacStatus.PROCESSING_AUTH_DATA: + self._pad_cache_and_update() + self._status = MacStatus.PROCESSING_CIPHERTEXT + + self._update(ciphertext) + self._msg_len += len(ciphertext) + + return self._cipher.decrypt(ciphertext, output=output) + + def digest(self): + """Compute the *binary* MAC tag in an AEAD mode. + + The caller invokes this function at the very end. + + This method returns the MAC that shall be sent to the receiver, + together with the ciphertext. + + :Return: the MAC, as a byte string. + """ + + if "digest" not in self._next: + raise TypeError("digest() cannot be called when decrypting" + " or validating a message") + self._next = ["digest"] + + return self._compute_mac() + + def _compute_mac(self): + """Compute MAC without any FSM checks.""" + + if self._tag: + return self._tag + + # Step 5 in NIST SP 800-38D, Algorithm 4 - Compute S + self._pad_cache_and_update() + self._update(long_to_bytes(8 * self._auth_len, 8)) + self._update(long_to_bytes(8 * self._msg_len, 8)) + s_tag = self._signer.digest() + + # Step 6 - Compute T + self._tag = self._tag_cipher.encrypt(s_tag)[:self._mac_len] + + return self._tag + + def hexdigest(self): + """Compute the *printable* MAC tag. + + This method is like `digest`. + + :Return: the MAC, as a hexadecimal string. + """ + return "".join(["%02x" % bord(x) for x in self.digest()]) + + def verify(self, received_mac_tag): + """Validate the *binary* MAC tag. + + The caller invokes this function at the very end. + + This method checks if the decrypted message is indeed valid + (that is, if the key is correct) and it has not been + tampered with while in transit. + + :Parameters: + received_mac_tag : bytes/bytearray/memoryview + This is the *binary* MAC, as received from the sender. + :Raises ValueError: + if the MAC does not match. The message has been tampered with + or the key is incorrect. + """ + + if "verify" not in self._next: + raise TypeError("verify() cannot be called" + " when encrypting a message") + self._next = ["verify"] + + secret = get_random_bytes(16) + + mac1 = BLAKE2s.new(digest_bits=160, key=secret, + data=self._compute_mac()) + mac2 = BLAKE2s.new(digest_bits=160, key=secret, + data=received_mac_tag) + + if mac1.digest() != mac2.digest(): + raise ValueError("MAC check failed") + + def hexverify(self, hex_mac_tag): + """Validate the *printable* MAC tag. + + This method is like `verify`. + + :Parameters: + hex_mac_tag : string + This is the *printable* MAC, as received from the sender. + :Raises ValueError: + if the MAC does not match. The message has been tampered with + or the key is incorrect. + """ + + self.verify(unhexlify(hex_mac_tag)) + + def encrypt_and_digest(self, plaintext, output=None): + """Perform encrypt() and digest() in one step. + + :Parameters: + plaintext : bytes/bytearray/memoryview + The piece of data to encrypt. + :Keywords: + output : bytearray/memoryview + The location where the ciphertext must be written to. + If ``None``, the ciphertext is returned. + :Return: + a tuple with two items: + + - the ciphertext, as ``bytes`` + - the MAC tag, as ``bytes`` + + The first item becomes ``None`` when the ``output`` parameter + specified a location for the result. + """ + + return self.encrypt(plaintext, output=output), self.digest() + + def decrypt_and_verify(self, ciphertext, received_mac_tag, output=None): + """Perform decrypt() and verify() in one step. + + :Parameters: + ciphertext : bytes/bytearray/memoryview + The piece of data to decrypt. + received_mac_tag : byte string + This is the *binary* MAC, as received from the sender. + :Keywords: + output : bytearray/memoryview + The location where the plaintext must be written to. + If ``None``, the plaintext is returned. + :Return: the plaintext as ``bytes`` or ``None`` when the ``output`` + parameter specified a location for the result. + :Raises ValueError: + if the MAC does not match. The message has been tampered with + or the key is incorrect. + """ + + plaintext = self.decrypt(ciphertext, output=output) + self.verify(received_mac_tag) + return plaintext + + +def _create_gcm_cipher(factory, **kwargs): + """Create a new block cipher, configured in Galois Counter Mode (GCM). + + :Parameters: + factory : module + A block cipher module, taken from `Cryptodome.Cipher`. + The cipher must have block length of 16 bytes. + GCM has been only defined for `Cryptodome.Cipher.AES`. + + :Keywords: + key : bytes/bytearray/memoryview + The secret key to use in the symmetric cipher. + It must be 16 (e.g. *AES-128*), 24 (e.g. *AES-192*) + or 32 (e.g. *AES-256*) bytes long. + + nonce : bytes/bytearray/memoryview + A value that must never be reused for any other encryption. + + There are no restrictions on its length, + but it is recommended to use at least 16 bytes. + + The nonce shall never repeat for two + different messages encrypted with the same key, + but it does not need to be random. + + If not provided, a 16 byte nonce will be randomly created. + + mac_len : integer + Length of the MAC, in bytes. + It must be no larger than 16 bytes (which is the default). + """ + + try: + key = kwargs.pop("key") + except KeyError as e: + raise TypeError("Missing parameter:" + str(e)) + + nonce = kwargs.pop("nonce", None) + if nonce is None: + nonce = get_random_bytes(16) + mac_len = kwargs.pop("mac_len", 16) + + # Not documented - only used for testing + use_clmul = kwargs.pop("use_clmul", True) + if use_clmul and _ghash_clmul: + ghash_c = _ghash_clmul + else: + ghash_c = _ghash_portable + + return GcmMode(factory, key, nonce, mac_len, kwargs, ghash_c) diff --git a/venv/Lib/site-packages/Cryptodome/Cipher/_mode_gcm.pyi b/venv/Lib/site-packages/Cryptodome/Cipher/_mode_gcm.pyi new file mode 100644 index 0000000..8912955 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Cipher/_mode_gcm.pyi @@ -0,0 +1,45 @@ +from types import ModuleType +from typing import Union, Tuple, Dict, overload, Optional + +__all__ = ['GcmMode'] + +Buffer = Union[bytes, bytearray, memoryview] + +class GcmMode(object): + block_size: int + nonce: Buffer + + def __init__(self, + factory: ModuleType, + key: Buffer, + nonce: Buffer, + mac_len: int, + cipher_params: Dict) -> None: ... + + def update(self, assoc_data: Buffer) -> GcmMode: ... + + @overload + def encrypt(self, plaintext: Buffer) -> bytes: ... + @overload + def encrypt(self, plaintext: Buffer, output: Union[bytearray, memoryview]) -> None: ... + @overload + def decrypt(self, plaintext: Buffer) -> bytes: ... + @overload + def decrypt(self, plaintext: Buffer, output: Union[bytearray, memoryview]) -> None: ... + + def digest(self) -> bytes: ... + def hexdigest(self) -> str: ... + def verify(self, received_mac_tag: Buffer) -> None: ... + def hexverify(self, hex_mac_tag: str) -> None: ... + + @overload + def encrypt_and_digest(self, + plaintext: Buffer) -> Tuple[bytes, bytes]: ... + @overload + def encrypt_and_digest(self, + plaintext: Buffer, + output: Buffer) -> Tuple[None, bytes]: ... + def decrypt_and_verify(self, + ciphertext: Buffer, + received_mac_tag: Buffer, + output: Optional[Union[bytearray, memoryview]] = ...) -> bytes: ... diff --git a/venv/Lib/site-packages/Cryptodome/Cipher/_mode_kw.py b/venv/Lib/site-packages/Cryptodome/Cipher/_mode_kw.py new file mode 100644 index 0000000..41c09ef --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Cipher/_mode_kw.py @@ -0,0 +1,158 @@ +import struct +from collections import deque + +from types import ModuleType +from typing import Union + +from Cryptodome.Util.strxor import strxor + + +def W(cipher: ModuleType, + plaintext: Union[bytes, bytearray]) -> bytes: + + S = [plaintext[i:i+8] for i in range(0, len(plaintext), 8)] + n = len(S) + s = 6 * (n - 1) + A = S[0] + R = deque(S[1:]) + + for t in range(1, s + 1): + t_64 = struct.pack('>Q', t) + ct = cipher.encrypt(A + R.popleft()) + A = strxor(ct[:8], t_64) + R.append(ct[8:]) + + return A + b''.join(R) + + +def W_inverse(cipher: ModuleType, + ciphertext: Union[bytes, bytearray]) -> bytes: + + C = [ciphertext[i:i+8] for i in range(0, len(ciphertext), 8)] + n = len(C) + s = 6 * (n - 1) + A = C[0] + R = deque(C[1:]) + + for t in range(s, 0, -1): + t_64 = struct.pack('>Q', t) + pt = cipher.decrypt(strxor(A, t_64) + R.pop()) + A = pt[:8] + R.appendleft(pt[8:]) + + return A + b''.join(R) + + +class KWMode(object): + """Key Wrap (KW) mode. + + This is a deterministic Authenticated Encryption (AE) mode + for protecting cryptographic keys. See `NIST SP800-38F`_. + + It provides both confidentiality and authenticity, and it designed + so that any bit of the ciphertext depends on all bits of the plaintext. + + This mode is only available for ciphers that operate on 128 bits blocks + (e.g., AES). + + .. _`NIST SP800-38F`: http://csrc.nist.gov/publications/nistpubs/800-38F/SP-800-38F.pdf + + :undocumented: __init__ + """ + + def __init__(self, + factory: ModuleType, + key: Union[bytes, bytearray]): + + self.block_size = factory.block_size + if self.block_size != 16: + raise ValueError("Key Wrap mode is only available for ciphers" + " that operate on 128 bits blocks") + + self._factory = factory + self._cipher = factory.new(key, factory.MODE_ECB) + self._done = False + + def seal(self, plaintext: Union[bytes, bytearray]) -> bytes: + """Encrypt and authenticate (wrap) a cryptographic key. + + Args: + plaintext: + The cryptographic key to wrap. + It must be at least 16 bytes long, and its length + must be a multiple of 8. + + Returns: + The wrapped key. + """ + + if self._done: + raise ValueError("The cipher cannot be used more than once") + + if len(plaintext) % 8: + raise ValueError("The plaintext must have length multiple of 8 bytes") + + if len(plaintext) < 16: + raise ValueError("The plaintext must be at least 16 bytes long") + + if len(plaintext) >= 2**32: + raise ValueError("The plaintext is too long") + + res = W(self._cipher, b'\xA6\xA6\xA6\xA6\xA6\xA6\xA6\xA6' + plaintext) + self._done = True + return res + + def unseal(self, ciphertext: Union[bytes, bytearray]) -> bytes: + """Decrypt and authenticate (unwrap) a cryptographic key. + + Args: + ciphertext: + The cryptographic key to unwrap. + It must be at least 24 bytes long, and its length + must be a multiple of 8. + + Returns: + The original key. + + Raises: ValueError + If the ciphertext or the key are not valid. + """ + + if self._done: + raise ValueError("The cipher cannot be used more than once") + + if len(ciphertext) % 8: + raise ValueError("The ciphertext must have length multiple of 8 bytes") + + if len(ciphertext) < 24: + raise ValueError("The ciphertext must be at least 24 bytes long") + + pt = W_inverse(self._cipher, ciphertext) + + if pt[:8] != b'\xA6\xA6\xA6\xA6\xA6\xA6\xA6\xA6': + raise ValueError("Incorrect integrity check value") + self._done = True + + return pt[8:] + + +def _create_kw_cipher(factory: ModuleType, + **kwargs: Union[bytes, bytearray]) -> KWMode: + """Create a new block cipher in Key Wrap mode. + + Args: + factory: + A block cipher module, taken from `Cryptodome.Cipher`. + The cipher must have block length of 16 bytes, such as AES. + + Keywords: + key: + The secret key to use to seal or unseal. + """ + + try: + key = kwargs["key"] + except KeyError as e: + raise TypeError("Missing parameter:" + str(e)) + + return KWMode(factory, key) diff --git a/venv/Lib/site-packages/Cryptodome/Cipher/_mode_kwp.py b/venv/Lib/site-packages/Cryptodome/Cipher/_mode_kwp.py new file mode 100644 index 0000000..0868443 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Cipher/_mode_kwp.py @@ -0,0 +1,135 @@ +import struct + +from types import ModuleType +from typing import Union + +from ._mode_kw import W, W_inverse + + +class KWPMode(object): + """Key Wrap with Padding (KWP) mode. + + This is a deterministic Authenticated Encryption (AE) mode + for protecting cryptographic keys. See `NIST SP800-38F`_. + + It provides both confidentiality and authenticity, and it designed + so that any bit of the ciphertext depends on all bits of the plaintext. + + This mode is only available for ciphers that operate on 128 bits blocks + (e.g., AES). + + .. _`NIST SP800-38F`: http://csrc.nist.gov/publications/nistpubs/800-38F/SP-800-38F.pdf + + :undocumented: __init__ + """ + + def __init__(self, + factory: ModuleType, + key: Union[bytes, bytearray]): + + self.block_size = factory.block_size + if self.block_size != 16: + raise ValueError("Key Wrap with Padding mode is only available for ciphers" + " that operate on 128 bits blocks") + + self._factory = factory + self._cipher = factory.new(key, factory.MODE_ECB) + self._done = False + + def seal(self, plaintext: Union[bytes, bytearray]) -> bytes: + """Encrypt and authenticate (wrap) a cryptographic key. + + Args: + plaintext: + The cryptographic key to wrap. + + Returns: + The wrapped key. + """ + + if self._done: + raise ValueError("The cipher cannot be used more than once") + + if len(plaintext) == 0: + raise ValueError("The plaintext must be at least 1 byte") + + if len(plaintext) >= 2 ** 32: + raise ValueError("The plaintext is too long") + + padlen = (8 - len(plaintext)) % 8 + padded = plaintext + b'\x00' * padlen + + AIV = b'\xA6\x59\x59\xA6' + struct.pack('>I', len(plaintext)) + + if len(padded) == 8: + res = self._cipher.encrypt(AIV + padded) + else: + res = W(self._cipher, AIV + padded) + + return res + + def unseal(self, ciphertext: Union[bytes, bytearray]) -> bytes: + """Decrypt and authenticate (unwrap) a cryptographic key. + + Args: + ciphertext: + The cryptographic key to unwrap. + It must be at least 16 bytes long, and its length + must be a multiple of 8. + + Returns: + The original key. + + Raises: ValueError + If the ciphertext or the key are not valid. + """ + + if self._done: + raise ValueError("The cipher cannot be used more than once") + + if len(ciphertext) % 8: + raise ValueError("The ciphertext must have length multiple of 8 bytes") + + if len(ciphertext) < 16: + raise ValueError("The ciphertext must be at least 24 bytes long") + + if len(ciphertext) == 16: + S = self._cipher.decrypt(ciphertext) + else: + S = W_inverse(self._cipher, ciphertext) + + if S[:4] != b'\xA6\x59\x59\xA6': + raise ValueError("Incorrect decryption") + + Plen = struct.unpack('>I', S[4:8])[0] + + padlen = len(S) - 8 - Plen + if padlen < 0 or padlen > 7: + raise ValueError("Incorrect decryption") + + if S[len(S) - padlen:] != b'\x00' * padlen: + raise ValueError("Incorrect decryption") + + return S[8:len(S) - padlen] + + +def _create_kwp_cipher(factory: ModuleType, + **kwargs: Union[bytes, bytearray]) -> KWPMode: + """Create a new block cipher in Key Wrap with Padding mode. + + Args: + factory: + A block cipher module, taken from `Cryptodome.Cipher`. + The cipher must have block length of 16 bytes, such as AES. + + Keywords: + key: + The secret key to use to seal or unseal. + """ + + try: + key = kwargs["key"] + except KeyError as e: + raise TypeError("Missing parameter:" + str(e)) + + return KWPMode(factory, key) diff --git a/venv/Lib/site-packages/Cryptodome/Cipher/_mode_ocb.py b/venv/Lib/site-packages/Cryptodome/Cipher/_mode_ocb.py new file mode 100644 index 0000000..1295e61 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Cipher/_mode_ocb.py @@ -0,0 +1,532 @@ +# =================================================================== +# +# Copyright (c) 2014, Legrandin +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# =================================================================== + +""" +Offset Codebook (OCB) mode. + +OCB is Authenticated Encryption with Associated Data (AEAD) cipher mode +designed by Prof. Phillip Rogaway and specified in `RFC7253`_. + +The algorithm provides both authenticity and privacy, it is very efficient, +it uses only one key and it can be used in online mode (so that encryption +or decryption can start before the end of the message is available). + +This module implements the third and last variant of OCB (OCB3) and it only +works in combination with a 128-bit block symmetric cipher, like AES. + +OCB is patented in US but `free licenses`_ exist for software implementations +meant for non-military purposes. + +Example: + >>> from Cryptodome.Cipher import AES + >>> from Cryptodome.Random import get_random_bytes + >>> + >>> key = get_random_bytes(32) + >>> cipher = AES.new(key, AES.MODE_OCB) + >>> plaintext = b"Attack at dawn" + >>> ciphertext, mac = cipher.encrypt_and_digest(plaintext) + >>> # Deliver cipher.nonce, ciphertext and mac + ... + >>> cipher = AES.new(key, AES.MODE_OCB, nonce=nonce) + >>> try: + >>> plaintext = cipher.decrypt_and_verify(ciphertext, mac) + >>> except ValueError: + >>> print "Invalid message" + >>> else: + >>> print plaintext + +:undocumented: __package__ + +.. _RFC7253: http://www.rfc-editor.org/info/rfc7253 +.. _free licenses: http://web.cs.ucdavis.edu/~rogaway/ocb/license.htm +""" + +import struct +from binascii import unhexlify + +from Cryptodome.Util.py3compat import bord, _copy_bytes, bchr +from Cryptodome.Util.number import long_to_bytes, bytes_to_long +from Cryptodome.Util.strxor import strxor + +from Cryptodome.Hash import BLAKE2s +from Cryptodome.Random import get_random_bytes + +from Cryptodome.Util._raw_api import (load_pycryptodome_raw_lib, VoidPointer, + create_string_buffer, get_raw_buffer, + SmartPointer, c_size_t, c_uint8_ptr, + is_buffer) + +_raw_ocb_lib = load_pycryptodome_raw_lib("Cryptodome.Cipher._raw_ocb", """ + int OCB_start_operation(void *cipher, + const uint8_t *offset_0, + size_t offset_0_len, + void **pState); + int OCB_encrypt(void *state, + const uint8_t *in, + uint8_t *out, + size_t data_len); + int OCB_decrypt(void *state, + const uint8_t *in, + uint8_t *out, + size_t data_len); + int OCB_update(void *state, + const uint8_t *in, + size_t data_len); + int OCB_digest(void *state, + uint8_t *tag, + size_t tag_len); + int OCB_stop_operation(void *state); + """) + + +class OcbMode(object): + """Offset Codebook (OCB) mode. + + :undocumented: __init__ + """ + + def __init__(self, factory, nonce, mac_len, cipher_params): + + if factory.block_size != 16: + raise ValueError("OCB mode is only available for ciphers" + " that operate on 128 bits blocks") + + self.block_size = 16 + """The block size of the underlying cipher, in bytes.""" + + self.nonce = _copy_bytes(None, None, nonce) + """Nonce used for this session.""" + if len(nonce) not in range(1, 16): + raise ValueError("Nonce must be at most 15 bytes long") + if not is_buffer(nonce): + raise TypeError("Nonce must be bytes, bytearray or memoryview") + + self._mac_len = mac_len + if not 8 <= mac_len <= 16: + raise ValueError("MAC tag must be between 8 and 16 bytes long") + + # Cache for MAC tag + self._mac_tag = None + + # Cache for unaligned associated data + self._cache_A = b"" + + # Cache for unaligned ciphertext/plaintext + self._cache_P = b"" + + # Allowed transitions after initialization + self._next = ["update", "encrypt", "decrypt", + "digest", "verify"] + + # Compute Offset_0 + params_without_key = dict(cipher_params) + key = params_without_key.pop("key") + + taglen_mod128 = (self._mac_len * 8) % 128 + if len(self.nonce) < 15: + nonce = bchr(taglen_mod128 << 1) +\ + b'\x00' * (14 - len(nonce)) +\ + b'\x01' +\ + self.nonce + else: + nonce = bchr((taglen_mod128 << 1) | 0x01) +\ + self.nonce + + bottom_bits = bord(nonce[15]) & 0x3F # 6 bits, 0..63 + top_bits = bord(nonce[15]) & 0xC0 # 2 bits + + ktop_cipher = factory.new(key, + factory.MODE_ECB, + **params_without_key) + ktop = ktop_cipher.encrypt(struct.pack('15sB', + nonce[:15], + top_bits)) + + stretch = ktop + strxor(ktop[:8], ktop[1:9]) # 192 bits + offset_0 = long_to_bytes(bytes_to_long(stretch) >> + (64 - bottom_bits), 24)[8:] + + # Create low-level cipher instance + raw_cipher = factory._create_base_cipher(cipher_params) + if cipher_params: + raise TypeError("Unknown keywords: " + str(cipher_params)) + + self._state = VoidPointer() + result = _raw_ocb_lib.OCB_start_operation(raw_cipher.get(), + offset_0, + c_size_t(len(offset_0)), + self._state.address_of()) + if result: + raise ValueError("Error %d while instantiating the OCB mode" + % result) + + # Ensure that object disposal of this Python object will (eventually) + # free the memory allocated by the raw library for the cipher mode + self._state = SmartPointer(self._state.get(), + _raw_ocb_lib.OCB_stop_operation) + + # Memory allocated for the underlying block cipher is now owed + # by the cipher mode + raw_cipher.release() + + def _update(self, assoc_data, assoc_data_len): + result = _raw_ocb_lib.OCB_update(self._state.get(), + c_uint8_ptr(assoc_data), + c_size_t(assoc_data_len)) + if result: + raise ValueError("Error %d while computing MAC in OCB mode" % result) + + def update(self, assoc_data): + """Process the associated data. + + If there is any associated data, the caller has to invoke + this method one or more times, before using + ``decrypt`` or ``encrypt``. + + By *associated data* it is meant any data (e.g. packet headers) that + will not be encrypted and will be transmitted in the clear. + However, the receiver shall still able to detect modifications. + + If there is no associated data, this method must not be called. + + The caller may split associated data in segments of any size, and + invoke this method multiple times, each time with the next segment. + + :Parameters: + assoc_data : bytes/bytearray/memoryview + A piece of associated data. + """ + + if "update" not in self._next: + raise TypeError("update() can only be called" + " immediately after initialization") + + self._next = ["encrypt", "decrypt", "digest", + "verify", "update"] + + if len(self._cache_A) > 0: + filler = min(16 - len(self._cache_A), len(assoc_data)) + self._cache_A += _copy_bytes(None, filler, assoc_data) + assoc_data = assoc_data[filler:] + + if len(self._cache_A) < 16: + return self + + # Clear the cache, and proceeding with any other aligned data + self._cache_A, seg = b"", self._cache_A + self.update(seg) + + update_len = len(assoc_data) // 16 * 16 + self._cache_A = _copy_bytes(update_len, None, assoc_data) + self._update(assoc_data, update_len) + return self + + def _transcrypt_aligned(self, in_data, in_data_len, + trans_func, trans_desc): + + out_data = create_string_buffer(in_data_len) + result = trans_func(self._state.get(), + in_data, + out_data, + c_size_t(in_data_len)) + if result: + raise ValueError("Error %d while %sing in OCB mode" + % (result, trans_desc)) + return get_raw_buffer(out_data) + + def _transcrypt(self, in_data, trans_func, trans_desc): + # Last piece to encrypt/decrypt + if in_data is None: + out_data = self._transcrypt_aligned(self._cache_P, + len(self._cache_P), + trans_func, + trans_desc) + self._cache_P = b"" + return out_data + + # Try to fill up the cache, if it already contains something + prefix = b"" + if len(self._cache_P) > 0: + filler = min(16 - len(self._cache_P), len(in_data)) + self._cache_P += _copy_bytes(None, filler, in_data) + in_data = in_data[filler:] + + if len(self._cache_P) < 16: + # We could not manage to fill the cache, so there is certainly + # no output yet. + return b"" + + # Clear the cache, and proceeding with any other aligned data + prefix = self._transcrypt_aligned(self._cache_P, + len(self._cache_P), + trans_func, + trans_desc) + self._cache_P = b"" + + # Process data in multiples of the block size + trans_len = len(in_data) // 16 * 16 + result = self._transcrypt_aligned(c_uint8_ptr(in_data), + trans_len, + trans_func, + trans_desc) + if prefix: + result = prefix + result + + # Left-over + self._cache_P = _copy_bytes(trans_len, None, in_data) + + return result + + def encrypt(self, plaintext=None): + """Encrypt the next piece of plaintext. + + After the entire plaintext has been passed (but before `digest`), + you **must** call this method one last time with no arguments to collect + the final piece of ciphertext. + + If possible, use the method `encrypt_and_digest` instead. + + :Parameters: + plaintext : bytes/bytearray/memoryview + The next piece of data to encrypt or ``None`` to signify + that encryption has finished and that any remaining ciphertext + has to be produced. + :Return: + the ciphertext, as a byte string. + Its length may not match the length of the *plaintext*. + """ + + if "encrypt" not in self._next: + raise TypeError("encrypt() can only be called after" + " initialization or an update()") + + if plaintext is None: + self._next = ["digest"] + else: + self._next = ["encrypt"] + return self._transcrypt(plaintext, _raw_ocb_lib.OCB_encrypt, "encrypt") + + def decrypt(self, ciphertext=None): + """Decrypt the next piece of ciphertext. + + After the entire ciphertext has been passed (but before `verify`), + you **must** call this method one last time with no arguments to collect + the remaining piece of plaintext. + + If possible, use the method `decrypt_and_verify` instead. + + :Parameters: + ciphertext : bytes/bytearray/memoryview + The next piece of data to decrypt or ``None`` to signify + that decryption has finished and that any remaining plaintext + has to be produced. + :Return: + the plaintext, as a byte string. + Its length may not match the length of the *ciphertext*. + """ + + if "decrypt" not in self._next: + raise TypeError("decrypt() can only be called after" + " initialization or an update()") + + if ciphertext is None: + self._next = ["verify"] + else: + self._next = ["decrypt"] + return self._transcrypt(ciphertext, + _raw_ocb_lib.OCB_decrypt, + "decrypt") + + def _compute_mac_tag(self): + + if self._mac_tag is not None: + return + + if self._cache_A: + self._update(self._cache_A, len(self._cache_A)) + self._cache_A = b"" + + mac_tag = create_string_buffer(16) + result = _raw_ocb_lib.OCB_digest(self._state.get(), + mac_tag, + c_size_t(len(mac_tag)) + ) + if result: + raise ValueError("Error %d while computing digest in OCB mode" + % result) + self._mac_tag = get_raw_buffer(mac_tag)[:self._mac_len] + + def digest(self): + """Compute the *binary* MAC tag. + + Call this method after the final `encrypt` (the one with no arguments) + to obtain the MAC tag. + + The MAC tag is needed by the receiver to determine authenticity + of the message. + + :Return: the MAC, as a byte string. + """ + + if "digest" not in self._next: + raise TypeError("digest() cannot be called now for this cipher") + + assert(len(self._cache_P) == 0) + + self._next = ["digest"] + + if self._mac_tag is None: + self._compute_mac_tag() + + return self._mac_tag + + def hexdigest(self): + """Compute the *printable* MAC tag. + + This method is like `digest`. + + :Return: the MAC, as a hexadecimal string. + """ + return "".join(["%02x" % bord(x) for x in self.digest()]) + + def verify(self, received_mac_tag): + """Validate the *binary* MAC tag. + + Call this method after the final `decrypt` (the one with no arguments) + to check if the message is authentic and valid. + + :Parameters: + received_mac_tag : bytes/bytearray/memoryview + This is the *binary* MAC, as received from the sender. + :Raises ValueError: + if the MAC does not match. The message has been tampered with + or the key is incorrect. + """ + + if "verify" not in self._next: + raise TypeError("verify() cannot be called now for this cipher") + + assert(len(self._cache_P) == 0) + + self._next = ["verify"] + + if self._mac_tag is None: + self._compute_mac_tag() + + secret = get_random_bytes(16) + mac1 = BLAKE2s.new(digest_bits=160, key=secret, data=self._mac_tag) + mac2 = BLAKE2s.new(digest_bits=160, key=secret, data=received_mac_tag) + + if mac1.digest() != mac2.digest(): + raise ValueError("MAC check failed") + + def hexverify(self, hex_mac_tag): + """Validate the *printable* MAC tag. + + This method is like `verify`. + + :Parameters: + hex_mac_tag : string + This is the *printable* MAC, as received from the sender. + :Raises ValueError: + if the MAC does not match. The message has been tampered with + or the key is incorrect. + """ + + self.verify(unhexlify(hex_mac_tag)) + + def encrypt_and_digest(self, plaintext): + """Encrypt the message and create the MAC tag in one step. + + :Parameters: + plaintext : bytes/bytearray/memoryview + The entire message to encrypt. + :Return: + a tuple with two byte strings: + + - the encrypted data + - the MAC + """ + + return self.encrypt(plaintext) + self.encrypt(), self.digest() + + def decrypt_and_verify(self, ciphertext, received_mac_tag): + """Decrypted the message and verify its authenticity in one step. + + :Parameters: + ciphertext : bytes/bytearray/memoryview + The entire message to decrypt. + received_mac_tag : byte string + This is the *binary* MAC, as received from the sender. + + :Return: the decrypted data (byte string). + :Raises ValueError: + if the MAC does not match. The message has been tampered with + or the key is incorrect. + """ + + plaintext = self.decrypt(ciphertext) + self.decrypt() + self.verify(received_mac_tag) + return plaintext + + +def _create_ocb_cipher(factory, **kwargs): + """Create a new block cipher, configured in OCB mode. + + :Parameters: + factory : module + A symmetric cipher module from `Cryptodome.Cipher` + (like `Cryptodome.Cipher.AES`). + + :Keywords: + nonce : bytes/bytearray/memoryview + A value that must never be reused for any other encryption. + Its length can vary from 1 to 15 bytes. + If not specified, a random 15 bytes long nonce is generated. + + mac_len : integer + Length of the MAC, in bytes. + It must be in the range ``[8..16]``. + The default is 16 (128 bits). + + Any other keyword will be passed to the underlying block cipher. + See the relevant documentation for details (at least ``key`` will need + to be present). + """ + + try: + nonce = kwargs.pop("nonce", None) + if nonce is None: + nonce = get_random_bytes(15) + mac_len = kwargs.pop("mac_len", 16) + except KeyError as e: + raise TypeError("Keyword missing: " + str(e)) + + return OcbMode(factory, nonce, mac_len, kwargs) diff --git a/venv/Lib/site-packages/Cryptodome/Cipher/_mode_ocb.pyi b/venv/Lib/site-packages/Cryptodome/Cipher/_mode_ocb.pyi new file mode 100644 index 0000000..a1909fc --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Cipher/_mode_ocb.pyi @@ -0,0 +1,36 @@ +from types import ModuleType +from typing import Union, Any, Optional, Tuple, Dict, overload + +Buffer = Union[bytes, bytearray, memoryview] + +class OcbMode(object): + block_size: int + nonce: Buffer + + def __init__(self, + factory: ModuleType, + nonce: Buffer, + mac_len: int, + cipher_params: Dict) -> None: ... + + def update(self, assoc_data: Buffer) -> OcbMode: ... + + @overload + def encrypt(self, plaintext: Buffer) -> bytes: ... + @overload + def encrypt(self, plaintext: Buffer, output: Union[bytearray, memoryview]) -> None: ... + @overload + def decrypt(self, plaintext: Buffer) -> bytes: ... + @overload + def decrypt(self, plaintext: Buffer, output: Union[bytearray, memoryview]) -> None: ... + + def digest(self) -> bytes: ... + def hexdigest(self) -> str: ... + def verify(self, received_mac_tag: Buffer) -> None: ... + def hexverify(self, hex_mac_tag: str) -> None: ... + + def encrypt_and_digest(self, + plaintext: Buffer) -> Tuple[bytes, bytes]: ... + def decrypt_and_verify(self, + ciphertext: Buffer, + received_mac_tag: Buffer) -> bytes: ... diff --git a/venv/Lib/site-packages/Cryptodome/Cipher/_mode_ofb.py b/venv/Lib/site-packages/Cryptodome/Cipher/_mode_ofb.py new file mode 100644 index 0000000..8c0ccf6 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Cipher/_mode_ofb.py @@ -0,0 +1,282 @@ +# -*- coding: utf-8 -*- +# +# Cipher/mode_ofb.py : OFB mode +# +# =================================================================== +# The contents of this file are dedicated to the public domain. To +# the extent that dedication to the public domain is not available, +# everyone is granted a worldwide, perpetual, royalty-free, +# non-exclusive license to exercise all rights associated with the +# contents of this file for any purpose whatsoever. +# No rights are reserved. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# =================================================================== + +""" +Output Feedback (CFB) mode. +""" + +__all__ = ['OfbMode'] + +from Cryptodome.Util.py3compat import _copy_bytes +from Cryptodome.Util._raw_api import (load_pycryptodome_raw_lib, VoidPointer, + create_string_buffer, get_raw_buffer, + SmartPointer, c_size_t, c_uint8_ptr, + is_writeable_buffer) + +from Cryptodome.Random import get_random_bytes + +raw_ofb_lib = load_pycryptodome_raw_lib("Cryptodome.Cipher._raw_ofb", """ + int OFB_start_operation(void *cipher, + const uint8_t iv[], + size_t iv_len, + void **pResult); + int OFB_encrypt(void *ofbState, + const uint8_t *in, + uint8_t *out, + size_t data_len); + int OFB_decrypt(void *ofbState, + const uint8_t *in, + uint8_t *out, + size_t data_len); + int OFB_stop_operation(void *state); + """ + ) + + +class OfbMode(object): + """*Output FeedBack (OFB)*. + + This mode is very similar to CBC, but it + transforms the underlying block cipher into a stream cipher. + + The keystream is the iterated block encryption of the + previous ciphertext block. + + An Initialization Vector (*IV*) is required. + + See `NIST SP800-38A`_ , Section 6.4. + + .. _`NIST SP800-38A` : http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf + + :undocumented: __init__ + """ + + def __init__(self, block_cipher, iv): + """Create a new block cipher, configured in OFB mode. + + :Parameters: + block_cipher : C pointer + A smart pointer to the low-level block cipher instance. + + iv : bytes/bytearray/memoryview + The initialization vector to use for encryption or decryption. + It is as long as the cipher block. + + **The IV must be a nonce, to to be reused for any other + message**. It shall be a nonce or a random value. + + Reusing the *IV* for encryptions performed with the same key + compromises confidentiality. + """ + + self._state = VoidPointer() + result = raw_ofb_lib.OFB_start_operation(block_cipher.get(), + c_uint8_ptr(iv), + c_size_t(len(iv)), + self._state.address_of()) + if result: + raise ValueError("Error %d while instantiating the OFB mode" + % result) + + # Ensure that object disposal of this Python object will (eventually) + # free the memory allocated by the raw library for the cipher mode + self._state = SmartPointer(self._state.get(), + raw_ofb_lib.OFB_stop_operation) + + # Memory allocated for the underlying block cipher is now owed + # by the cipher mode + block_cipher.release() + + self.block_size = len(iv) + """The block size of the underlying cipher, in bytes.""" + + self.iv = _copy_bytes(None, None, iv) + """The Initialization Vector originally used to create the object. + The value does not change.""" + + self.IV = self.iv + """Alias for `iv`""" + + self._next = ["encrypt", "decrypt"] + + def encrypt(self, plaintext, output=None): + """Encrypt data with the key and the parameters set at initialization. + + A cipher object is stateful: once you have encrypted a message + you cannot encrypt (or decrypt) another message using the same + object. + + The data to encrypt can be broken up in two or + more pieces and `encrypt` can be called multiple times. + + That is, the statement: + + >>> c.encrypt(a) + c.encrypt(b) + + is equivalent to: + + >>> c.encrypt(a+b) + + This function does not add any padding to the plaintext. + + :Parameters: + plaintext : bytes/bytearray/memoryview + The piece of data to encrypt. + It can be of any length. + :Keywords: + output : bytearray/memoryview + The location where the ciphertext must be written to. + If ``None``, the ciphertext is returned. + :Return: + If ``output`` is ``None``, the ciphertext is returned as ``bytes``. + Otherwise, ``None``. + """ + + if "encrypt" not in self._next: + raise TypeError("encrypt() cannot be called after decrypt()") + self._next = ["encrypt"] + + if output is None: + ciphertext = create_string_buffer(len(plaintext)) + else: + ciphertext = output + + if not is_writeable_buffer(output): + raise TypeError("output must be a bytearray or a writeable memoryview") + + if len(plaintext) != len(output): + raise ValueError("output must have the same length as the input" + " (%d bytes)" % len(plaintext)) + + result = raw_ofb_lib.OFB_encrypt(self._state.get(), + c_uint8_ptr(plaintext), + c_uint8_ptr(ciphertext), + c_size_t(len(plaintext))) + if result: + raise ValueError("Error %d while encrypting in OFB mode" % result) + + if output is None: + return get_raw_buffer(ciphertext) + else: + return None + + def decrypt(self, ciphertext, output=None): + """Decrypt data with the key and the parameters set at initialization. + + A cipher object is stateful: once you have decrypted a message + you cannot decrypt (or encrypt) another message with the same + object. + + The data to decrypt can be broken up in two or + more pieces and `decrypt` can be called multiple times. + + That is, the statement: + + >>> c.decrypt(a) + c.decrypt(b) + + is equivalent to: + + >>> c.decrypt(a+b) + + This function does not remove any padding from the plaintext. + + :Parameters: + ciphertext : bytes/bytearray/memoryview + The piece of data to decrypt. + It can be of any length. + :Keywords: + output : bytearray/memoryview + The location where the plaintext is written to. + If ``None``, the plaintext is returned. + :Return: + If ``output`` is ``None``, the plaintext is returned as ``bytes``. + Otherwise, ``None``. + """ + + if "decrypt" not in self._next: + raise TypeError("decrypt() cannot be called after encrypt()") + self._next = ["decrypt"] + + if output is None: + plaintext = create_string_buffer(len(ciphertext)) + else: + plaintext = output + + if not is_writeable_buffer(output): + raise TypeError("output must be a bytearray or a writeable memoryview") + + if len(ciphertext) != len(output): + raise ValueError("output must have the same length as the input" + " (%d bytes)" % len(plaintext)) + + result = raw_ofb_lib.OFB_decrypt(self._state.get(), + c_uint8_ptr(ciphertext), + c_uint8_ptr(plaintext), + c_size_t(len(ciphertext))) + if result: + raise ValueError("Error %d while decrypting in OFB mode" % result) + + if output is None: + return get_raw_buffer(plaintext) + else: + return None + + +def _create_ofb_cipher(factory, **kwargs): + """Instantiate a cipher object that performs OFB encryption/decryption. + + :Parameters: + factory : module + The underlying block cipher, a module from ``Cryptodome.Cipher``. + + :Keywords: + iv : bytes/bytearray/memoryview + The IV to use for OFB. + + IV : bytes/bytearray/memoryview + Alias for ``iv``. + + Any other keyword will be passed to the underlying block cipher. + See the relevant documentation for details (at least ``key`` will need + to be present). + """ + + cipher_state = factory._create_base_cipher(kwargs) + iv = kwargs.pop("IV", None) + IV = kwargs.pop("iv", None) + + if (None, None) == (iv, IV): + iv = get_random_bytes(factory.block_size) + if iv is not None: + if IV is not None: + raise TypeError("You must either use 'iv' or 'IV', not both") + else: + iv = IV + + if len(iv) != factory.block_size: + raise ValueError("Incorrect IV length (it must be %d bytes long)" % + factory.block_size) + + if kwargs: + raise TypeError("Unknown parameters for OFB: %s" % str(kwargs)) + + return OfbMode(cipher_state, iv) diff --git a/venv/Lib/site-packages/Cryptodome/Cipher/_mode_ofb.pyi b/venv/Lib/site-packages/Cryptodome/Cipher/_mode_ofb.pyi new file mode 100644 index 0000000..d28608e --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Cipher/_mode_ofb.pyi @@ -0,0 +1,25 @@ +from typing import Union, overload + +from Cryptodome.Util._raw_api import SmartPointer + +Buffer = Union[bytes, bytearray, memoryview] + +__all__ = ['OfbMode'] + +class OfbMode(object): + block_size: int + iv: Buffer + IV: Buffer + + def __init__(self, + block_cipher: SmartPointer, + iv: Buffer) -> None: ... + @overload + def encrypt(self, plaintext: Buffer) -> bytes: ... + @overload + def encrypt(self, plaintext: Buffer, output: Union[bytearray, memoryview]) -> None: ... + @overload + def decrypt(self, plaintext: Buffer) -> bytes: ... + @overload + def decrypt(self, plaintext: Buffer, output: Union[bytearray, memoryview]) -> None: ... + diff --git a/venv/Lib/site-packages/Cryptodome/Cipher/_mode_openpgp.py b/venv/Lib/site-packages/Cryptodome/Cipher/_mode_openpgp.py new file mode 100644 index 0000000..d86ed19 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Cipher/_mode_openpgp.py @@ -0,0 +1,206 @@ +# =================================================================== +# +# Copyright (c) 2014, Legrandin +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# =================================================================== + +""" +OpenPGP mode. +""" + +__all__ = ['OpenPgpMode'] + +from Cryptodome.Util.py3compat import _copy_bytes +from Cryptodome.Random import get_random_bytes + +class OpenPgpMode(object): + """OpenPGP mode. + + This mode is a variant of CFB, and it is only used in PGP and + OpenPGP_ applications. If in doubt, use another mode. + + An Initialization Vector (*IV*) is required. + + Unlike CFB, the *encrypted* IV (not the IV itself) is + transmitted to the receiver. + + The IV is a random data block. For legacy reasons, two of its bytes are + duplicated to act as a checksum for the correctness of the key, which is now + known to be insecure and is ignored. The encrypted IV is therefore 2 bytes + longer than the clean IV. + + .. _OpenPGP: http://tools.ietf.org/html/rfc4880 + + :undocumented: __init__ + """ + + def __init__(self, factory, key, iv, cipher_params): + + #: The block size of the underlying cipher, in bytes. + self.block_size = factory.block_size + + self._done_first_block = False # True after the first encryption + + # Instantiate a temporary cipher to process the IV + IV_cipher = factory.new( + key, + factory.MODE_CFB, + IV=b'\x00' * self.block_size, + segment_size=self.block_size * 8, + **cipher_params) + + iv = _copy_bytes(None, None, iv) + + # The cipher will be used for... + if len(iv) == self.block_size: + # ... encryption + self._encrypted_IV = IV_cipher.encrypt(iv + iv[-2:]) + elif len(iv) == self.block_size + 2: + # ... decryption + self._encrypted_IV = iv + # Last two bytes are for a deprecated "quick check" feature that + # should not be used. (https://eprint.iacr.org/2005/033) + iv = IV_cipher.decrypt(iv)[:-2] + else: + raise ValueError("Length of IV must be %d or %d bytes" + " for MODE_OPENPGP" + % (self.block_size, self.block_size + 2)) + + self.iv = self.IV = iv + + # Instantiate the cipher for the real PGP data + self._cipher = factory.new( + key, + factory.MODE_CFB, + IV=self._encrypted_IV[-self.block_size:], + segment_size=self.block_size * 8, + **cipher_params) + + def encrypt(self, plaintext): + """Encrypt data with the key and the parameters set at initialization. + + A cipher object is stateful: once you have encrypted a message + you cannot encrypt (or decrypt) another message using the same + object. + + The data to encrypt can be broken up in two or + more pieces and `encrypt` can be called multiple times. + + That is, the statement: + + >>> c.encrypt(a) + c.encrypt(b) + + is equivalent to: + + >>> c.encrypt(a+b) + + This function does not add any padding to the plaintext. + + :Parameters: + plaintext : bytes/bytearray/memoryview + The piece of data to encrypt. + + :Return: + the encrypted data, as a byte string. + It is as long as *plaintext* with one exception: + when encrypting the first message chunk, + the encypted IV is prepended to the returned ciphertext. + """ + + res = self._cipher.encrypt(plaintext) + if not self._done_first_block: + res = self._encrypted_IV + res + self._done_first_block = True + return res + + def decrypt(self, ciphertext): + """Decrypt data with the key and the parameters set at initialization. + + A cipher object is stateful: once you have decrypted a message + you cannot decrypt (or encrypt) another message with the same + object. + + The data to decrypt can be broken up in two or + more pieces and `decrypt` can be called multiple times. + + That is, the statement: + + >>> c.decrypt(a) + c.decrypt(b) + + is equivalent to: + + >>> c.decrypt(a+b) + + This function does not remove any padding from the plaintext. + + :Parameters: + ciphertext : bytes/bytearray/memoryview + The piece of data to decrypt. + + :Return: the decrypted data (byte string). + """ + + return self._cipher.decrypt(ciphertext) + + +def _create_openpgp_cipher(factory, **kwargs): + """Create a new block cipher, configured in OpenPGP mode. + + :Parameters: + factory : module + The module. + + :Keywords: + key : bytes/bytearray/memoryview + The secret key to use in the symmetric cipher. + + IV : bytes/bytearray/memoryview + The initialization vector to use for encryption or decryption. + + For encryption, the IV must be as long as the cipher block size. + + For decryption, it must be 2 bytes longer (it is actually the + *encrypted* IV which was prefixed to the ciphertext). + """ + + iv = kwargs.pop("IV", None) + IV = kwargs.pop("iv", None) + + if (None, None) == (iv, IV): + iv = get_random_bytes(factory.block_size) + if iv is not None: + if IV is not None: + raise TypeError("You must either use 'iv' or 'IV', not both") + else: + iv = IV + + try: + key = kwargs.pop("key") + except KeyError as e: + raise TypeError("Missing component: " + str(e)) + + return OpenPgpMode(factory, key, iv, kwargs) diff --git a/venv/Lib/site-packages/Cryptodome/Cipher/_mode_openpgp.pyi b/venv/Lib/site-packages/Cryptodome/Cipher/_mode_openpgp.pyi new file mode 100644 index 0000000..14b8105 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Cipher/_mode_openpgp.pyi @@ -0,0 +1,20 @@ +from types import ModuleType +from typing import Union, Dict + +Buffer = Union[bytes, bytearray, memoryview] + +__all__ = ['OpenPgpMode'] + +class OpenPgpMode(object): + block_size: int + iv: Union[bytes, bytearray, memoryview] + IV: Union[bytes, bytearray, memoryview] + + def __init__(self, + factory: ModuleType, + key: Buffer, + iv: Buffer, + cipher_params: Dict) -> None: ... + def encrypt(self, plaintext: Buffer) -> bytes: ... + def decrypt(self, plaintext: Buffer) -> bytes: ... + diff --git a/venv/Lib/site-packages/Cryptodome/Cipher/_mode_siv.py b/venv/Lib/site-packages/Cryptodome/Cipher/_mode_siv.py new file mode 100644 index 0000000..4a76ad6 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Cipher/_mode_siv.py @@ -0,0 +1,392 @@ +# =================================================================== +# +# Copyright (c) 2014, Legrandin +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# =================================================================== + +""" +Synthetic Initialization Vector (SIV) mode. +""" + +__all__ = ['SivMode'] + +from binascii import hexlify, unhexlify + +from Cryptodome.Util.py3compat import bord, _copy_bytes + +from Cryptodome.Util._raw_api import is_buffer + +from Cryptodome.Util.number import long_to_bytes, bytes_to_long +from Cryptodome.Protocol.KDF import _S2V +from Cryptodome.Hash import BLAKE2s +from Cryptodome.Random import get_random_bytes + + +class SivMode(object): + """Synthetic Initialization Vector (SIV). + + This is an Authenticated Encryption with Associated Data (`AEAD`_) mode. + It provides both confidentiality and authenticity. + + The header of the message may be left in the clear, if needed, and it will + still be subject to authentication. The decryption step tells the receiver + if the message comes from a source that really knowns the secret key. + Additionally, decryption detects if any part of the message - including the + header - has been modified or corrupted. + + Unlike other AEAD modes such as CCM, EAX or GCM, accidental reuse of a + nonce is not catastrophic for the confidentiality of the message. The only + effect is that an attacker can tell when the same plaintext (and same + associated data) is protected with the same key. + + The length of the MAC is fixed to the block size of the underlying cipher. + The key size is twice the length of the key of the underlying cipher. + + This mode is only available for AES ciphers. + + +--------------------+---------------+-------------------+ + | Cipher | SIV MAC size | SIV key length | + | | (bytes) | (bytes) | + +====================+===============+===================+ + | AES-128 | 16 | 32 | + +--------------------+---------------+-------------------+ + | AES-192 | 16 | 48 | + +--------------------+---------------+-------------------+ + | AES-256 | 16 | 64 | + +--------------------+---------------+-------------------+ + + See `RFC5297`_ and the `original paper`__. + + .. _RFC5297: https://tools.ietf.org/html/rfc5297 + .. _AEAD: http://blog.cryptographyengineering.com/2012/05/how-to-choose-authenticated-encryption.html + .. __: http://www.cs.ucdavis.edu/~rogaway/papers/keywrap.pdf + + :undocumented: __init__ + """ + + def __init__(self, factory, key, nonce, kwargs): + + self.block_size = factory.block_size + """The block size of the underlying cipher, in bytes.""" + + self._factory = factory + + self._cipher_params = kwargs + + if len(key) not in (32, 48, 64): + raise ValueError("Incorrect key length (%d bytes)" % len(key)) + + if nonce is not None: + if not is_buffer(nonce): + raise TypeError("When provided, the nonce must be bytes, bytearray or memoryview") + + if len(nonce) == 0: + raise ValueError("When provided, the nonce must be non-empty") + + self.nonce = _copy_bytes(None, None, nonce) + """Public attribute is only available in case of non-deterministic + encryption.""" + + subkey_size = len(key) // 2 + + self._mac_tag = None # Cache for MAC tag + self._kdf = _S2V(key[:subkey_size], + ciphermod=factory, + cipher_params=self._cipher_params) + self._subkey_cipher = key[subkey_size:] + + # Purely for the purpose of verifying that cipher_params are OK + factory.new(key[:subkey_size], factory.MODE_ECB, **kwargs) + + # Allowed transitions after initialization + self._next = ["update", "encrypt", "decrypt", + "digest", "verify"] + + def _create_ctr_cipher(self, v): + """Create a new CTR cipher from V in SIV mode""" + + v_int = bytes_to_long(v) + q = v_int & 0xFFFFFFFFFFFFFFFF7FFFFFFF7FFFFFFF + return self._factory.new( + self._subkey_cipher, + self._factory.MODE_CTR, + initial_value=q, + nonce=b"", + **self._cipher_params) + + def update(self, component): + """Protect one associated data component + + For SIV, the associated data is a sequence (*vector*) of non-empty + byte strings (*components*). + + This method consumes the next component. It must be called + once for each of the components that constitue the associated data. + + Note that the components have clear boundaries, so that: + + >>> cipher.update(b"builtin") + >>> cipher.update(b"securely") + + is not equivalent to: + + >>> cipher.update(b"built") + >>> cipher.update(b"insecurely") + + If there is no associated data, this method must not be called. + + :Parameters: + component : bytes/bytearray/memoryview + The next associated data component. + """ + + if "update" not in self._next: + raise TypeError("update() can only be called" + " immediately after initialization") + + self._next = ["update", "encrypt", "decrypt", + "digest", "verify"] + + return self._kdf.update(component) + + def encrypt(self, plaintext): + """ + For SIV, encryption and MAC authentication must take place at the same + point. This method shall not be used. + + Use `encrypt_and_digest` instead. + """ + + raise TypeError("encrypt() not allowed for SIV mode." + " Use encrypt_and_digest() instead.") + + def decrypt(self, ciphertext): + """ + For SIV, decryption and verification must take place at the same + point. This method shall not be used. + + Use `decrypt_and_verify` instead. + """ + + raise TypeError("decrypt() not allowed for SIV mode." + " Use decrypt_and_verify() instead.") + + def digest(self): + """Compute the *binary* MAC tag. + + The caller invokes this function at the very end. + + This method returns the MAC that shall be sent to the receiver, + together with the ciphertext. + + :Return: the MAC, as a byte string. + """ + + if "digest" not in self._next: + raise TypeError("digest() cannot be called when decrypting" + " or validating a message") + self._next = ["digest"] + if self._mac_tag is None: + self._mac_tag = self._kdf.derive() + return self._mac_tag + + def hexdigest(self): + """Compute the *printable* MAC tag. + + This method is like `digest`. + + :Return: the MAC, as a hexadecimal string. + """ + return "".join(["%02x" % bord(x) for x in self.digest()]) + + def verify(self, received_mac_tag): + """Validate the *binary* MAC tag. + + The caller invokes this function at the very end. + + This method checks if the decrypted message is indeed valid + (that is, if the key is correct) and it has not been + tampered with while in transit. + + :Parameters: + received_mac_tag : bytes/bytearray/memoryview + This is the *binary* MAC, as received from the sender. + :Raises ValueError: + if the MAC does not match. The message has been tampered with + or the key is incorrect. + """ + + if "verify" not in self._next: + raise TypeError("verify() cannot be called" + " when encrypting a message") + self._next = ["verify"] + + if self._mac_tag is None: + self._mac_tag = self._kdf.derive() + + secret = get_random_bytes(16) + + mac1 = BLAKE2s.new(digest_bits=160, key=secret, data=self._mac_tag) + mac2 = BLAKE2s.new(digest_bits=160, key=secret, data=received_mac_tag) + + if mac1.digest() != mac2.digest(): + raise ValueError("MAC check failed") + + def hexverify(self, hex_mac_tag): + """Validate the *printable* MAC tag. + + This method is like `verify`. + + :Parameters: + hex_mac_tag : string + This is the *printable* MAC, as received from the sender. + :Raises ValueError: + if the MAC does not match. The message has been tampered with + or the key is incorrect. + """ + + self.verify(unhexlify(hex_mac_tag)) + + def encrypt_and_digest(self, plaintext, output=None): + """Perform encrypt() and digest() in one step. + + :Parameters: + plaintext : bytes/bytearray/memoryview + The piece of data to encrypt. + :Keywords: + output : bytearray/memoryview + The location where the ciphertext must be written to. + If ``None``, the ciphertext is returned. + :Return: + a tuple with two items: + + - the ciphertext, as ``bytes`` + - the MAC tag, as ``bytes`` + + The first item becomes ``None`` when the ``output`` parameter + specified a location for the result. + """ + + if "encrypt" not in self._next: + raise TypeError("encrypt() can only be called after" + " initialization or an update()") + + self._next = ["digest"] + + # Compute V (MAC) + if hasattr(self, 'nonce'): + self._kdf.update(self.nonce) + self._kdf.update(plaintext) + self._mac_tag = self._kdf.derive() + + cipher = self._create_ctr_cipher(self._mac_tag) + + return cipher.encrypt(plaintext, output=output), self._mac_tag + + def decrypt_and_verify(self, ciphertext, mac_tag, output=None): + """Perform decryption and verification in one step. + + A cipher object is stateful: once you have decrypted a message + you cannot decrypt (or encrypt) another message with the same + object. + + You cannot reuse an object for encrypting + or decrypting other data with the same key. + + This function does not remove any padding from the plaintext. + + :Parameters: + ciphertext : bytes/bytearray/memoryview + The piece of data to decrypt. + It can be of any length. + mac_tag : bytes/bytearray/memoryview + This is the *binary* MAC, as received from the sender. + :Keywords: + output : bytearray/memoryview + The location where the plaintext must be written to. + If ``None``, the plaintext is returned. + :Return: the plaintext as ``bytes`` or ``None`` when the ``output`` + parameter specified a location for the result. + :Raises ValueError: + if the MAC does not match. The message has been tampered with + or the key is incorrect. + """ + + if "decrypt" not in self._next: + raise TypeError("decrypt() can only be called" + " after initialization or an update()") + self._next = ["verify"] + + # Take the MAC and start the cipher for decryption + self._cipher = self._create_ctr_cipher(mac_tag) + + plaintext = self._cipher.decrypt(ciphertext, output=output) + + if hasattr(self, 'nonce'): + self._kdf.update(self.nonce) + self._kdf.update(plaintext if output is None else output) + self.verify(mac_tag) + + return plaintext + + +def _create_siv_cipher(factory, **kwargs): + """Create a new block cipher, configured in + Synthetic Initializaton Vector (SIV) mode. + + :Parameters: + + factory : object + A symmetric cipher module from `Cryptodome.Cipher` + (like `Cryptodome.Cipher.AES`). + + :Keywords: + + key : bytes/bytearray/memoryview + The secret key to use in the symmetric cipher. + It must be 32, 48 or 64 bytes long. + If AES is the chosen cipher, the variants *AES-128*, + *AES-192* and or *AES-256* will be used internally. + + nonce : bytes/bytearray/memoryview + For deterministic encryption, it is not present. + + Otherwise, it is a value that must never be reused + for encrypting message under this key. + + There are no restrictions on its length, + but it is recommended to use at least 16 bytes. + """ + + try: + key = kwargs.pop("key") + except KeyError as e: + raise TypeError("Missing parameter: " + str(e)) + + nonce = kwargs.pop("nonce", None) + + return SivMode(factory, key, nonce, kwargs) diff --git a/venv/Lib/site-packages/Cryptodome/Cipher/_mode_siv.pyi b/venv/Lib/site-packages/Cryptodome/Cipher/_mode_siv.pyi new file mode 100644 index 0000000..2934f23 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Cipher/_mode_siv.pyi @@ -0,0 +1,38 @@ +from types import ModuleType +from typing import Union, Tuple, Dict, Optional, overload + +Buffer = Union[bytes, bytearray, memoryview] + +__all__ = ['SivMode'] + +class SivMode(object): + block_size: int + nonce: bytes + + def __init__(self, + factory: ModuleType, + key: Buffer, + nonce: Buffer, + kwargs: Dict) -> None: ... + + def update(self, component: Buffer) -> SivMode: ... + + def encrypt(self, plaintext: Buffer) -> bytes: ... + def decrypt(self, plaintext: Buffer) -> bytes: ... + + def digest(self) -> bytes: ... + def hexdigest(self) -> str: ... + def verify(self, received_mac_tag: Buffer) -> None: ... + def hexverify(self, hex_mac_tag: str) -> None: ... + + @overload + def encrypt_and_digest(self, + plaintext: Buffer) -> Tuple[bytes, bytes]: ... + @overload + def encrypt_and_digest(self, + plaintext: Buffer, + output: Buffer) -> Tuple[None, bytes]: ... + def decrypt_and_verify(self, + ciphertext: Buffer, + received_mac_tag: Buffer, + output: Optional[Union[bytearray, memoryview]] = ...) -> bytes: ... diff --git a/venv/Lib/site-packages/Cryptodome/Cipher/_pkcs1_decode.pyd b/venv/Lib/site-packages/Cryptodome/Cipher/_pkcs1_decode.pyd new file mode 100644 index 0000000..13059c4 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Cipher/_pkcs1_decode.pyd differ diff --git a/venv/Lib/site-packages/Cryptodome/Cipher/_pkcs1_oaep_decode.py b/venv/Lib/site-packages/Cryptodome/Cipher/_pkcs1_oaep_decode.py new file mode 100644 index 0000000..82bdaa7 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Cipher/_pkcs1_oaep_decode.py @@ -0,0 +1,41 @@ +from Cryptodome.Util._raw_api import (load_pycryptodome_raw_lib, c_size_t, + c_uint8_ptr) + + +_raw_pkcs1_decode = load_pycryptodome_raw_lib("Cryptodome.Cipher._pkcs1_decode", + """ + int pkcs1_decode(const uint8_t *em, size_t len_em, + const uint8_t *sentinel, size_t len_sentinel, + size_t expected_pt_len, + uint8_t *output); + + int oaep_decode(const uint8_t *em, + size_t em_len, + const uint8_t *lHash, + size_t hLen, + const uint8_t *db, + size_t db_len); + """) + + +def pkcs1_decode(em, sentinel, expected_pt_len, output): + if len(em) != len(output): + raise ValueError("Incorrect output length") + + ret = _raw_pkcs1_decode.pkcs1_decode(c_uint8_ptr(em), + c_size_t(len(em)), + c_uint8_ptr(sentinel), + c_size_t(len(sentinel)), + c_size_t(expected_pt_len), + c_uint8_ptr(output)) + return ret + + +def oaep_decode(em, lHash, db): + ret = _raw_pkcs1_decode.oaep_decode(c_uint8_ptr(em), + c_size_t(len(em)), + c_uint8_ptr(lHash), + c_size_t(len(lHash)), + c_uint8_ptr(db), + c_size_t(len(db))) + return ret diff --git a/venv/Lib/site-packages/Cryptodome/Cipher/_raw_aes.pyd b/venv/Lib/site-packages/Cryptodome/Cipher/_raw_aes.pyd new file mode 100644 index 0000000..70e520d Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Cipher/_raw_aes.pyd differ diff --git a/venv/Lib/site-packages/Cryptodome/Cipher/_raw_aesni.pyd b/venv/Lib/site-packages/Cryptodome/Cipher/_raw_aesni.pyd new file mode 100644 index 0000000..97bf6e8 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Cipher/_raw_aesni.pyd differ diff --git a/venv/Lib/site-packages/Cryptodome/Cipher/_raw_arc2.pyd b/venv/Lib/site-packages/Cryptodome/Cipher/_raw_arc2.pyd new file mode 100644 index 0000000..53f802e Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Cipher/_raw_arc2.pyd differ diff --git a/venv/Lib/site-packages/Cryptodome/Cipher/_raw_blowfish.pyd b/venv/Lib/site-packages/Cryptodome/Cipher/_raw_blowfish.pyd new file mode 100644 index 0000000..a03f704 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Cipher/_raw_blowfish.pyd differ diff --git a/venv/Lib/site-packages/Cryptodome/Cipher/_raw_cast.pyd b/venv/Lib/site-packages/Cryptodome/Cipher/_raw_cast.pyd new file mode 100644 index 0000000..61e6ec6 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Cipher/_raw_cast.pyd differ diff --git a/venv/Lib/site-packages/Cryptodome/Cipher/_raw_cbc.pyd b/venv/Lib/site-packages/Cryptodome/Cipher/_raw_cbc.pyd new file mode 100644 index 0000000..dce36b1 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Cipher/_raw_cbc.pyd differ diff --git a/venv/Lib/site-packages/Cryptodome/Cipher/_raw_cfb.pyd b/venv/Lib/site-packages/Cryptodome/Cipher/_raw_cfb.pyd new file mode 100644 index 0000000..aa91db3 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Cipher/_raw_cfb.pyd differ diff --git a/venv/Lib/site-packages/Cryptodome/Cipher/_raw_ctr.pyd b/venv/Lib/site-packages/Cryptodome/Cipher/_raw_ctr.pyd new file mode 100644 index 0000000..77950e2 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Cipher/_raw_ctr.pyd differ diff --git a/venv/Lib/site-packages/Cryptodome/Cipher/_raw_des.pyd b/venv/Lib/site-packages/Cryptodome/Cipher/_raw_des.pyd new file mode 100644 index 0000000..4bbefdd Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Cipher/_raw_des.pyd differ diff --git a/venv/Lib/site-packages/Cryptodome/Cipher/_raw_des3.pyd b/venv/Lib/site-packages/Cryptodome/Cipher/_raw_des3.pyd new file mode 100644 index 0000000..d24825e Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Cipher/_raw_des3.pyd differ diff --git a/venv/Lib/site-packages/Cryptodome/Cipher/_raw_ecb.pyd b/venv/Lib/site-packages/Cryptodome/Cipher/_raw_ecb.pyd new file mode 100644 index 0000000..2170586 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Cipher/_raw_ecb.pyd differ diff --git a/venv/Lib/site-packages/Cryptodome/Cipher/_raw_eksblowfish.pyd b/venv/Lib/site-packages/Cryptodome/Cipher/_raw_eksblowfish.pyd new file mode 100644 index 0000000..dc39ffe Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Cipher/_raw_eksblowfish.pyd differ diff --git a/venv/Lib/site-packages/Cryptodome/Cipher/_raw_ocb.pyd b/venv/Lib/site-packages/Cryptodome/Cipher/_raw_ocb.pyd new file mode 100644 index 0000000..75b5675 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Cipher/_raw_ocb.pyd differ diff --git a/venv/Lib/site-packages/Cryptodome/Cipher/_raw_ofb.pyd b/venv/Lib/site-packages/Cryptodome/Cipher/_raw_ofb.pyd new file mode 100644 index 0000000..2266fdc Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Cipher/_raw_ofb.pyd differ diff --git a/venv/Lib/site-packages/Cryptodome/Hash/BLAKE2b.py b/venv/Lib/site-packages/Cryptodome/Hash/BLAKE2b.py new file mode 100644 index 0000000..85da887 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Hash/BLAKE2b.py @@ -0,0 +1,247 @@ +# =================================================================== +# +# Copyright (c) 2014, Legrandin +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# =================================================================== + +from binascii import unhexlify + +from Cryptodome.Util.py3compat import bord, tobytes + +from Cryptodome.Random import get_random_bytes +from Cryptodome.Util._raw_api import (load_pycryptodome_raw_lib, + VoidPointer, SmartPointer, + create_string_buffer, + get_raw_buffer, c_size_t, + c_uint8_ptr) + +_raw_blake2b_lib = load_pycryptodome_raw_lib("Cryptodome.Hash._BLAKE2b", + """ + int blake2b_init(void **state, + const uint8_t *key, + size_t key_size, + size_t digest_size); + int blake2b_destroy(void *state); + int blake2b_update(void *state, + const uint8_t *buf, + size_t len); + int blake2b_digest(const void *state, + uint8_t digest[64]); + int blake2b_copy(const void *src, void *dst); + """) + + +class BLAKE2b_Hash(object): + """A BLAKE2b hash object. + Do not instantiate directly. Use the :func:`new` function. + + :ivar oid: ASN.1 Object ID + :vartype oid: string + + :ivar block_size: the size in bytes of the internal message block, + input to the compression function + :vartype block_size: integer + + :ivar digest_size: the size in bytes of the resulting hash + :vartype digest_size: integer + """ + + # The internal block size of the hash algorithm in bytes. + block_size = 64 + + def __init__(self, data, key, digest_bytes, update_after_digest): + + # The size of the resulting hash in bytes. + self.digest_size = digest_bytes + + self._update_after_digest = update_after_digest + self._digest_done = False + + # See https://tools.ietf.org/html/rfc7693 + if digest_bytes in (20, 32, 48, 64) and not key: + self.oid = "1.3.6.1.4.1.1722.12.2.1." + str(digest_bytes) + + state = VoidPointer() + result = _raw_blake2b_lib.blake2b_init(state.address_of(), + c_uint8_ptr(key), + c_size_t(len(key)), + c_size_t(digest_bytes) + ) + if result: + raise ValueError("Error %d while instantiating BLAKE2b" % result) + self._state = SmartPointer(state.get(), + _raw_blake2b_lib.blake2b_destroy) + if data: + self.update(data) + + + def update(self, data): + """Continue hashing of a message by consuming the next chunk of data. + + Args: + data (bytes/bytearray/memoryview): The next chunk of the message being hashed. + """ + + if self._digest_done and not self._update_after_digest: + raise TypeError("You can only call 'digest' or 'hexdigest' on this object") + + result = _raw_blake2b_lib.blake2b_update(self._state.get(), + c_uint8_ptr(data), + c_size_t(len(data))) + if result: + raise ValueError("Error %d while hashing BLAKE2b data" % result) + return self + + + def digest(self): + """Return the **binary** (non-printable) digest of the message that has been hashed so far. + + :return: The hash digest, computed over the data processed so far. + Binary form. + :rtype: byte string + """ + + bfr = create_string_buffer(64) + result = _raw_blake2b_lib.blake2b_digest(self._state.get(), + bfr) + if result: + raise ValueError("Error %d while creating BLAKE2b digest" % result) + + self._digest_done = True + + return get_raw_buffer(bfr)[:self.digest_size] + + + def hexdigest(self): + """Return the **printable** digest of the message that has been hashed so far. + + :return: The hash digest, computed over the data processed so far. + Hexadecimal encoded. + :rtype: string + """ + + return "".join(["%02x" % bord(x) for x in tuple(self.digest())]) + + + def verify(self, mac_tag): + """Verify that a given **binary** MAC (computed by another party) + is valid. + + Args: + mac_tag (bytes/bytearray/memoryview): the expected MAC of the message. + + Raises: + ValueError: if the MAC does not match. It means that the message + has been tampered with or that the MAC key is incorrect. + """ + + secret = get_random_bytes(16) + + mac1 = new(digest_bits=160, key=secret, data=mac_tag) + mac2 = new(digest_bits=160, key=secret, data=self.digest()) + + if mac1.digest() != mac2.digest(): + raise ValueError("MAC check failed") + + + def hexverify(self, hex_mac_tag): + """Verify that a given **printable** MAC (computed by another party) + is valid. + + Args: + hex_mac_tag (string): the expected MAC of the message, as a hexadecimal string. + + Raises: + ValueError: if the MAC does not match. It means that the message + has been tampered with or that the MAC key is incorrect. + """ + + self.verify(unhexlify(tobytes(hex_mac_tag))) + + + def new(self, **kwargs): + """Return a new instance of a BLAKE2b hash object. + See :func:`new`. + """ + + if "digest_bytes" not in kwargs and "digest_bits" not in kwargs: + kwargs["digest_bytes"] = self.digest_size + + return new(**kwargs) + + +def new(**kwargs): + """Create a new hash object. + + Args: + data (bytes/bytearray/memoryview): + Optional. The very first chunk of the message to hash. + It is equivalent to an early call to :meth:`BLAKE2b_Hash.update`. + digest_bytes (integer): + Optional. The size of the digest, in bytes (1 to 64). Default is 64. + digest_bits (integer): + Optional and alternative to ``digest_bytes``. + The size of the digest, in bits (8 to 512, in steps of 8). + Default is 512. + key (bytes/bytearray/memoryview): + Optional. The key to use to compute the MAC (1 to 64 bytes). + If not specified, no key will be used. + update_after_digest (boolean): + Optional. By default, a hash object cannot be updated anymore after + the digest is computed. When this flag is ``True``, such check + is no longer enforced. + + Returns: + A :class:`BLAKE2b_Hash` hash object + """ + + data = kwargs.pop("data", None) + update_after_digest = kwargs.pop("update_after_digest", False) + + digest_bytes = kwargs.pop("digest_bytes", None) + digest_bits = kwargs.pop("digest_bits", None) + if None not in (digest_bytes, digest_bits): + raise TypeError("Only one digest parameter must be provided") + if (None, None) == (digest_bytes, digest_bits): + digest_bytes = 64 + if digest_bytes is not None: + if not (1 <= digest_bytes <= 64): + raise ValueError("'digest_bytes' not in range 1..64") + else: + if not (8 <= digest_bits <= 512) or (digest_bits % 8): + raise ValueError("'digest_bits' not in range 8..512, " + "with steps of 8") + digest_bytes = digest_bits // 8 + + key = kwargs.pop("key", b"") + if len(key) > 64: + raise ValueError("BLAKE2b key cannot exceed 64 bytes") + + if kwargs: + raise TypeError("Unknown parameters: " + str(kwargs)) + + return BLAKE2b_Hash(data, key, digest_bytes, update_after_digest) diff --git a/venv/Lib/site-packages/Cryptodome/Hash/BLAKE2b.pyi b/venv/Lib/site-packages/Cryptodome/Hash/BLAKE2b.pyi new file mode 100644 index 0000000..d37c374 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Hash/BLAKE2b.pyi @@ -0,0 +1,32 @@ +from typing import Any, Union +from types import ModuleType + +Buffer = Union[bytes, bytearray, memoryview] + +class BLAKE2b_Hash(object): + block_size: int + digest_size: int + oid: str + + def __init__(self, + data: Buffer, + key: Buffer, + digest_bytes: bytes, + update_after_digest: bool) -> None: ... + def update(self, data: Buffer) -> BLAKE2b_Hash: ... + def digest(self) -> bytes: ... + def hexdigest(self) -> str: ... + def verify(self, mac_tag: Buffer) -> None: ... + def hexverify(self, hex_mac_tag: str) -> None: ... + def new(self, + data: Buffer = ..., + digest_bytes: int = ..., + digest_bits: int = ..., + key: Buffer = ..., + update_after_digest: bool = ...) -> BLAKE2b_Hash: ... + +def new(data: Buffer = ..., + digest_bytes: int = ..., + digest_bits: int = ..., + key: Buffer = ..., + update_after_digest: bool = ...) -> BLAKE2b_Hash: ... diff --git a/venv/Lib/site-packages/Cryptodome/Hash/BLAKE2s.py b/venv/Lib/site-packages/Cryptodome/Hash/BLAKE2s.py new file mode 100644 index 0000000..43be5c4 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Hash/BLAKE2s.py @@ -0,0 +1,247 @@ +# =================================================================== +# +# Copyright (c) 2014, Legrandin +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# =================================================================== + +from binascii import unhexlify + +from Cryptodome.Util.py3compat import bord, tobytes + +from Cryptodome.Random import get_random_bytes +from Cryptodome.Util._raw_api import (load_pycryptodome_raw_lib, + VoidPointer, SmartPointer, + create_string_buffer, + get_raw_buffer, c_size_t, + c_uint8_ptr) + +_raw_blake2s_lib = load_pycryptodome_raw_lib("Cryptodome.Hash._BLAKE2s", + """ + int blake2s_init(void **state, + const uint8_t *key, + size_t key_size, + size_t digest_size); + int blake2s_destroy(void *state); + int blake2s_update(void *state, + const uint8_t *buf, + size_t len); + int blake2s_digest(const void *state, + uint8_t digest[32]); + int blake2s_copy(const void *src, void *dst); + """) + + +class BLAKE2s_Hash(object): + """A BLAKE2s hash object. + Do not instantiate directly. Use the :func:`new` function. + + :ivar oid: ASN.1 Object ID + :vartype oid: string + + :ivar block_size: the size in bytes of the internal message block, + input to the compression function + :vartype block_size: integer + + :ivar digest_size: the size in bytes of the resulting hash + :vartype digest_size: integer + """ + + # The internal block size of the hash algorithm in bytes. + block_size = 32 + + def __init__(self, data, key, digest_bytes, update_after_digest): + + # The size of the resulting hash in bytes. + self.digest_size = digest_bytes + + self._update_after_digest = update_after_digest + self._digest_done = False + + # See https://tools.ietf.org/html/rfc7693 + if digest_bytes in (16, 20, 28, 32) and not key: + self.oid = "1.3.6.1.4.1.1722.12.2.2." + str(digest_bytes) + + state = VoidPointer() + result = _raw_blake2s_lib.blake2s_init(state.address_of(), + c_uint8_ptr(key), + c_size_t(len(key)), + c_size_t(digest_bytes) + ) + if result: + raise ValueError("Error %d while instantiating BLAKE2s" % result) + self._state = SmartPointer(state.get(), + _raw_blake2s_lib.blake2s_destroy) + if data: + self.update(data) + + + def update(self, data): + """Continue hashing of a message by consuming the next chunk of data. + + Args: + data (byte string/byte array/memoryview): The next chunk of the message being hashed. + """ + + if self._digest_done and not self._update_after_digest: + raise TypeError("You can only call 'digest' or 'hexdigest' on this object") + + result = _raw_blake2s_lib.blake2s_update(self._state.get(), + c_uint8_ptr(data), + c_size_t(len(data))) + if result: + raise ValueError("Error %d while hashing BLAKE2s data" % result) + return self + + + def digest(self): + """Return the **binary** (non-printable) digest of the message that has been hashed so far. + + :return: The hash digest, computed over the data processed so far. + Binary form. + :rtype: byte string + """ + + bfr = create_string_buffer(32) + result = _raw_blake2s_lib.blake2s_digest(self._state.get(), + bfr) + if result: + raise ValueError("Error %d while creating BLAKE2s digest" % result) + + self._digest_done = True + + return get_raw_buffer(bfr)[:self.digest_size] + + + def hexdigest(self): + """Return the **printable** digest of the message that has been hashed so far. + + :return: The hash digest, computed over the data processed so far. + Hexadecimal encoded. + :rtype: string + """ + + return "".join(["%02x" % bord(x) for x in tuple(self.digest())]) + + + def verify(self, mac_tag): + """Verify that a given **binary** MAC (computed by another party) + is valid. + + Args: + mac_tag (byte string/byte array/memoryview): the expected MAC of the message. + + Raises: + ValueError: if the MAC does not match. It means that the message + has been tampered with or that the MAC key is incorrect. + """ + + secret = get_random_bytes(16) + + mac1 = new(digest_bits=160, key=secret, data=mac_tag) + mac2 = new(digest_bits=160, key=secret, data=self.digest()) + + if mac1.digest() != mac2.digest(): + raise ValueError("MAC check failed") + + + def hexverify(self, hex_mac_tag): + """Verify that a given **printable** MAC (computed by another party) + is valid. + + Args: + hex_mac_tag (string): the expected MAC of the message, as a hexadecimal string. + + Raises: + ValueError: if the MAC does not match. It means that the message + has been tampered with or that the MAC key is incorrect. + """ + + self.verify(unhexlify(tobytes(hex_mac_tag))) + + + def new(self, **kwargs): + """Return a new instance of a BLAKE2s hash object. + See :func:`new`. + """ + + if "digest_bytes" not in kwargs and "digest_bits" not in kwargs: + kwargs["digest_bytes"] = self.digest_size + + return new(**kwargs) + + +def new(**kwargs): + """Create a new hash object. + + Args: + data (byte string/byte array/memoryview): + Optional. The very first chunk of the message to hash. + It is equivalent to an early call to :meth:`BLAKE2s_Hash.update`. + digest_bytes (integer): + Optional. The size of the digest, in bytes (1 to 32). Default is 32. + digest_bits (integer): + Optional and alternative to ``digest_bytes``. + The size of the digest, in bits (8 to 256, in steps of 8). + Default is 256. + key (byte string): + Optional. The key to use to compute the MAC (1 to 64 bytes). + If not specified, no key will be used. + update_after_digest (boolean): + Optional. By default, a hash object cannot be updated anymore after + the digest is computed. When this flag is ``True``, such check + is no longer enforced. + + Returns: + A :class:`BLAKE2s_Hash` hash object + """ + + data = kwargs.pop("data", None) + update_after_digest = kwargs.pop("update_after_digest", False) + + digest_bytes = kwargs.pop("digest_bytes", None) + digest_bits = kwargs.pop("digest_bits", None) + if None not in (digest_bytes, digest_bits): + raise TypeError("Only one digest parameter must be provided") + if (None, None) == (digest_bytes, digest_bits): + digest_bytes = 32 + if digest_bytes is not None: + if not (1 <= digest_bytes <= 32): + raise ValueError("'digest_bytes' not in range 1..32") + else: + if not (8 <= digest_bits <= 256) or (digest_bits % 8): + raise ValueError("'digest_bits' not in range 8..256, " + "with steps of 8") + digest_bytes = digest_bits // 8 + + key = kwargs.pop("key", b"") + if len(key) > 32: + raise ValueError("BLAKE2s key cannot exceed 32 bytes") + + if kwargs: + raise TypeError("Unknown parameters: " + str(kwargs)) + + return BLAKE2s_Hash(data, key, digest_bytes, update_after_digest) diff --git a/venv/Lib/site-packages/Cryptodome/Hash/BLAKE2s.pyi b/venv/Lib/site-packages/Cryptodome/Hash/BLAKE2s.pyi new file mode 100644 index 0000000..374b3a4 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Hash/BLAKE2s.pyi @@ -0,0 +1,26 @@ +from typing import Any, Union + +Buffer = Union[bytes, bytearray, memoryview] + +class BLAKE2s_Hash(object): + block_size: int + digest_size: int + oid: str + + def __init__(self, + data: Buffer, + key: Buffer, + digest_bytes: bytes, + update_after_digest: bool) -> None: ... + def update(self, data: Buffer) -> BLAKE2s_Hash: ... + def digest(self) -> bytes: ... + def hexdigest(self) -> str: ... + def verify(self, mac_tag: Buffer) -> None: ... + def hexverify(self, hex_mac_tag: str) -> None: ... + def new(self, **kwargs: Any) -> BLAKE2s_Hash: ... + +def new(data: Buffer = ..., + digest_bytes: int = ..., + digest_bits: int = ..., + key: Buffer = ..., + update_after_digest: bool = ...) -> BLAKE2s_Hash: ... diff --git a/venv/Lib/site-packages/Cryptodome/Hash/CMAC.py b/venv/Lib/site-packages/Cryptodome/Hash/CMAC.py new file mode 100644 index 0000000..8feb79f --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Hash/CMAC.py @@ -0,0 +1,306 @@ +# -*- coding: utf-8 -*- +# +# Hash/CMAC.py - Implements the CMAC algorithm +# +# =================================================================== +# The contents of this file are dedicated to the public domain. To +# the extent that dedication to the public domain is not available, +# everyone is granted a worldwide, perpetual, royalty-free, +# non-exclusive license to exercise all rights associated with the +# contents of this file for any purpose whatsoever. +# No rights are reserved. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# =================================================================== + +from binascii import unhexlify + +from Cryptodome.Hash import BLAKE2s +from Cryptodome.Util.strxor import strxor +from Cryptodome.Util.number import long_to_bytes, bytes_to_long +from Cryptodome.Util.py3compat import bord, tobytes, _copy_bytes +from Cryptodome.Random import get_random_bytes + + +# The size of the authentication tag produced by the MAC. +digest_size = None + + +def _shift_bytes(bs, xor_lsb=0): + num = (bytes_to_long(bs) << 1) ^ xor_lsb + return long_to_bytes(num, len(bs))[-len(bs):] + + +class CMAC(object): + """A CMAC hash object. + Do not instantiate directly. Use the :func:`new` function. + + :ivar digest_size: the size in bytes of the resulting MAC tag + :vartype digest_size: integer + """ + + digest_size = None + + def __init__(self, key, msg, ciphermod, cipher_params, mac_len, + update_after_digest): + + self.digest_size = mac_len + + self._key = _copy_bytes(None, None, key) + self._factory = ciphermod + self._cipher_params = cipher_params + self._block_size = bs = ciphermod.block_size + self._mac_tag = None + self._update_after_digest = update_after_digest + + # Section 5.3 of NIST SP 800 38B and Appendix B + if bs == 8: + const_Rb = 0x1B + self._max_size = 8 * (2 ** 21) + elif bs == 16: + const_Rb = 0x87 + self._max_size = 16 * (2 ** 48) + else: + raise TypeError("CMAC requires a cipher with a block size" + " of 8 or 16 bytes, not %d" % bs) + + # Compute sub-keys + zero_block = b'\x00' * bs + self._ecb = ciphermod.new(key, + ciphermod.MODE_ECB, + **self._cipher_params) + L = self._ecb.encrypt(zero_block) + if bord(L[0]) & 0x80: + self._k1 = _shift_bytes(L, const_Rb) + else: + self._k1 = _shift_bytes(L) + if bord(self._k1[0]) & 0x80: + self._k2 = _shift_bytes(self._k1, const_Rb) + else: + self._k2 = _shift_bytes(self._k1) + + # Initialize CBC cipher with zero IV + self._cbc = ciphermod.new(key, + ciphermod.MODE_CBC, + zero_block, + **self._cipher_params) + + # Cache for outstanding data to authenticate + self._cache = bytearray(bs) + self._cache_n = 0 + + # Last piece of ciphertext produced + self._last_ct = zero_block + + # Last block that was encrypted with AES + self._last_pt = None + + # Counter for total message size + self._data_size = 0 + + if msg: + self.update(msg) + + def update(self, msg): + """Authenticate the next chunk of message. + + Args: + data (byte string/byte array/memoryview): The next chunk of data + """ + + if self._mac_tag is not None and not self._update_after_digest: + raise TypeError("update() cannot be called after digest() or verify()") + + self._data_size += len(msg) + bs = self._block_size + + if self._cache_n > 0: + filler = min(bs - self._cache_n, len(msg)) + self._cache[self._cache_n:self._cache_n+filler] = msg[:filler] + self._cache_n += filler + + if self._cache_n < bs: + return self + + msg = memoryview(msg)[filler:] + self._update(self._cache) + self._cache_n = 0 + + remain = len(msg) % bs + if remain > 0: + self._update(msg[:-remain]) + self._cache[:remain] = msg[-remain:] + else: + self._update(msg) + self._cache_n = remain + return self + + def _update(self, data_block): + """Update a block aligned to the block boundary""" + + bs = self._block_size + assert len(data_block) % bs == 0 + + if len(data_block) == 0: + return + + ct = self._cbc.encrypt(data_block) + if len(data_block) == bs: + second_last = self._last_ct + else: + second_last = ct[-bs*2:-bs] + self._last_ct = ct[-bs:] + self._last_pt = strxor(second_last, data_block[-bs:]) + + def copy(self): + """Return a copy ("clone") of the CMAC object. + + The copy will have the same internal state as the original CMAC + object. + This can be used to efficiently compute the MAC tag of byte + strings that share a common initial substring. + + :return: An :class:`CMAC` + """ + + obj = self.__new__(CMAC) + obj.__dict__ = self.__dict__.copy() + obj._cbc = self._factory.new(self._key, + self._factory.MODE_CBC, + self._last_ct, + **self._cipher_params) + obj._cache = self._cache[:] + obj._last_ct = self._last_ct[:] + return obj + + def digest(self): + """Return the **binary** (non-printable) MAC tag of the message + that has been authenticated so far. + + :return: The MAC tag, computed over the data processed so far. + Binary form. + :rtype: byte string + """ + + bs = self._block_size + + if self._mac_tag is not None and not self._update_after_digest: + return self._mac_tag + + if self._data_size > self._max_size: + raise ValueError("MAC is unsafe for this message") + + if self._cache_n == 0 and self._data_size > 0: + # Last block was full + pt = strxor(self._last_pt, self._k1) + else: + # Last block is partial (or message length is zero) + partial = self._cache[:] + partial[self._cache_n:] = b'\x80' + b'\x00' * (bs - self._cache_n - 1) + pt = strxor(strxor(self._last_ct, partial), self._k2) + + self._mac_tag = self._ecb.encrypt(pt)[:self.digest_size] + + return self._mac_tag + + def hexdigest(self): + """Return the **printable** MAC tag of the message authenticated so far. + + :return: The MAC tag, computed over the data processed so far. + Hexadecimal encoded. + :rtype: string + """ + + return "".join(["%02x" % bord(x) + for x in tuple(self.digest())]) + + def verify(self, mac_tag): + """Verify that a given **binary** MAC (computed by another party) + is valid. + + Args: + mac_tag (byte string/byte array/memoryview): the expected MAC of the message. + + Raises: + ValueError: if the MAC does not match. It means that the message + has been tampered with or that the MAC key is incorrect. + """ + + secret = get_random_bytes(16) + + mac1 = BLAKE2s.new(digest_bits=160, key=secret, data=mac_tag) + mac2 = BLAKE2s.new(digest_bits=160, key=secret, data=self.digest()) + + if mac1.digest() != mac2.digest(): + raise ValueError("MAC check failed") + + def hexverify(self, hex_mac_tag): + """Verify that a given **printable** MAC (computed by another party) + is valid. + + Args: + hex_mac_tag (string): the expected MAC of the message, as a hexadecimal string. + + Raises: + ValueError: if the MAC does not match. It means that the message + has been tampered with or that the MAC key is incorrect. + """ + + self.verify(unhexlify(tobytes(hex_mac_tag))) + + +def new(key, msg=None, ciphermod=None, cipher_params=None, mac_len=None, + update_after_digest=False): + """Create a new MAC object. + + Args: + key (byte string/byte array/memoryview): + key for the CMAC object. + The key must be valid for the underlying cipher algorithm. + For instance, it must be 16 bytes long for AES-128. + ciphermod (module): + A cipher module from :mod:`Cryptodome.Cipher`. + The cipher's block size has to be 128 bits, + like :mod:`Cryptodome.Cipher.AES`, to reduce the probability + of collisions. + msg (byte string/byte array/memoryview): + Optional. The very first chunk of the message to authenticate. + It is equivalent to an early call to `CMAC.update`. Optional. + cipher_params (dict): + Optional. A set of parameters to use when instantiating a cipher + object. + mac_len (integer): + Length of the MAC, in bytes. + It must be at least 4 bytes long. + The default (and recommended) length matches the size of a cipher block. + update_after_digest (boolean): + Optional. By default, a hash object cannot be updated anymore after + the digest is computed. When this flag is ``True``, such check + is no longer enforced. + Returns: + A :class:`CMAC` object + """ + + if ciphermod is None: + raise TypeError("ciphermod must be specified (try AES)") + + cipher_params = {} if cipher_params is None else dict(cipher_params) + + if mac_len is None: + mac_len = ciphermod.block_size + + if mac_len < 4: + raise ValueError("MAC tag length must be at least 4 bytes long") + + if mac_len > ciphermod.block_size: + raise ValueError("MAC tag length cannot be larger than a cipher block (%d) bytes" % ciphermod.block_size) + + return CMAC(key, msg, ciphermod, cipher_params, mac_len, + update_after_digest) diff --git a/venv/Lib/site-packages/Cryptodome/Hash/CMAC.pyi b/venv/Lib/site-packages/Cryptodome/Hash/CMAC.pyi new file mode 100644 index 0000000..acdf055 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Hash/CMAC.pyi @@ -0,0 +1,30 @@ +from types import ModuleType +from typing import Union, Dict, Any + +Buffer = Union[bytes, bytearray, memoryview] + +digest_size: int + +class CMAC(object): + digest_size: int + + def __init__(self, + key: Buffer, + msg: Buffer, + ciphermod: ModuleType, + cipher_params: Dict[str, Any], + mac_len: int, update_after_digest: bool) -> None: ... + def update(self, data: Buffer) -> CMAC: ... + def copy(self) -> CMAC: ... + def digest(self) -> bytes: ... + def hexdigest(self) -> str: ... + def verify(self, mac_tag: Buffer) -> None: ... + def hexverify(self, hex_mac_tag: str) -> None: ... + + +def new(key: Buffer, + msg: Buffer = ..., + ciphermod: ModuleType = ..., + cipher_params: Dict[str, Any] = ..., + mac_len: int = ..., + update_after_digest: bool = ...) -> CMAC: ... diff --git a/venv/Lib/site-packages/Cryptodome/Hash/HMAC.py b/venv/Lib/site-packages/Cryptodome/Hash/HMAC.py new file mode 100644 index 0000000..615056a --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Hash/HMAC.py @@ -0,0 +1,238 @@ +# +# HMAC.py - Implements the HMAC algorithm as described by RFC 2104. +# +# =================================================================== +# +# Copyright (c) 2014, Legrandin +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# =================================================================== + +from Cryptodome.Util.py3compat import bord, tobytes + +from binascii import unhexlify + +from Cryptodome.Hash import BLAKE2s +from Cryptodome.Util.strxor import strxor +from Cryptodome.Random import get_random_bytes + +__all__ = ['new', 'HMAC'] + +_hash2hmac_oid = { + '1.3.14.3.2.26': '1.2.840.113549.2.7', # SHA-1 + '2.16.840.1.101.3.4.2.4': '1.2.840.113549.2.8', # SHA-224 + '2.16.840.1.101.3.4.2.1': '1.2.840.113549.2.9', # SHA-256 + '2.16.840.1.101.3.4.2.2': '1.2.840.113549.2.10', # SHA-384 + '2.16.840.1.101.3.4.2.3': '1.2.840.113549.2.11', # SHA-512 + '2.16.840.1.101.3.4.2.5': '1.2.840.113549.2.12', # SHA-512_224 + '2.16.840.1.101.3.4.2.6': '1.2.840.113549.2.13', # SHA-512_256 + '2.16.840.1.101.3.4.2.7': '2.16.840.1.101.3.4.2.13', # SHA-3 224 + '2.16.840.1.101.3.4.2.8': '2.16.840.1.101.3.4.2.14', # SHA-3 256 + '2.16.840.1.101.3.4.2.9': '2.16.840.1.101.3.4.2.15', # SHA-3 384 + '2.16.840.1.101.3.4.2.10': '2.16.840.1.101.3.4.2.16', # SHA-3 512 +} + +_hmac2hash_oid = {v: k for k, v in _hash2hmac_oid.items()} + + +class HMAC(object): + """An HMAC hash object. + Do not instantiate directly. Use the :func:`new` function. + + :ivar digest_size: the size in bytes of the resulting MAC tag + :vartype digest_size: integer + + :ivar oid: the ASN.1 object ID of the HMAC algorithm. + Only present if the algorithm was officially assigned one. + """ + + def __init__(self, key, msg=b"", digestmod=None): + + if digestmod is None: + from Cryptodome.Hash import MD5 + digestmod = MD5 + + if msg is None: + msg = b"" + + # Size of the MAC tag + self.digest_size = digestmod.digest_size + + self._digestmod = digestmod + + # Hash OID --> HMAC OID + try: + self.oid = _hash2hmac_oid[digestmod.oid] + except (KeyError, AttributeError): + pass + + if isinstance(key, memoryview): + key = key.tobytes() + + try: + if len(key) <= digestmod.block_size: + # Step 1 or 2 + key_0 = key + b"\x00" * (digestmod.block_size - len(key)) + else: + # Step 3 + hash_k = digestmod.new(key).digest() + key_0 = hash_k + b"\x00" * (digestmod.block_size - len(hash_k)) + except AttributeError: + # Not all hash types have "block_size" + raise ValueError("Hash type incompatible to HMAC") + + # Step 4 + key_0_ipad = strxor(key_0, b"\x36" * len(key_0)) + + # Start step 5 and 6 + self._inner = digestmod.new(key_0_ipad) + self._inner.update(msg) + + # Step 7 + key_0_opad = strxor(key_0, b"\x5c" * len(key_0)) + + # Start step 8 and 9 + self._outer = digestmod.new(key_0_opad) + + def update(self, msg): + """Authenticate the next chunk of message. + + Args: + data (byte string/byte array/memoryview): The next chunk of data + """ + + self._inner.update(msg) + return self + + def _pbkdf2_hmac_assist(self, first_digest, iterations): + """Carry out the expensive inner loop for PBKDF2-HMAC""" + + result = self._digestmod._pbkdf2_hmac_assist( + self._inner, + self._outer, + first_digest, + iterations) + return result + + def copy(self): + """Return a copy ("clone") of the HMAC object. + + The copy will have the same internal state as the original HMAC + object. + This can be used to efficiently compute the MAC tag of byte + strings that share a common initial substring. + + :return: An :class:`HMAC` + """ + + new_hmac = HMAC(b"fake key", digestmod=self._digestmod) + + # Syncronize the state + new_hmac._inner = self._inner.copy() + new_hmac._outer = self._outer.copy() + + return new_hmac + + def digest(self): + """Return the **binary** (non-printable) MAC tag of the message + authenticated so far. + + :return: The MAC tag digest, computed over the data processed so far. + Binary form. + :rtype: byte string + """ + + frozen_outer_hash = self._outer.copy() + frozen_outer_hash.update(self._inner.digest()) + return frozen_outer_hash.digest() + + def verify(self, mac_tag): + """Verify that a given **binary** MAC (computed by another party) + is valid. + + Args: + mac_tag (byte string/byte string/memoryview): the expected MAC of the message. + + Raises: + ValueError: if the MAC does not match. It means that the message + has been tampered with or that the MAC key is incorrect. + """ + + secret = get_random_bytes(16) + + mac1 = BLAKE2s.new(digest_bits=160, key=secret, data=mac_tag) + mac2 = BLAKE2s.new(digest_bits=160, key=secret, data=self.digest()) + + if mac1.digest() != mac2.digest(): + raise ValueError("MAC check failed") + + def hexdigest(self): + """Return the **printable** MAC tag of the message authenticated so far. + + :return: The MAC tag, computed over the data processed so far. + Hexadecimal encoded. + :rtype: string + """ + + return "".join(["%02x" % bord(x) + for x in tuple(self.digest())]) + + def hexverify(self, hex_mac_tag): + """Verify that a given **printable** MAC (computed by another party) + is valid. + + Args: + hex_mac_tag (string): the expected MAC of the message, + as a hexadecimal string. + + Raises: + ValueError: if the MAC does not match. It means that the message + has been tampered with or that the MAC key is incorrect. + """ + + self.verify(unhexlify(tobytes(hex_mac_tag))) + + +def new(key, msg=b"", digestmod=None): + """Create a new MAC object. + + Args: + key (bytes/bytearray/memoryview): + key for the MAC object. + It must be long enough to match the expected security level of the + MAC. + msg (bytes/bytearray/memoryview): + Optional. The very first chunk of the message to authenticate. + It is equivalent to an early call to :meth:`HMAC.update`. + digestmod (module): + The hash to use to implement the HMAC. + Default is :mod:`Cryptodome.Hash.MD5`. + + Returns: + An :class:`HMAC` object + """ + + return HMAC(key, msg, digestmod) diff --git a/venv/Lib/site-packages/Cryptodome/Hash/HMAC.pyi b/venv/Lib/site-packages/Cryptodome/Hash/HMAC.pyi new file mode 100644 index 0000000..b577230 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Hash/HMAC.pyi @@ -0,0 +1,25 @@ +from types import ModuleType +from typing import Union, Dict + +Buffer = Union[bytes, bytearray, memoryview] + +digest_size: int + +class HMAC(object): + digest_size: int + + def __init__(self, + key: Buffer, + msg: Buffer, + digestmod: ModuleType) -> None: ... + def update(self, msg: Buffer) -> HMAC: ... + def copy(self) -> HMAC: ... + def digest(self) -> bytes: ... + def hexdigest(self) -> str: ... + def verify(self, mac_tag: Buffer) -> None: ... + def hexverify(self, hex_mac_tag: str) -> None: ... + + +def new(key: Buffer, + msg: Buffer = ..., + digestmod: ModuleType = ...) -> HMAC: ... diff --git a/venv/Lib/site-packages/Cryptodome/Hash/KMAC128.py b/venv/Lib/site-packages/Cryptodome/Hash/KMAC128.py new file mode 100644 index 0000000..afd91c4 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Hash/KMAC128.py @@ -0,0 +1,179 @@ +# =================================================================== +# +# Copyright (c) 2021, Legrandin +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# =================================================================== + +from binascii import unhexlify + +from Cryptodome.Util.py3compat import bord, tobytes, is_bytes +from Cryptodome.Random import get_random_bytes + +from . import cSHAKE128, SHA3_256 +from .cSHAKE128 import _bytepad, _encode_str, _right_encode + + +class KMAC_Hash(object): + """A KMAC hash object. + Do not instantiate directly. + Use the :func:`new` function. + """ + + def __init__(self, data, key, mac_len, custom, + oid_variant, cshake, rate): + + # See https://tools.ietf.org/html/rfc8702 + self.oid = "2.16.840.1.101.3.4.2." + oid_variant + self.digest_size = mac_len + + self._mac = None + + partial_newX = _bytepad(_encode_str(tobytes(key)), rate) + self._cshake = cshake._new(partial_newX, custom, b"KMAC") + + if data: + self._cshake.update(data) + + def update(self, data): + """Authenticate the next chunk of message. + + Args: + data (bytes/bytearray/memoryview): The next chunk of the message to + authenticate. + """ + + if self._mac: + raise TypeError("You can only call 'digest' or 'hexdigest' on this object") + + self._cshake.update(data) + return self + + def digest(self): + """Return the **binary** (non-printable) MAC tag of the message. + + :return: The MAC tag. Binary form. + :rtype: byte string + """ + + if not self._mac: + self._cshake.update(_right_encode(self.digest_size * 8)) + self._mac = self._cshake.read(self.digest_size) + + return self._mac + + def hexdigest(self): + """Return the **printable** MAC tag of the message. + + :return: The MAC tag. Hexadecimal encoded. + :rtype: string + """ + + return "".join(["%02x" % bord(x) for x in tuple(self.digest())]) + + def verify(self, mac_tag): + """Verify that a given **binary** MAC (computed by another party) + is valid. + + Args: + mac_tag (bytes/bytearray/memoryview): the expected MAC of the message. + + Raises: + ValueError: if the MAC does not match. It means that the message + has been tampered with or that the MAC key is incorrect. + """ + + secret = get_random_bytes(16) + + mac1 = SHA3_256.new(secret + mac_tag) + mac2 = SHA3_256.new(secret + self.digest()) + + if mac1.digest() != mac2.digest(): + raise ValueError("MAC check failed") + + def hexverify(self, hex_mac_tag): + """Verify that a given **printable** MAC (computed by another party) + is valid. + + Args: + hex_mac_tag (string): the expected MAC of the message, as a hexadecimal string. + + Raises: + ValueError: if the MAC does not match. It means that the message + has been tampered with or that the MAC key is incorrect. + """ + + self.verify(unhexlify(tobytes(hex_mac_tag))) + + def new(self, **kwargs): + """Return a new instance of a KMAC hash object. + See :func:`new`. + """ + + if "mac_len" not in kwargs: + kwargs["mac_len"] = self.digest_size + + return new(**kwargs) + + +def new(**kwargs): + """Create a new KMAC128 object. + + Args: + key (bytes/bytearray/memoryview): + The key to use to compute the MAC. + It must be at least 128 bits long (16 bytes). + data (bytes/bytearray/memoryview): + Optional. The very first chunk of the message to authenticate. + It is equivalent to an early call to :meth:`KMAC_Hash.update`. + mac_len (integer): + Optional. The size of the authentication tag, in bytes. + Default is 64. Minimum is 8. + custom (bytes/bytearray/memoryview): + Optional. A customization byte string (``S`` in SP 800-185). + + Returns: + A :class:`KMAC_Hash` hash object + """ + + key = kwargs.pop("key", None) + if not is_bytes(key): + raise TypeError("You must pass a key to KMAC128") + if len(key) < 16: + raise ValueError("The key must be at least 128 bits long (16 bytes)") + + data = kwargs.pop("data", None) + + mac_len = kwargs.pop("mac_len", 64) + if mac_len < 8: + raise ValueError("'mac_len' must be 8 bytes or more") + + custom = kwargs.pop("custom", b"") + + if kwargs: + raise TypeError("Unknown parameters: " + str(kwargs)) + + return KMAC_Hash(data, key, mac_len, custom, "19", cSHAKE128, 168) diff --git a/venv/Lib/site-packages/Cryptodome/Hash/KMAC128.pyi b/venv/Lib/site-packages/Cryptodome/Hash/KMAC128.pyi new file mode 100644 index 0000000..8947dab --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Hash/KMAC128.pyi @@ -0,0 +1,33 @@ +from typing import Union +from types import ModuleType + +Buffer = Union[bytes, bytearray, memoryview] + +class KMAC_Hash(object): + + def __init__(self, + data: Buffer, + key: Buffer, + mac_len: int, + custom: Buffer, + oid_variant: str, + cshake: ModuleType, + rate: int) -> None: ... + + def update(self, data: Buffer) -> KMAC_Hash: ... + + def digest(self) -> bytes: ... + def hexdigest(self) -> str: ... + def verify(self, mac_tag: Buffer) -> None: ... + def hexverify(self, hex_mac_tag: str) -> None: ... + def new(self, + data: Buffer = ..., + mac_len: int = ..., + key: Buffer = ..., + custom: Buffer = ...) -> KMAC_Hash: ... + + +def new(key: Buffer, + data: Buffer = ..., + mac_len: int = ..., + custom: Buffer = ...) -> KMAC_Hash: ... diff --git a/venv/Lib/site-packages/Cryptodome/Hash/KMAC256.py b/venv/Lib/site-packages/Cryptodome/Hash/KMAC256.py new file mode 100644 index 0000000..82da062 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Hash/KMAC256.py @@ -0,0 +1,74 @@ +# =================================================================== +# +# Copyright (c) 2021, Legrandin +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# =================================================================== + +from Cryptodome.Util.py3compat import is_bytes + +from .KMAC128 import KMAC_Hash +from . import cSHAKE256 + + +def new(**kwargs): + """Create a new KMAC256 object. + + Args: + key (bytes/bytearray/memoryview): + The key to use to compute the MAC. + It must be at least 256 bits long (32 bytes). + data (bytes/bytearray/memoryview): + Optional. The very first chunk of the message to authenticate. + It is equivalent to an early call to :meth:`KMAC_Hash.update`. + mac_len (integer): + Optional. The size of the authentication tag, in bytes. + Default is 64. Minimum is 8. + custom (bytes/bytearray/memoryview): + Optional. A customization byte string (``S`` in SP 800-185). + + Returns: + A :class:`KMAC_Hash` hash object + """ + + key = kwargs.pop("key", None) + if not is_bytes(key): + raise TypeError("You must pass a key to KMAC256") + if len(key) < 32: + raise ValueError("The key must be at least 256 bits long (32 bytes)") + + data = kwargs.pop("data", None) + + mac_len = kwargs.pop("mac_len", 64) + if mac_len < 8: + raise ValueError("'mac_len' must be 8 bytes or more") + + custom = kwargs.pop("custom", b"") + + if kwargs: + raise TypeError("Unknown parameters: " + str(kwargs)) + + return KMAC_Hash(data, key, mac_len, custom, "20", cSHAKE256, 136) diff --git a/venv/Lib/site-packages/Cryptodome/Hash/KMAC256.pyi b/venv/Lib/site-packages/Cryptodome/Hash/KMAC256.pyi new file mode 100644 index 0000000..86cc500 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Hash/KMAC256.pyi @@ -0,0 +1,10 @@ +from typing import Union + +from .KMAC128 import KMAC_Hash + +Buffer = Union[bytes, bytearray, memoryview] + +def new(key: Buffer, + data: Buffer = ..., + mac_len: int = ..., + custom: Buffer = ...) -> KMAC_Hash: ... diff --git a/venv/Lib/site-packages/Cryptodome/Hash/KangarooTwelve.py b/venv/Lib/site-packages/Cryptodome/Hash/KangarooTwelve.py new file mode 100644 index 0000000..60ced57 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Hash/KangarooTwelve.py @@ -0,0 +1,222 @@ +# =================================================================== +# +# Copyright (c) 2021, Legrandin +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# =================================================================== + +from Cryptodome.Util.number import long_to_bytes +from Cryptodome.Util.py3compat import bchr + +from . import TurboSHAKE128 + +def _length_encode(x): + if x == 0: + return b'\x00' + + S = long_to_bytes(x) + return S + bchr(len(S)) + + +# Possible states for a KangarooTwelve instance, which depend on the amount of data processed so far. +SHORT_MSG = 1 # Still within the first 8192 bytes, but it is not certain we will exceed them. +LONG_MSG_S0 = 2 # Still within the first 8192 bytes, and it is certain we will exceed them. +LONG_MSG_SX = 3 # Beyond the first 8192 bytes. +SQUEEZING = 4 # No more data to process. + + +class K12_XOF(object): + """A KangarooTwelve hash object. + Do not instantiate directly. + Use the :func:`new` function. + """ + + def __init__(self, data, custom): + + if custom == None: + custom = b'' + + self._custom = custom + _length_encode(len(custom)) + self._state = SHORT_MSG + self._padding = None # Final padding is only decided in read() + + # Internal hash that consumes FinalNode + # The real domain separation byte will be known before squeezing + self._hash1 = TurboSHAKE128.new(domain=1) + self._length1 = 0 + + # Internal hash that produces CV_i (reset each time) + self._hash2 = None + self._length2 = 0 + + # Incremented by one for each 8192-byte block + self._ctr = 0 + + if data: + self.update(data) + + def update(self, data): + """Hash the next piece of data. + + .. note:: + For better performance, submit chunks with a length multiple of 8192 bytes. + + Args: + data (byte string/byte array/memoryview): The next chunk of the + message to hash. + """ + + if self._state == SQUEEZING: + raise TypeError("You cannot call 'update' after the first 'read'") + + if self._state == SHORT_MSG: + next_length = self._length1 + len(data) + + if next_length + len(self._custom) <= 8192: + self._length1 = next_length + self._hash1.update(data) + return self + + # Switch to tree hashing + self._state = LONG_MSG_S0 + + if self._state == LONG_MSG_S0: + data_mem = memoryview(data) + assert(self._length1 < 8192) + dtc = min(len(data), 8192 - self._length1) + self._hash1.update(data_mem[:dtc]) + self._length1 += dtc + + if self._length1 < 8192: + return self + + # Finish hashing S_0 and start S_1 + assert(self._length1 == 8192) + + divider = b'\x03' + b'\x00' * 7 + self._hash1.update(divider) + self._length1 += 8 + + self._hash2 = TurboSHAKE128.new(domain=0x0B) + self._length2 = 0 + self._ctr = 1 + + self._state = LONG_MSG_SX + return self.update(data_mem[dtc:]) + + # LONG_MSG_SX + assert(self._state == LONG_MSG_SX) + index = 0 + len_data = len(data) + + # All iteractions could actually run in parallel + data_mem = memoryview(data) + while index < len_data: + + new_index = min(index + 8192 - self._length2, len_data) + self._hash2.update(data_mem[index:new_index]) + self._length2 += new_index - index + index = new_index + + if self._length2 == 8192: + cv_i = self._hash2.read(32) + self._hash1.update(cv_i) + self._length1 += 32 + self._hash2._reset() + self._length2 = 0 + self._ctr += 1 + + return self + + def read(self, length): + """ + Produce more bytes of the digest. + + .. note:: + You cannot use :meth:`update` anymore after the first call to + :meth:`read`. + + Args: + length (integer): the amount of bytes this method must return + + :return: the next piece of XOF output (of the given length) + :rtype: byte string + """ + + custom_was_consumed = False + + if self._state == SHORT_MSG: + self._hash1.update(self._custom) + self._padding = 0x07 + self._state = SQUEEZING + + if self._state == LONG_MSG_S0: + self.update(self._custom) + custom_was_consumed = True + assert(self._state == LONG_MSG_SX) + + if self._state == LONG_MSG_SX: + if not custom_was_consumed: + self.update(self._custom) + + # Is there still some leftover data in hash2? + if self._length2 > 0: + cv_i = self._hash2.read(32) + self._hash1.update(cv_i) + self._length1 += 32 + self._hash2._reset() + self._length2 = 0 + self._ctr += 1 + + trailer = _length_encode(self._ctr - 1) + b'\xFF\xFF' + self._hash1.update(trailer) + + self._padding = 0x06 + self._state = SQUEEZING + + self._hash1._domain = self._padding + return self._hash1.read(length) + + def new(self, data=None, custom=b''): + return type(self)(data, custom) + + +def new(data=None, custom=None): + """Return a fresh instance of a KangarooTwelve object. + + Args: + data (bytes/bytearray/memoryview): + Optional. + The very first chunk of the message to hash. + It is equivalent to an early call to :meth:`update`. + custom (bytes): + Optional. + A customization byte string. + + :Return: A :class:`K12_XOF` object + """ + + return K12_XOF(data, custom) diff --git a/venv/Lib/site-packages/Cryptodome/Hash/KangarooTwelve.pyi b/venv/Lib/site-packages/Cryptodome/Hash/KangarooTwelve.pyi new file mode 100644 index 0000000..8b3fd74 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Hash/KangarooTwelve.pyi @@ -0,0 +1,16 @@ +from typing import Union, Optional + +Buffer = Union[bytes, bytearray, memoryview] + +class K12_XOF(object): + def __init__(self, + data: Optional[Buffer] = ..., + custom: Optional[bytes] = ...) -> None: ... + def update(self, data: Buffer) -> K12_XOF: ... + def read(self, length: int) -> bytes: ... + def new(self, + data: Optional[Buffer] = ..., + custom: Optional[bytes] = ...) -> None: ... + +def new(data: Optional[Buffer] = ..., + custom: Optional[Buffer] = ...) -> K12_XOF: ... diff --git a/venv/Lib/site-packages/Cryptodome/Hash/MD2.py b/venv/Lib/site-packages/Cryptodome/Hash/MD2.py new file mode 100644 index 0000000..47ecc05 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Hash/MD2.py @@ -0,0 +1,166 @@ +# =================================================================== +# +# Copyright (c) 2014, Legrandin +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# =================================================================== + +from Cryptodome.Util.py3compat import bord + +from Cryptodome.Util._raw_api import (load_pycryptodome_raw_lib, + VoidPointer, SmartPointer, + create_string_buffer, + get_raw_buffer, c_size_t, + c_uint8_ptr) + +_raw_md2_lib = load_pycryptodome_raw_lib( + "Cryptodome.Hash._MD2", + """ + int md2_init(void **shaState); + int md2_destroy(void *shaState); + int md2_update(void *hs, + const uint8_t *buf, + size_t len); + int md2_digest(const void *shaState, + uint8_t digest[20]); + int md2_copy(const void *src, void *dst); + """) + + +class MD2Hash(object): + """An MD2 hash object. + Do not instantiate directly. Use the :func:`new` function. + + :ivar oid: ASN.1 Object ID + :vartype oid: string + + :ivar block_size: the size in bytes of the internal message block, + input to the compression function + :vartype block_size: integer + + :ivar digest_size: the size in bytes of the resulting hash + :vartype digest_size: integer + """ + + # The size of the resulting hash in bytes. + digest_size = 16 + # The internal block size of the hash algorithm in bytes. + block_size = 16 + # ASN.1 Object ID + oid = "1.2.840.113549.2.2" + + def __init__(self, data=None): + state = VoidPointer() + result = _raw_md2_lib.md2_init(state.address_of()) + if result: + raise ValueError("Error %d while instantiating MD2" + % result) + self._state = SmartPointer(state.get(), + _raw_md2_lib.md2_destroy) + if data: + self.update(data) + + def update(self, data): + """Continue hashing of a message by consuming the next chunk of data. + + Args: + data (byte string/byte array/memoryview): The next chunk of the message being hashed. + """ + + result = _raw_md2_lib.md2_update(self._state.get(), + c_uint8_ptr(data), + c_size_t(len(data))) + if result: + raise ValueError("Error %d while instantiating MD2" + % result) + + def digest(self): + """Return the **binary** (non-printable) digest of the message that has been hashed so far. + + :return: The hash digest, computed over the data processed so far. + Binary form. + :rtype: byte string + """ + + bfr = create_string_buffer(self.digest_size) + result = _raw_md2_lib.md2_digest(self._state.get(), + bfr) + if result: + raise ValueError("Error %d while instantiating MD2" + % result) + + return get_raw_buffer(bfr) + + def hexdigest(self): + """Return the **printable** digest of the message that has been hashed so far. + + :return: The hash digest, computed over the data processed so far. + Hexadecimal encoded. + :rtype: string + """ + + return "".join(["%02x" % bord(x) for x in self.digest()]) + + def copy(self): + """Return a copy ("clone") of the hash object. + + The copy will have the same internal state as the original hash + object. + This can be used to efficiently compute the digests of strings that + share a common initial substring. + + :return: A hash object of the same type + """ + + clone = MD2Hash() + result = _raw_md2_lib.md2_copy(self._state.get(), + clone._state.get()) + if result: + raise ValueError("Error %d while copying MD2" % result) + return clone + + def new(self, data=None): + return MD2Hash(data) + + +def new(data=None): + """Create a new hash object. + + :parameter data: + Optional. The very first chunk of the message to hash. + It is equivalent to an early call to :meth:`MD2Hash.update`. + :type data: bytes/bytearray/memoryview + + :Return: A :class:`MD2Hash` hash object + """ + + return MD2Hash().new(data) + +# The size of the resulting hash in bytes. +digest_size = MD2Hash.digest_size + +# The internal block size of the hash algorithm in bytes. +block_size = MD2Hash.block_size diff --git a/venv/Lib/site-packages/Cryptodome/Hash/MD2.pyi b/venv/Lib/site-packages/Cryptodome/Hash/MD2.pyi new file mode 100644 index 0000000..95a97a9 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Hash/MD2.pyi @@ -0,0 +1,19 @@ +from typing import Union + +Buffer = Union[bytes, bytearray, memoryview] + +class MD4Hash(object): + digest_size: int + block_size: int + oid: str + + def __init__(self, data: Buffer = ...) -> None: ... + def update(self, data: Buffer) -> None: ... + def digest(self) -> bytes: ... + def hexdigest(self) -> str: ... + def copy(self) -> MD4Hash: ... + def new(self, data: Buffer = ...) -> MD4Hash: ... + +def new(data: Buffer = ...) -> MD4Hash: ... +digest_size: int +block_size: int diff --git a/venv/Lib/site-packages/Cryptodome/Hash/MD4.py b/venv/Lib/site-packages/Cryptodome/Hash/MD4.py new file mode 100644 index 0000000..668fa65 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Hash/MD4.py @@ -0,0 +1,185 @@ +# =================================================================== +# +# Copyright (c) 2014, Legrandin +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# =================================================================== + +""" +MD4 is specified in RFC1320_ and produces the 128 bit digest of a message. + + >>> from Cryptodome.Hash import MD4 + >>> + >>> h = MD4.new() + >>> h.update(b'Hello') + >>> print h.hexdigest() + +MD4 stand for Message Digest version 4, and it was invented by Rivest in 1990. +This algorithm is insecure. Do not use it for new designs. + +.. _RFC1320: http://tools.ietf.org/html/rfc1320 +""" + +from Cryptodome.Util.py3compat import bord + +from Cryptodome.Util._raw_api import (load_pycryptodome_raw_lib, + VoidPointer, SmartPointer, + create_string_buffer, + get_raw_buffer, c_size_t, + c_uint8_ptr) + +_raw_md4_lib = load_pycryptodome_raw_lib( + "Cryptodome.Hash._MD4", + """ + int md4_init(void **shaState); + int md4_destroy(void *shaState); + int md4_update(void *hs, + const uint8_t *buf, + size_t len); + int md4_digest(const void *shaState, + uint8_t digest[20]); + int md4_copy(const void *src, void *dst); + """) + + +class MD4Hash(object): + """Class that implements an MD4 hash + """ + + #: The size of the resulting hash in bytes. + digest_size = 16 + #: The internal block size of the hash algorithm in bytes. + block_size = 64 + #: ASN.1 Object ID + oid = "1.2.840.113549.2.4" + + def __init__(self, data=None): + state = VoidPointer() + result = _raw_md4_lib.md4_init(state.address_of()) + if result: + raise ValueError("Error %d while instantiating MD4" + % result) + self._state = SmartPointer(state.get(), + _raw_md4_lib.md4_destroy) + if data: + self.update(data) + + def update(self, data): + """Continue hashing of a message by consuming the next chunk of data. + + Repeated calls are equivalent to a single call with the concatenation + of all the arguments. In other words: + + >>> m.update(a); m.update(b) + + is equivalent to: + + >>> m.update(a+b) + + :Parameters: + data : byte string/byte array/memoryview + The next chunk of the message being hashed. + """ + + result = _raw_md4_lib.md4_update(self._state.get(), + c_uint8_ptr(data), + c_size_t(len(data))) + if result: + raise ValueError("Error %d while instantiating MD4" + % result) + + def digest(self): + """Return the **binary** (non-printable) digest of the message that + has been hashed so far. + + This method does not change the state of the hash object. + You can continue updating the object after calling this function. + + :Return: A byte string of `digest_size` bytes. It may contain non-ASCII + characters, including null bytes. + """ + + bfr = create_string_buffer(self.digest_size) + result = _raw_md4_lib.md4_digest(self._state.get(), + bfr) + if result: + raise ValueError("Error %d while instantiating MD4" + % result) + + return get_raw_buffer(bfr) + + def hexdigest(self): + """Return the **printable** digest of the message that has been + hashed so far. + + This method does not change the state of the hash object. + + :Return: A string of 2* `digest_size` characters. It contains only + hexadecimal ASCII digits. + """ + + return "".join(["%02x" % bord(x) for x in self.digest()]) + + def copy(self): + """Return a copy ("clone") of the hash object. + + The copy will have the same internal state as the original hash + object. + This can be used to efficiently compute the digests of strings that + share a common initial substring. + + :Return: A hash object of the same type + """ + + clone = MD4Hash() + result = _raw_md4_lib.md4_copy(self._state.get(), + clone._state.get()) + if result: + raise ValueError("Error %d while copying MD4" % result) + return clone + + def new(self, data=None): + return MD4Hash(data) + + +def new(data=None): + """Return a fresh instance of the hash object. + + :Parameters: + data : byte string/byte array/memoryview + The very first chunk of the message to hash. + It is equivalent to an early call to `MD4Hash.update()`. + Optional. + + :Return: A `MD4Hash` object + """ + return MD4Hash().new(data) + +#: The size of the resulting hash in bytes. +digest_size = MD4Hash.digest_size + +#: The internal block size of the hash algorithm in bytes. +block_size = MD4Hash.block_size diff --git a/venv/Lib/site-packages/Cryptodome/Hash/MD4.pyi b/venv/Lib/site-packages/Cryptodome/Hash/MD4.pyi new file mode 100644 index 0000000..a9a7295 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Hash/MD4.pyi @@ -0,0 +1,19 @@ +from typing import Union, Optional + +Buffer = Union[bytes, bytearray, memoryview] + +class MD4Hash(object): + digest_size: int + block_size: int + oid: str + + def __init__(self, data: Optional[Buffer] = ...) -> None: ... + def update(self, data: Buffer) -> None: ... + def digest(self) -> bytes: ... + def hexdigest(self) -> str: ... + def copy(self) -> MD4Hash: ... + def new(self, data: Optional[Buffer] = ...) -> MD4Hash: ... + +def new(data: Optional[Buffer] = ...) -> MD4Hash: ... +digest_size: int +block_size: int diff --git a/venv/Lib/site-packages/Cryptodome/Hash/MD5.py b/venv/Lib/site-packages/Cryptodome/Hash/MD5.py new file mode 100644 index 0000000..8f573a9 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Hash/MD5.py @@ -0,0 +1,184 @@ +# -*- coding: utf-8 -*- +# +# =================================================================== +# The contents of this file are dedicated to the public domain. To +# the extent that dedication to the public domain is not available, +# everyone is granted a worldwide, perpetual, royalty-free, +# non-exclusive license to exercise all rights associated with the +# contents of this file for any purpose whatsoever. +# No rights are reserved. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# =================================================================== + +from Cryptodome.Util.py3compat import * + +from Cryptodome.Util._raw_api import (load_pycryptodome_raw_lib, + VoidPointer, SmartPointer, + create_string_buffer, + get_raw_buffer, c_size_t, + c_uint8_ptr) + +_raw_md5_lib = load_pycryptodome_raw_lib("Cryptodome.Hash._MD5", + """ + #define MD5_DIGEST_SIZE 16 + + int MD5_init(void **shaState); + int MD5_destroy(void *shaState); + int MD5_update(void *hs, + const uint8_t *buf, + size_t len); + int MD5_digest(const void *shaState, + uint8_t digest[MD5_DIGEST_SIZE]); + int MD5_copy(const void *src, void *dst); + + int MD5_pbkdf2_hmac_assist(const void *inner, + const void *outer, + const uint8_t first_digest[MD5_DIGEST_SIZE], + uint8_t final_digest[MD5_DIGEST_SIZE], + size_t iterations); + """) + +class MD5Hash(object): + """A MD5 hash object. + Do not instantiate directly. + Use the :func:`new` function. + + :ivar oid: ASN.1 Object ID + :vartype oid: string + + :ivar block_size: the size in bytes of the internal message block, + input to the compression function + :vartype block_size: integer + + :ivar digest_size: the size in bytes of the resulting hash + :vartype digest_size: integer + """ + + # The size of the resulting hash in bytes. + digest_size = 16 + # The internal block size of the hash algorithm in bytes. + block_size = 64 + # ASN.1 Object ID + oid = "1.2.840.113549.2.5" + + def __init__(self, data=None): + state = VoidPointer() + result = _raw_md5_lib.MD5_init(state.address_of()) + if result: + raise ValueError("Error %d while instantiating MD5" + % result) + self._state = SmartPointer(state.get(), + _raw_md5_lib.MD5_destroy) + if data: + self.update(data) + + def update(self, data): + """Continue hashing of a message by consuming the next chunk of data. + + Args: + data (byte string/byte array/memoryview): The next chunk of the message being hashed. + """ + + result = _raw_md5_lib.MD5_update(self._state.get(), + c_uint8_ptr(data), + c_size_t(len(data))) + if result: + raise ValueError("Error %d while instantiating MD5" + % result) + + def digest(self): + """Return the **binary** (non-printable) digest of the message that has been hashed so far. + + :return: The hash digest, computed over the data processed so far. + Binary form. + :rtype: byte string + """ + + bfr = create_string_buffer(self.digest_size) + result = _raw_md5_lib.MD5_digest(self._state.get(), + bfr) + if result: + raise ValueError("Error %d while instantiating MD5" + % result) + + return get_raw_buffer(bfr) + + def hexdigest(self): + """Return the **printable** digest of the message that has been hashed so far. + + :return: The hash digest, computed over the data processed so far. + Hexadecimal encoded. + :rtype: string + """ + + return "".join(["%02x" % bord(x) for x in self.digest()]) + + def copy(self): + """Return a copy ("clone") of the hash object. + + The copy will have the same internal state as the original hash + object. + This can be used to efficiently compute the digests of strings that + share a common initial substring. + + :return: A hash object of the same type + """ + + clone = MD5Hash() + result = _raw_md5_lib.MD5_copy(self._state.get(), + clone._state.get()) + if result: + raise ValueError("Error %d while copying MD5" % result) + return clone + + def new(self, data=None): + """Create a fresh SHA-1 hash object.""" + + return MD5Hash(data) + + +def new(data=None): + """Create a new hash object. + + :parameter data: + Optional. The very first chunk of the message to hash. + It is equivalent to an early call to :meth:`MD5Hash.update`. + :type data: byte string/byte array/memoryview + + :Return: A :class:`MD5Hash` hash object + """ + return MD5Hash().new(data) + +# The size of the resulting hash in bytes. +digest_size = 16 + +# The internal block size of the hash algorithm in bytes. +block_size = 64 + + +def _pbkdf2_hmac_assist(inner, outer, first_digest, iterations): + """Compute the expensive inner loop in PBKDF-HMAC.""" + + assert len(first_digest) == digest_size + assert iterations > 0 + + bfr = create_string_buffer(digest_size); + result = _raw_md5_lib.MD5_pbkdf2_hmac_assist( + inner._state.get(), + outer._state.get(), + first_digest, + bfr, + c_size_t(iterations)) + + if result: + raise ValueError("Error %d with PBKDF2-HMAC assis for MD5" % result) + + return get_raw_buffer(bfr) diff --git a/venv/Lib/site-packages/Cryptodome/Hash/MD5.pyi b/venv/Lib/site-packages/Cryptodome/Hash/MD5.pyi new file mode 100644 index 0000000..d819556 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Hash/MD5.pyi @@ -0,0 +1,19 @@ +from typing import Union + +Buffer = Union[bytes, bytearray, memoryview] + +class MD5Hash(object): + digest_size: int + block_size: int + oid: str + + def __init__(self, data: Buffer = ...) -> None: ... + def update(self, data: Buffer) -> None: ... + def digest(self) -> bytes: ... + def hexdigest(self) -> str: ... + def copy(self) -> MD5Hash: ... + def new(self, data: Buffer = ...) -> MD5Hash: ... + +def new(data: Buffer = ...) -> MD5Hash: ... +digest_size: int +block_size: int diff --git a/venv/Lib/site-packages/Cryptodome/Hash/Poly1305.py b/venv/Lib/site-packages/Cryptodome/Hash/Poly1305.py new file mode 100644 index 0000000..c03f522 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Hash/Poly1305.py @@ -0,0 +1,217 @@ +# -*- coding: utf-8 -*- +# +# Hash/Poly1305.py - Implements the Poly1305 MAC +# +# =================================================================== +# The contents of this file are dedicated to the public domain. To +# the extent that dedication to the public domain is not available, +# everyone is granted a worldwide, perpetual, royalty-free, +# non-exclusive license to exercise all rights associated with the +# contents of this file for any purpose whatsoever. +# No rights are reserved. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# =================================================================== + +from binascii import unhexlify + +from Cryptodome.Util.py3compat import bord, tobytes, _copy_bytes + +from Cryptodome.Hash import BLAKE2s +from Cryptodome.Random import get_random_bytes +from Cryptodome.Util._raw_api import (load_pycryptodome_raw_lib, + VoidPointer, SmartPointer, + create_string_buffer, + get_raw_buffer, c_size_t, + c_uint8_ptr) + + +_raw_poly1305 = load_pycryptodome_raw_lib("Cryptodome.Hash._poly1305", + """ + int poly1305_init(void **state, + const uint8_t *r, + size_t r_len, + const uint8_t *s, + size_t s_len); + int poly1305_destroy(void *state); + int poly1305_update(void *state, + const uint8_t *in, + size_t len); + int poly1305_digest(const void *state, + uint8_t *digest, + size_t len); + """) + + +class Poly1305_MAC(object): + """An Poly1305 MAC object. + Do not instantiate directly. Use the :func:`new` function. + + :ivar digest_size: the size in bytes of the resulting MAC tag + :vartype digest_size: integer + """ + + digest_size = 16 + + def __init__(self, r, s, data): + + if len(r) != 16: + raise ValueError("Parameter r is not 16 bytes long") + if len(s) != 16: + raise ValueError("Parameter s is not 16 bytes long") + + self._mac_tag = None + + state = VoidPointer() + result = _raw_poly1305.poly1305_init(state.address_of(), + c_uint8_ptr(r), + c_size_t(len(r)), + c_uint8_ptr(s), + c_size_t(len(s)) + ) + if result: + raise ValueError("Error %d while instantiating Poly1305" % result) + self._state = SmartPointer(state.get(), + _raw_poly1305.poly1305_destroy) + if data: + self.update(data) + + def update(self, data): + """Authenticate the next chunk of message. + + Args: + data (byte string/byte array/memoryview): The next chunk of data + """ + + if self._mac_tag: + raise TypeError("You can only call 'digest' or 'hexdigest' on this object") + + result = _raw_poly1305.poly1305_update(self._state.get(), + c_uint8_ptr(data), + c_size_t(len(data))) + if result: + raise ValueError("Error %d while hashing Poly1305 data" % result) + return self + + def copy(self): + raise NotImplementedError() + + def digest(self): + """Return the **binary** (non-printable) MAC tag of the message + authenticated so far. + + :return: The MAC tag digest, computed over the data processed so far. + Binary form. + :rtype: byte string + """ + + if self._mac_tag: + return self._mac_tag + + bfr = create_string_buffer(16) + result = _raw_poly1305.poly1305_digest(self._state.get(), + bfr, + c_size_t(len(bfr))) + if result: + raise ValueError("Error %d while creating Poly1305 digest" % result) + + self._mac_tag = get_raw_buffer(bfr) + return self._mac_tag + + def hexdigest(self): + """Return the **printable** MAC tag of the message authenticated so far. + + :return: The MAC tag, computed over the data processed so far. + Hexadecimal encoded. + :rtype: string + """ + + return "".join(["%02x" % bord(x) + for x in tuple(self.digest())]) + + def verify(self, mac_tag): + """Verify that a given **binary** MAC (computed by another party) + is valid. + + Args: + mac_tag (byte string/byte string/memoryview): the expected MAC of the message. + + Raises: + ValueError: if the MAC does not match. It means that the message + has been tampered with or that the MAC key is incorrect. + """ + + secret = get_random_bytes(16) + + mac1 = BLAKE2s.new(digest_bits=160, key=secret, data=mac_tag) + mac2 = BLAKE2s.new(digest_bits=160, key=secret, data=self.digest()) + + if mac1.digest() != mac2.digest(): + raise ValueError("MAC check failed") + + def hexverify(self, hex_mac_tag): + """Verify that a given **printable** MAC (computed by another party) + is valid. + + Args: + hex_mac_tag (string): the expected MAC of the message, + as a hexadecimal string. + + Raises: + ValueError: if the MAC does not match. It means that the message + has been tampered with or that the MAC key is incorrect. + """ + + self.verify(unhexlify(tobytes(hex_mac_tag))) + + + +def new(**kwargs): + """Create a new Poly1305 MAC object. + + Args: + key (bytes/bytearray/memoryview): + The 32-byte key for the Poly1305 object. + cipher (module from ``Cryptodome.Cipher``): + The cipher algorithm to use for deriving the Poly1305 + key pair *(r, s)*. + It can only be ``Cryptodome.Cipher.AES`` or ``Cryptodome.Cipher.ChaCha20``. + nonce (bytes/bytearray/memoryview): + Optional. The non-repeatable value to use for the MAC of this message. + It must be 16 bytes long for ``AES`` and 8 or 12 bytes for ``ChaCha20``. + If not passed, a random nonce is created; you will find it in the + ``nonce`` attribute of the new object. + data (bytes/bytearray/memoryview): + Optional. The very first chunk of the message to authenticate. + It is equivalent to an early call to ``update()``. + + Returns: + A :class:`Poly1305_MAC` object + """ + + cipher = kwargs.pop("cipher", None) + if not hasattr(cipher, '_derive_Poly1305_key_pair'): + raise ValueError("Parameter 'cipher' must be AES or ChaCha20") + + cipher_key = kwargs.pop("key", None) + if cipher_key is None: + raise TypeError("You must pass a parameter 'key'") + + nonce = kwargs.pop("nonce", None) + data = kwargs.pop("data", None) + + if kwargs: + raise TypeError("Unknown parameters: " + str(kwargs)) + + r, s, nonce = cipher._derive_Poly1305_key_pair(cipher_key, nonce) + + new_mac = Poly1305_MAC(r, s, data) + new_mac.nonce = _copy_bytes(None, None, nonce) # nonce may still be just a memoryview + return new_mac diff --git a/venv/Lib/site-packages/Cryptodome/Hash/Poly1305.pyi b/venv/Lib/site-packages/Cryptodome/Hash/Poly1305.pyi new file mode 100644 index 0000000..f97a14a --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Hash/Poly1305.pyi @@ -0,0 +1,24 @@ +from types import ModuleType +from typing import Union + +Buffer = Union[bytes, bytearray, memoryview] + +class Poly1305_MAC(object): + block_size: int + digest_size: int + oid: str + + def __init__(self, + r : int, + s : int, + data : Buffer) -> None: ... + def update(self, data: Buffer) -> Poly1305_MAC: ... + def digest(self) -> bytes: ... + def hexdigest(self) -> str: ... + def verify(self, mac_tag: Buffer) -> None: ... + def hexverify(self, hex_mac_tag: str) -> None: ... + +def new(key: Buffer, + cipher: ModuleType, + nonce: Buffer = ..., + data: Buffer = ...) -> Poly1305_MAC: ... diff --git a/venv/Lib/site-packages/Cryptodome/Hash/RIPEMD.py b/venv/Lib/site-packages/Cryptodome/Hash/RIPEMD.py new file mode 100644 index 0000000..35ad576 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Hash/RIPEMD.py @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- +# +# =================================================================== +# The contents of this file are dedicated to the public domain. To +# the extent that dedication to the public domain is not available, +# everyone is granted a worldwide, perpetual, royalty-free, +# non-exclusive license to exercise all rights associated with the +# contents of this file for any purpose whatsoever. +# No rights are reserved. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# =================================================================== + +# This file exists for backward compatibility with old code that refers to +# Cryptodome.Hash.RIPEMD + +"""Deprecated alias for `Cryptodome.Hash.RIPEMD160`""" + +from Cryptodome.Hash.RIPEMD160 import new, block_size, digest_size diff --git a/venv/Lib/site-packages/Cryptodome/Hash/RIPEMD.pyi b/venv/Lib/site-packages/Cryptodome/Hash/RIPEMD.pyi new file mode 100644 index 0000000..cfb2252 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Hash/RIPEMD.pyi @@ -0,0 +1,3 @@ +# This file exists for backward compatibility with old code that refers to +# Cryptodome.Hash.SHA + diff --git a/venv/Lib/site-packages/Cryptodome/Hash/RIPEMD160.py b/venv/Lib/site-packages/Cryptodome/Hash/RIPEMD160.py new file mode 100644 index 0000000..f959027 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Hash/RIPEMD160.py @@ -0,0 +1,169 @@ +# =================================================================== +# +# Copyright (c) 2014, Legrandin +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# =================================================================== + +from Cryptodome.Util.py3compat import bord + +from Cryptodome.Util._raw_api import (load_pycryptodome_raw_lib, + VoidPointer, SmartPointer, + create_string_buffer, + get_raw_buffer, c_size_t, + c_uint8_ptr) + +_raw_ripemd160_lib = load_pycryptodome_raw_lib( + "Cryptodome.Hash._RIPEMD160", + """ + int ripemd160_init(void **shaState); + int ripemd160_destroy(void *shaState); + int ripemd160_update(void *hs, + const uint8_t *buf, + size_t len); + int ripemd160_digest(const void *shaState, + uint8_t digest[20]); + int ripemd160_copy(const void *src, void *dst); + """) + + +class RIPEMD160Hash(object): + """A RIPEMD-160 hash object. + Do not instantiate directly. + Use the :func:`new` function. + + :ivar oid: ASN.1 Object ID + :vartype oid: string + + :ivar block_size: the size in bytes of the internal message block, + input to the compression function + :vartype block_size: integer + + :ivar digest_size: the size in bytes of the resulting hash + :vartype digest_size: integer + """ + + # The size of the resulting hash in bytes. + digest_size = 20 + # The internal block size of the hash algorithm in bytes. + block_size = 64 + # ASN.1 Object ID + oid = "1.3.36.3.2.1" + + def __init__(self, data=None): + state = VoidPointer() + result = _raw_ripemd160_lib.ripemd160_init(state.address_of()) + if result: + raise ValueError("Error %d while instantiating RIPEMD160" + % result) + self._state = SmartPointer(state.get(), + _raw_ripemd160_lib.ripemd160_destroy) + if data: + self.update(data) + + def update(self, data): + """Continue hashing of a message by consuming the next chunk of data. + + Args: + data (byte string/byte array/memoryview): The next chunk of the message being hashed. + """ + + result = _raw_ripemd160_lib.ripemd160_update(self._state.get(), + c_uint8_ptr(data), + c_size_t(len(data))) + if result: + raise ValueError("Error %d while instantiating ripemd160" + % result) + + def digest(self): + """Return the **binary** (non-printable) digest of the message that has been hashed so far. + + :return: The hash digest, computed over the data processed so far. + Binary form. + :rtype: byte string + """ + + bfr = create_string_buffer(self.digest_size) + result = _raw_ripemd160_lib.ripemd160_digest(self._state.get(), + bfr) + if result: + raise ValueError("Error %d while instantiating ripemd160" + % result) + + return get_raw_buffer(bfr) + + def hexdigest(self): + """Return the **printable** digest of the message that has been hashed so far. + + :return: The hash digest, computed over the data processed so far. + Hexadecimal encoded. + :rtype: string + """ + + return "".join(["%02x" % bord(x) for x in self.digest()]) + + def copy(self): + """Return a copy ("clone") of the hash object. + + The copy will have the same internal state as the original hash + object. + This can be used to efficiently compute the digests of strings that + share a common initial substring. + + :return: A hash object of the same type + """ + + clone = RIPEMD160Hash() + result = _raw_ripemd160_lib.ripemd160_copy(self._state.get(), + clone._state.get()) + if result: + raise ValueError("Error %d while copying ripemd160" % result) + return clone + + def new(self, data=None): + """Create a fresh RIPEMD-160 hash object.""" + + return RIPEMD160Hash(data) + + +def new(data=None): + """Create a new hash object. + + :parameter data: + Optional. The very first chunk of the message to hash. + It is equivalent to an early call to :meth:`RIPEMD160Hash.update`. + :type data: byte string/byte array/memoryview + + :Return: A :class:`RIPEMD160Hash` hash object + """ + + return RIPEMD160Hash().new(data) + +# The size of the resulting hash in bytes. +digest_size = RIPEMD160Hash.digest_size + +# The internal block size of the hash algorithm in bytes. +block_size = RIPEMD160Hash.block_size diff --git a/venv/Lib/site-packages/Cryptodome/Hash/RIPEMD160.pyi b/venv/Lib/site-packages/Cryptodome/Hash/RIPEMD160.pyi new file mode 100644 index 0000000..b619473 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Hash/RIPEMD160.pyi @@ -0,0 +1,19 @@ +from typing import Union + +Buffer = Union[bytes, bytearray, memoryview] + +class RIPEMD160Hash(object): + digest_size: int + block_size: int + oid: str + + def __init__(self, data: Buffer = ...) -> None: ... + def update(self, data: Buffer) -> None: ... + def digest(self) -> bytes: ... + def hexdigest(self) -> str: ... + def copy(self) -> RIPEMD160Hash: ... + def new(self, data: Buffer = ...) -> RIPEMD160Hash: ... + +def new(data: Buffer = ...) -> RIPEMD160Hash: ... +digest_size: int +block_size: int diff --git a/venv/Lib/site-packages/Cryptodome/Hash/SHA.py b/venv/Lib/site-packages/Cryptodome/Hash/SHA.py new file mode 100644 index 0000000..95f8745 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Hash/SHA.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- +# +# =================================================================== +# The contents of this file are dedicated to the public domain. To +# the extent that dedication to the public domain is not available, +# everyone is granted a worldwide, perpetual, royalty-free, +# non-exclusive license to exercise all rights associated with the +# contents of this file for any purpose whatsoever. +# No rights are reserved. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# =================================================================== + +# This file exists for backward compatibility with old code that refers to +# Cryptodome.Hash.SHA + +from Cryptodome.Hash.SHA1 import __doc__, new, block_size, digest_size diff --git a/venv/Lib/site-packages/Cryptodome/Hash/SHA.pyi b/venv/Lib/site-packages/Cryptodome/Hash/SHA.pyi new file mode 100644 index 0000000..7d01a5f --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Hash/SHA.pyi @@ -0,0 +1,4 @@ +# This file exists for backward compatibility with old code that refers to +# Cryptodome.Hash.SHA + +from Cryptodome.Hash.SHA1 import __doc__, new, block_size, digest_size diff --git a/venv/Lib/site-packages/Cryptodome/Hash/SHA1.py b/venv/Lib/site-packages/Cryptodome/Hash/SHA1.py new file mode 100644 index 0000000..dea51bc --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Hash/SHA1.py @@ -0,0 +1,185 @@ +# -*- coding: utf-8 -*- +# +# =================================================================== +# The contents of this file are dedicated to the public domain. To +# the extent that dedication to the public domain is not available, +# everyone is granted a worldwide, perpetual, royalty-free, +# non-exclusive license to exercise all rights associated with the +# contents of this file for any purpose whatsoever. +# No rights are reserved. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# =================================================================== + +from Cryptodome.Util.py3compat import * + +from Cryptodome.Util._raw_api import (load_pycryptodome_raw_lib, + VoidPointer, SmartPointer, + create_string_buffer, + get_raw_buffer, c_size_t, + c_uint8_ptr) + +_raw_sha1_lib = load_pycryptodome_raw_lib("Cryptodome.Hash._SHA1", + """ + #define SHA1_DIGEST_SIZE 20 + + int SHA1_init(void **shaState); + int SHA1_destroy(void *shaState); + int SHA1_update(void *hs, + const uint8_t *buf, + size_t len); + int SHA1_digest(const void *shaState, + uint8_t digest[SHA1_DIGEST_SIZE]); + int SHA1_copy(const void *src, void *dst); + + int SHA1_pbkdf2_hmac_assist(const void *inner, + const void *outer, + const uint8_t first_digest[SHA1_DIGEST_SIZE], + uint8_t final_digest[SHA1_DIGEST_SIZE], + size_t iterations); + """) + +class SHA1Hash(object): + """A SHA-1 hash object. + Do not instantiate directly. + Use the :func:`new` function. + + :ivar oid: ASN.1 Object ID + :vartype oid: string + + :ivar block_size: the size in bytes of the internal message block, + input to the compression function + :vartype block_size: integer + + :ivar digest_size: the size in bytes of the resulting hash + :vartype digest_size: integer + """ + + # The size of the resulting hash in bytes. + digest_size = 20 + # The internal block size of the hash algorithm in bytes. + block_size = 64 + # ASN.1 Object ID + oid = "1.3.14.3.2.26" + + def __init__(self, data=None): + state = VoidPointer() + result = _raw_sha1_lib.SHA1_init(state.address_of()) + if result: + raise ValueError("Error %d while instantiating SHA1" + % result) + self._state = SmartPointer(state.get(), + _raw_sha1_lib.SHA1_destroy) + if data: + self.update(data) + + def update(self, data): + """Continue hashing of a message by consuming the next chunk of data. + + Args: + data (byte string/byte array/memoryview): The next chunk of the message being hashed. + """ + + result = _raw_sha1_lib.SHA1_update(self._state.get(), + c_uint8_ptr(data), + c_size_t(len(data))) + if result: + raise ValueError("Error %d while instantiating SHA1" + % result) + + def digest(self): + """Return the **binary** (non-printable) digest of the message that has been hashed so far. + + :return: The hash digest, computed over the data processed so far. + Binary form. + :rtype: byte string + """ + + bfr = create_string_buffer(self.digest_size) + result = _raw_sha1_lib.SHA1_digest(self._state.get(), + bfr) + if result: + raise ValueError("Error %d while instantiating SHA1" + % result) + + return get_raw_buffer(bfr) + + def hexdigest(self): + """Return the **printable** digest of the message that has been hashed so far. + + :return: The hash digest, computed over the data processed so far. + Hexadecimal encoded. + :rtype: string + """ + + return "".join(["%02x" % bord(x) for x in self.digest()]) + + def copy(self): + """Return a copy ("clone") of the hash object. + + The copy will have the same internal state as the original hash + object. + This can be used to efficiently compute the digests of strings that + share a common initial substring. + + :return: A hash object of the same type + """ + + clone = SHA1Hash() + result = _raw_sha1_lib.SHA1_copy(self._state.get(), + clone._state.get()) + if result: + raise ValueError("Error %d while copying SHA1" % result) + return clone + + def new(self, data=None): + """Create a fresh SHA-1 hash object.""" + + return SHA1Hash(data) + + +def new(data=None): + """Create a new hash object. + + :parameter data: + Optional. The very first chunk of the message to hash. + It is equivalent to an early call to :meth:`SHA1Hash.update`. + :type data: byte string/byte array/memoryview + + :Return: A :class:`SHA1Hash` hash object + """ + return SHA1Hash().new(data) + + +# The size of the resulting hash in bytes. +digest_size = SHA1Hash.digest_size + +# The internal block size of the hash algorithm in bytes. +block_size = SHA1Hash.block_size + + +def _pbkdf2_hmac_assist(inner, outer, first_digest, iterations): + """Compute the expensive inner loop in PBKDF-HMAC.""" + + assert len(first_digest) == digest_size + assert iterations > 0 + + bfr = create_string_buffer(digest_size); + result = _raw_sha1_lib.SHA1_pbkdf2_hmac_assist( + inner._state.get(), + outer._state.get(), + first_digest, + bfr, + c_size_t(iterations)) + + if result: + raise ValueError("Error %d with PBKDF2-HMAC assis for SHA1" % result) + + return get_raw_buffer(bfr) diff --git a/venv/Lib/site-packages/Cryptodome/Hash/SHA1.pyi b/venv/Lib/site-packages/Cryptodome/Hash/SHA1.pyi new file mode 100644 index 0000000..d6c8e25 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Hash/SHA1.pyi @@ -0,0 +1,19 @@ +from typing import Union, Optional + +Buffer = Union[bytes, bytearray, memoryview] + +class SHA1Hash(object): + digest_size: int + block_size: int + oid: str + + def __init__(self, data: Optional[Buffer] = ...) -> None: ... + def update(self, data: Buffer) -> None: ... + def digest(self) -> bytes: ... + def hexdigest(self) -> str: ... + def copy(self) -> SHA1Hash: ... + def new(self, data: Optional[Buffer] = ...) -> SHA1Hash: ... + +def new(data: Optional[Buffer] = ...) -> SHA1Hash: ... +digest_size: int +block_size: int diff --git a/venv/Lib/site-packages/Cryptodome/Hash/SHA224.py b/venv/Lib/site-packages/Cryptodome/Hash/SHA224.py new file mode 100644 index 0000000..fca7622 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Hash/SHA224.py @@ -0,0 +1,186 @@ +# -*- coding: utf-8 -*- +# +# =================================================================== +# The contents of this file are dedicated to the public domain. To +# the extent that dedication to the public domain is not available, +# everyone is granted a worldwide, perpetual, royalty-free, +# non-exclusive license to exercise all rights associated with the +# contents of this file for any purpose whatsoever. +# No rights are reserved. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# =================================================================== + +from Cryptodome.Util.py3compat import bord + +from Cryptodome.Util._raw_api import (load_pycryptodome_raw_lib, + VoidPointer, SmartPointer, + create_string_buffer, + get_raw_buffer, c_size_t, + c_uint8_ptr) + +_raw_sha224_lib = load_pycryptodome_raw_lib("Cryptodome.Hash._SHA224", + """ + int SHA224_init(void **shaState); + int SHA224_destroy(void *shaState); + int SHA224_update(void *hs, + const uint8_t *buf, + size_t len); + int SHA224_digest(const void *shaState, + uint8_t *digest, + size_t digest_size); + int SHA224_copy(const void *src, void *dst); + + int SHA224_pbkdf2_hmac_assist(const void *inner, + const void *outer, + const uint8_t *first_digest, + uint8_t *final_digest, + size_t iterations, + size_t digest_size); + """) + +class SHA224Hash(object): + """A SHA-224 hash object. + Do not instantiate directly. + Use the :func:`new` function. + + :ivar oid: ASN.1 Object ID + :vartype oid: string + + :ivar block_size: the size in bytes of the internal message block, + input to the compression function + :vartype block_size: integer + + :ivar digest_size: the size in bytes of the resulting hash + :vartype digest_size: integer + """ + + # The size of the resulting hash in bytes. + digest_size = 28 + # The internal block size of the hash algorithm in bytes. + block_size = 64 + # ASN.1 Object ID + oid = '2.16.840.1.101.3.4.2.4' + + def __init__(self, data=None): + state = VoidPointer() + result = _raw_sha224_lib.SHA224_init(state.address_of()) + if result: + raise ValueError("Error %d while instantiating SHA224" + % result) + self._state = SmartPointer(state.get(), + _raw_sha224_lib.SHA224_destroy) + if data: + self.update(data) + + def update(self, data): + """Continue hashing of a message by consuming the next chunk of data. + + Args: + data (byte string/byte array/memoryview): The next chunk of the message being hashed. + """ + + result = _raw_sha224_lib.SHA224_update(self._state.get(), + c_uint8_ptr(data), + c_size_t(len(data))) + if result: + raise ValueError("Error %d while hashing data with SHA224" + % result) + + def digest(self): + """Return the **binary** (non-printable) digest of the message that has been hashed so far. + + :return: The hash digest, computed over the data processed so far. + Binary form. + :rtype: byte string + """ + + bfr = create_string_buffer(self.digest_size) + result = _raw_sha224_lib.SHA224_digest(self._state.get(), + bfr, + c_size_t(self.digest_size)) + if result: + raise ValueError("Error %d while making SHA224 digest" + % result) + + return get_raw_buffer(bfr) + + def hexdigest(self): + """Return the **printable** digest of the message that has been hashed so far. + + :return: The hash digest, computed over the data processed so far. + Hexadecimal encoded. + :rtype: string + """ + + return "".join(["%02x" % bord(x) for x in self.digest()]) + + def copy(self): + """Return a copy ("clone") of the hash object. + + The copy will have the same internal state as the original hash + object. + This can be used to efficiently compute the digests of strings that + share a common initial substring. + + :return: A hash object of the same type + """ + + clone = SHA224Hash() + result = _raw_sha224_lib.SHA224_copy(self._state.get(), + clone._state.get()) + if result: + raise ValueError("Error %d while copying SHA224" % result) + return clone + + def new(self, data=None): + """Create a fresh SHA-224 hash object.""" + + return SHA224Hash(data) + + +def new(data=None): + """Create a new hash object. + + :parameter data: + Optional. The very first chunk of the message to hash. + It is equivalent to an early call to :meth:`SHA224Hash.update`. + :type data: byte string/byte array/memoryview + + :Return: A :class:`SHA224Hash` hash object + """ + return SHA224Hash().new(data) + + +# The size of the resulting hash in bytes. +digest_size = SHA224Hash.digest_size + +# The internal block size of the hash algorithm in bytes. +block_size = SHA224Hash.block_size + + +def _pbkdf2_hmac_assist(inner, outer, first_digest, iterations): + """Compute the expensive inner loop in PBKDF-HMAC.""" + + assert iterations > 0 + + bfr = create_string_buffer(len(first_digest)); + result = _raw_sha224_lib.SHA224_pbkdf2_hmac_assist( + inner._state.get(), + outer._state.get(), + first_digest, + bfr, + c_size_t(iterations), + c_size_t(len(first_digest))) + + if result: + raise ValueError("Error %d with PBKDF2-HMAC assist for SHA224" % result) + + return get_raw_buffer(bfr) diff --git a/venv/Lib/site-packages/Cryptodome/Hash/SHA224.pyi b/venv/Lib/site-packages/Cryptodome/Hash/SHA224.pyi new file mode 100644 index 0000000..613a7f9 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Hash/SHA224.pyi @@ -0,0 +1,19 @@ +from typing import Union, Optional + +Buffer = Union[bytes, bytearray, memoryview] + +class SHA224Hash(object): + digest_size: int + block_size: int + oid: str + + def __init__(self, data: Optional[Buffer] = ...) -> None: ... + def update(self, data: Buffer) -> None: ... + def digest(self) -> bytes: ... + def hexdigest(self) -> str: ... + def copy(self) -> SHA224Hash: ... + def new(self, data: Optional[Buffer] = ...) -> SHA224Hash: ... + +def new(data: Optional[Buffer] = ...) -> SHA224Hash: ... +digest_size: int +block_size: int diff --git a/venv/Lib/site-packages/Cryptodome/Hash/SHA256.py b/venv/Lib/site-packages/Cryptodome/Hash/SHA256.py new file mode 100644 index 0000000..c1a81b1 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Hash/SHA256.py @@ -0,0 +1,185 @@ +# -*- coding: utf-8 -*- +# +# =================================================================== +# The contents of this file are dedicated to the public domain. To +# the extent that dedication to the public domain is not available, +# everyone is granted a worldwide, perpetual, royalty-free, +# non-exclusive license to exercise all rights associated with the +# contents of this file for any purpose whatsoever. +# No rights are reserved. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# =================================================================== + +from Cryptodome.Util.py3compat import bord + +from Cryptodome.Util._raw_api import (load_pycryptodome_raw_lib, + VoidPointer, SmartPointer, + create_string_buffer, + get_raw_buffer, c_size_t, + c_uint8_ptr) + +_raw_sha256_lib = load_pycryptodome_raw_lib("Cryptodome.Hash._SHA256", + """ + int SHA256_init(void **shaState); + int SHA256_destroy(void *shaState); + int SHA256_update(void *hs, + const uint8_t *buf, + size_t len); + int SHA256_digest(const void *shaState, + uint8_t *digest, + size_t digest_size); + int SHA256_copy(const void *src, void *dst); + + int SHA256_pbkdf2_hmac_assist(const void *inner, + const void *outer, + const uint8_t *first_digest, + uint8_t *final_digest, + size_t iterations, + size_t digest_size); + """) + +class SHA256Hash(object): + """A SHA-256 hash object. + Do not instantiate directly. Use the :func:`new` function. + + :ivar oid: ASN.1 Object ID + :vartype oid: string + + :ivar block_size: the size in bytes of the internal message block, + input to the compression function + :vartype block_size: integer + + :ivar digest_size: the size in bytes of the resulting hash + :vartype digest_size: integer + """ + + # The size of the resulting hash in bytes. + digest_size = 32 + # The internal block size of the hash algorithm in bytes. + block_size = 64 + # ASN.1 Object ID + oid = "2.16.840.1.101.3.4.2.1" + + def __init__(self, data=None): + state = VoidPointer() + result = _raw_sha256_lib.SHA256_init(state.address_of()) + if result: + raise ValueError("Error %d while instantiating SHA256" + % result) + self._state = SmartPointer(state.get(), + _raw_sha256_lib.SHA256_destroy) + if data: + self.update(data) + + def update(self, data): + """Continue hashing of a message by consuming the next chunk of data. + + Args: + data (byte string/byte array/memoryview): The next chunk of the message being hashed. + """ + + result = _raw_sha256_lib.SHA256_update(self._state.get(), + c_uint8_ptr(data), + c_size_t(len(data))) + if result: + raise ValueError("Error %d while hashing data with SHA256" + % result) + + def digest(self): + """Return the **binary** (non-printable) digest of the message that has been hashed so far. + + :return: The hash digest, computed over the data processed so far. + Binary form. + :rtype: byte string + """ + + bfr = create_string_buffer(self.digest_size) + result = _raw_sha256_lib.SHA256_digest(self._state.get(), + bfr, + c_size_t(self.digest_size)) + if result: + raise ValueError("Error %d while making SHA256 digest" + % result) + + return get_raw_buffer(bfr) + + def hexdigest(self): + """Return the **printable** digest of the message that has been hashed so far. + + :return: The hash digest, computed over the data processed so far. + Hexadecimal encoded. + :rtype: string + """ + + return "".join(["%02x" % bord(x) for x in self.digest()]) + + def copy(self): + """Return a copy ("clone") of the hash object. + + The copy will have the same internal state as the original hash + object. + This can be used to efficiently compute the digests of strings that + share a common initial substring. + + :return: A hash object of the same type + """ + + clone = SHA256Hash() + result = _raw_sha256_lib.SHA256_copy(self._state.get(), + clone._state.get()) + if result: + raise ValueError("Error %d while copying SHA256" % result) + return clone + + def new(self, data=None): + """Create a fresh SHA-256 hash object.""" + + return SHA256Hash(data) + +def new(data=None): + """Create a new hash object. + + :parameter data: + Optional. The very first chunk of the message to hash. + It is equivalent to an early call to :meth:`SHA256Hash.update`. + :type data: byte string/byte array/memoryview + + :Return: A :class:`SHA256Hash` hash object + """ + + return SHA256Hash().new(data) + + +# The size of the resulting hash in bytes. +digest_size = SHA256Hash.digest_size + +# The internal block size of the hash algorithm in bytes. +block_size = SHA256Hash.block_size + + +def _pbkdf2_hmac_assist(inner, outer, first_digest, iterations): + """Compute the expensive inner loop in PBKDF-HMAC.""" + + assert iterations > 0 + + bfr = create_string_buffer(len(first_digest)); + result = _raw_sha256_lib.SHA256_pbkdf2_hmac_assist( + inner._state.get(), + outer._state.get(), + first_digest, + bfr, + c_size_t(iterations), + c_size_t(len(first_digest))) + + if result: + raise ValueError("Error %d with PBKDF2-HMAC assist for SHA256" % result) + + return get_raw_buffer(bfr) diff --git a/venv/Lib/site-packages/Cryptodome/Hash/SHA256.pyi b/venv/Lib/site-packages/Cryptodome/Hash/SHA256.pyi new file mode 100644 index 0000000..cbf21bf --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Hash/SHA256.pyi @@ -0,0 +1,18 @@ +from typing import Union, Optional + + +class SHA256Hash(object): + digest_size: int + block_size: int + oid: str + def __init__(self, data: Optional[Union[bytes, bytearray, memoryview]]=None) -> None: ... + def update(self, data: Union[bytes, bytearray, memoryview]) -> None: ... + def digest(self) -> bytes: ... + def hexdigest(self) -> str: ... + def copy(self) -> SHA256Hash: ... + def new(self, data: Optional[Union[bytes, bytearray, memoryview]]=None) -> SHA256Hash: ... + +def new(data: Optional[Union[bytes, bytearray, memoryview]]=None) -> SHA256Hash: ... + +digest_size: int +block_size: int diff --git a/venv/Lib/site-packages/Cryptodome/Hash/SHA384.py b/venv/Lib/site-packages/Cryptodome/Hash/SHA384.py new file mode 100644 index 0000000..711aa73 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Hash/SHA384.py @@ -0,0 +1,186 @@ +# -*- coding: utf-8 -*- +# +# =================================================================== +# The contents of this file are dedicated to the public domain. To +# the extent that dedication to the public domain is not available, +# everyone is granted a worldwide, perpetual, royalty-free, +# non-exclusive license to exercise all rights associated with the +# contents of this file for any purpose whatsoever. +# No rights are reserved. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# =================================================================== + +from Cryptodome.Util.py3compat import bord + +from Cryptodome.Util._raw_api import (load_pycryptodome_raw_lib, + VoidPointer, SmartPointer, + create_string_buffer, + get_raw_buffer, c_size_t, + c_uint8_ptr) + +_raw_sha384_lib = load_pycryptodome_raw_lib("Cryptodome.Hash._SHA384", + """ + int SHA384_init(void **shaState); + int SHA384_destroy(void *shaState); + int SHA384_update(void *hs, + const uint8_t *buf, + size_t len); + int SHA384_digest(const void *shaState, + uint8_t *digest, + size_t digest_size); + int SHA384_copy(const void *src, void *dst); + + int SHA384_pbkdf2_hmac_assist(const void *inner, + const void *outer, + const uint8_t *first_digest, + uint8_t *final_digest, + size_t iterations, + size_t digest_size); + """) + +class SHA384Hash(object): + """A SHA-384 hash object. + Do not instantiate directly. Use the :func:`new` function. + + :ivar oid: ASN.1 Object ID + :vartype oid: string + + :ivar block_size: the size in bytes of the internal message block, + input to the compression function + :vartype block_size: integer + + :ivar digest_size: the size in bytes of the resulting hash + :vartype digest_size: integer + """ + + # The size of the resulting hash in bytes. + digest_size = 48 + # The internal block size of the hash algorithm in bytes. + block_size = 128 + # ASN.1 Object ID + oid = '2.16.840.1.101.3.4.2.2' + + def __init__(self, data=None): + state = VoidPointer() + result = _raw_sha384_lib.SHA384_init(state.address_of()) + if result: + raise ValueError("Error %d while instantiating SHA384" + % result) + self._state = SmartPointer(state.get(), + _raw_sha384_lib.SHA384_destroy) + if data: + self.update(data) + + def update(self, data): + """Continue hashing of a message by consuming the next chunk of data. + + Args: + data (byte string/byte array/memoryview): The next chunk of the message being hashed. + """ + + result = _raw_sha384_lib.SHA384_update(self._state.get(), + c_uint8_ptr(data), + c_size_t(len(data))) + if result: + raise ValueError("Error %d while hashing data with SHA384" + % result) + + def digest(self): + """Return the **binary** (non-printable) digest of the message that has been hashed so far. + + :return: The hash digest, computed over the data processed so far. + Binary form. + :rtype: byte string + """ + + bfr = create_string_buffer(self.digest_size) + result = _raw_sha384_lib.SHA384_digest(self._state.get(), + bfr, + c_size_t(self.digest_size)) + if result: + raise ValueError("Error %d while making SHA384 digest" + % result) + + return get_raw_buffer(bfr) + + def hexdigest(self): + """Return the **printable** digest of the message that has been hashed so far. + + :return: The hash digest, computed over the data processed so far. + Hexadecimal encoded. + :rtype: string + """ + + return "".join(["%02x" % bord(x) for x in self.digest()]) + + def copy(self): + """Return a copy ("clone") of the hash object. + + The copy will have the same internal state as the original hash + object. + This can be used to efficiently compute the digests of strings that + share a common initial substring. + + :return: A hash object of the same type + """ + + clone = SHA384Hash() + result = _raw_sha384_lib.SHA384_copy(self._state.get(), + clone._state.get()) + if result: + raise ValueError("Error %d while copying SHA384" % result) + return clone + + def new(self, data=None): + """Create a fresh SHA-384 hash object.""" + + return SHA384Hash(data) + + +def new(data=None): + """Create a new hash object. + + :parameter data: + Optional. The very first chunk of the message to hash. + It is equivalent to an early call to :meth:`SHA384Hash.update`. + :type data: byte string/byte array/memoryview + + :Return: A :class:`SHA384Hash` hash object + """ + + return SHA384Hash().new(data) + + +# The size of the resulting hash in bytes. +digest_size = SHA384Hash.digest_size + +# The internal block size of the hash algorithm in bytes. +block_size = SHA384Hash.block_size + + +def _pbkdf2_hmac_assist(inner, outer, first_digest, iterations): + """Compute the expensive inner loop in PBKDF-HMAC.""" + + assert iterations > 0 + + bfr = create_string_buffer(len(first_digest)); + result = _raw_sha384_lib.SHA384_pbkdf2_hmac_assist( + inner._state.get(), + outer._state.get(), + first_digest, + bfr, + c_size_t(iterations), + c_size_t(len(first_digest))) + + if result: + raise ValueError("Error %d with PBKDF2-HMAC assist for SHA384" % result) + + return get_raw_buffer(bfr) diff --git a/venv/Lib/site-packages/Cryptodome/Hash/SHA384.pyi b/venv/Lib/site-packages/Cryptodome/Hash/SHA384.pyi new file mode 100644 index 0000000..c2aab9e --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Hash/SHA384.pyi @@ -0,0 +1,19 @@ +from typing import Union, Optional + +Buffer = Union[bytes, bytearray, memoryview] + +class SHA384Hash(object): + digest_size: int + block_size: int + oid: str + + def __init__(self, data: Optional[Buffer] = ...) -> None: ... + def update(self, data: Buffer) -> None: ... + def digest(self) -> bytes: ... + def hexdigest(self) -> str: ... + def copy(self) -> SHA384Hash: ... + def new(self, data: Optional[Buffer] = ...) -> SHA384Hash: ... + +def new(data: Optional[Buffer] = ...) -> SHA384Hash: ... +digest_size: int +block_size: int diff --git a/venv/Lib/site-packages/Cryptodome/Hash/SHA3_224.py b/venv/Lib/site-packages/Cryptodome/Hash/SHA3_224.py new file mode 100644 index 0000000..34888c5 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Hash/SHA3_224.py @@ -0,0 +1,174 @@ +# -*- coding: utf-8 -*- +# +# =================================================================== +# The contents of this file are dedicated to the public domain. To +# the extent that dedication to the public domain is not available, +# everyone is granted a worldwide, perpetual, royalty-free, +# non-exclusive license to exercise all rights associated with the +# contents of this file for any purpose whatsoever. +# No rights are reserved. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# =================================================================== + +from Cryptodome.Util.py3compat import bord + +from Cryptodome.Util._raw_api import (load_pycryptodome_raw_lib, + VoidPointer, SmartPointer, + create_string_buffer, + get_raw_buffer, c_size_t, + c_uint8_ptr, c_ubyte) + +from Cryptodome.Hash.keccak import _raw_keccak_lib + +class SHA3_224_Hash(object): + """A SHA3-224 hash object. + Do not instantiate directly. + Use the :func:`new` function. + + :ivar oid: ASN.1 Object ID + :vartype oid: string + + :ivar digest_size: the size in bytes of the resulting hash + :vartype digest_size: integer + """ + + # The size of the resulting hash in bytes. + digest_size = 28 + + # ASN.1 Object ID + oid = "2.16.840.1.101.3.4.2.7" + + # Input block size for HMAC + block_size = 144 + + def __init__(self, data, update_after_digest): + self._update_after_digest = update_after_digest + self._digest_done = False + self._padding = 0x06 + + state = VoidPointer() + result = _raw_keccak_lib.keccak_init(state.address_of(), + c_size_t(self.digest_size * 2), + c_ubyte(24)) + if result: + raise ValueError("Error %d while instantiating SHA-3/224" + % result) + self._state = SmartPointer(state.get(), + _raw_keccak_lib.keccak_destroy) + if data: + self.update(data) + + def update(self, data): + """Continue hashing of a message by consuming the next chunk of data. + + Args: + data (byte string/byte array/memoryview): The next chunk of the message being hashed. + """ + + if self._digest_done and not self._update_after_digest: + raise TypeError("You can only call 'digest' or 'hexdigest' on this object") + + result = _raw_keccak_lib.keccak_absorb(self._state.get(), + c_uint8_ptr(data), + c_size_t(len(data)) + ) + if result: + raise ValueError("Error %d while updating SHA-3/224" + % result) + return self + + def digest(self): + """Return the **binary** (non-printable) digest of the message that has been hashed so far. + + :return: The hash digest, computed over the data processed so far. + Binary form. + :rtype: byte string + """ + + self._digest_done = True + + bfr = create_string_buffer(self.digest_size) + result = _raw_keccak_lib.keccak_digest(self._state.get(), + bfr, + c_size_t(self.digest_size), + c_ubyte(self._padding)) + if result: + raise ValueError("Error %d while instantiating SHA-3/224" + % result) + + self._digest_value = get_raw_buffer(bfr) + return self._digest_value + + def hexdigest(self): + """Return the **printable** digest of the message that has been hashed so far. + + :return: The hash digest, computed over the data processed so far. + Hexadecimal encoded. + :rtype: string + """ + + return "".join(["%02x" % bord(x) for x in self.digest()]) + + def copy(self): + """Return a copy ("clone") of the hash object. + + The copy will have the same internal state as the original hash + object. + This can be used to efficiently compute the digests of strings that + share a common initial substring. + + :return: A hash object of the same type + """ + + clone = self.new() + result = _raw_keccak_lib.keccak_copy(self._state.get(), + clone._state.get()) + if result: + raise ValueError("Error %d while copying SHA3-224" % result) + return clone + + def new(self, data=None): + """Create a fresh SHA3-224 hash object.""" + + return type(self)(data, self._update_after_digest) + + +def new(*args, **kwargs): + """Create a new hash object. + + Args: + data (byte string/byte array/memoryview): + The very first chunk of the message to hash. + It is equivalent to an early call to :meth:`update`. + update_after_digest (boolean): + Whether :meth:`digest` can be followed by another :meth:`update` + (default: ``False``). + + :Return: A :class:`SHA3_224_Hash` hash object + """ + + data = kwargs.pop("data", None) + update_after_digest = kwargs.pop("update_after_digest", False) + if len(args) == 1: + if data: + raise ValueError("Initial data for hash specified twice") + data = args[0] + + if kwargs: + raise TypeError("Unknown parameters: " + str(kwargs)) + + return SHA3_224_Hash(data, update_after_digest) + +# The size of the resulting hash in bytes. +digest_size = SHA3_224_Hash.digest_size + +# Input block size for HMAC +block_size = 144 diff --git a/venv/Lib/site-packages/Cryptodome/Hash/SHA3_224.pyi b/venv/Lib/site-packages/Cryptodome/Hash/SHA3_224.pyi new file mode 100644 index 0000000..2180821 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Hash/SHA3_224.pyi @@ -0,0 +1,19 @@ +from typing import Union, Optional + +Buffer = Union[bytes, bytearray, memoryview] + +class SHA3_224_Hash(object): + digest_size: int + block_size: int + oid: str + def __init__(self, data: Optional[Buffer], update_after_digest: bool) -> None: ... + def update(self, data: Buffer) -> SHA3_224_Hash: ... + def digest(self) -> bytes: ... + def hexdigest(self) -> str: ... + def copy(self) -> SHA3_224_Hash: ... + def new(self, data: Optional[Buffer]) -> SHA3_224_Hash: ... + +def new(__data: Buffer = ..., update_after_digest: bool = ...) -> SHA3_224_Hash: ... + +digest_size: int +block_size: int diff --git a/venv/Lib/site-packages/Cryptodome/Hash/SHA3_256.py b/venv/Lib/site-packages/Cryptodome/Hash/SHA3_256.py new file mode 100644 index 0000000..024962f --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Hash/SHA3_256.py @@ -0,0 +1,174 @@ +# -*- coding: utf-8 -*- +# +# =================================================================== +# The contents of this file are dedicated to the public domain. To +# the extent that dedication to the public domain is not available, +# everyone is granted a worldwide, perpetual, royalty-free, +# non-exclusive license to exercise all rights associated with the +# contents of this file for any purpose whatsoever. +# No rights are reserved. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# =================================================================== + +from Cryptodome.Util.py3compat import bord + +from Cryptodome.Util._raw_api import (load_pycryptodome_raw_lib, + VoidPointer, SmartPointer, + create_string_buffer, + get_raw_buffer, c_size_t, + c_uint8_ptr, c_ubyte) + +from Cryptodome.Hash.keccak import _raw_keccak_lib + +class SHA3_256_Hash(object): + """A SHA3-256 hash object. + Do not instantiate directly. + Use the :func:`new` function. + + :ivar oid: ASN.1 Object ID + :vartype oid: string + + :ivar digest_size: the size in bytes of the resulting hash + :vartype digest_size: integer + """ + + # The size of the resulting hash in bytes. + digest_size = 32 + + # ASN.1 Object ID + oid = "2.16.840.1.101.3.4.2.8" + + # Input block size for HMAC + block_size = 136 + + def __init__(self, data, update_after_digest): + self._update_after_digest = update_after_digest + self._digest_done = False + self._padding = 0x06 + + state = VoidPointer() + result = _raw_keccak_lib.keccak_init(state.address_of(), + c_size_t(self.digest_size * 2), + c_ubyte(24)) + if result: + raise ValueError("Error %d while instantiating SHA-3/256" + % result) + self._state = SmartPointer(state.get(), + _raw_keccak_lib.keccak_destroy) + if data: + self.update(data) + + def update(self, data): + """Continue hashing of a message by consuming the next chunk of data. + + Args: + data (byte string/byte array/memoryview): The next chunk of the message being hashed. + """ + + if self._digest_done and not self._update_after_digest: + raise TypeError("You can only call 'digest' or 'hexdigest' on this object") + + result = _raw_keccak_lib.keccak_absorb(self._state.get(), + c_uint8_ptr(data), + c_size_t(len(data)) + ) + if result: + raise ValueError("Error %d while updating SHA-3/256" + % result) + return self + + def digest(self): + """Return the **binary** (non-printable) digest of the message that has been hashed so far. + + :return: The hash digest, computed over the data processed so far. + Binary form. + :rtype: byte string + """ + + self._digest_done = True + + bfr = create_string_buffer(self.digest_size) + result = _raw_keccak_lib.keccak_digest(self._state.get(), + bfr, + c_size_t(self.digest_size), + c_ubyte(self._padding)) + if result: + raise ValueError("Error %d while instantiating SHA-3/256" + % result) + + self._digest_value = get_raw_buffer(bfr) + return self._digest_value + + def hexdigest(self): + """Return the **printable** digest of the message that has been hashed so far. + + :return: The hash digest, computed over the data processed so far. + Hexadecimal encoded. + :rtype: string + """ + + return "".join(["%02x" % bord(x) for x in self.digest()]) + + def copy(self): + """Return a copy ("clone") of the hash object. + + The copy will have the same internal state as the original hash + object. + This can be used to efficiently compute the digests of strings that + share a common initial substring. + + :return: A hash object of the same type + """ + + clone = self.new() + result = _raw_keccak_lib.keccak_copy(self._state.get(), + clone._state.get()) + if result: + raise ValueError("Error %d while copying SHA3-256" % result) + return clone + + def new(self, data=None): + """Create a fresh SHA3-256 hash object.""" + + return type(self)(data, self._update_after_digest) + + +def new(*args, **kwargs): + """Create a new hash object. + + Args: + data (byte string/byte array/memoryview): + The very first chunk of the message to hash. + It is equivalent to an early call to :meth:`update`. + update_after_digest (boolean): + Whether :meth:`digest` can be followed by another :meth:`update` + (default: ``False``). + + :Return: A :class:`SHA3_256_Hash` hash object + """ + + data = kwargs.pop("data", None) + update_after_digest = kwargs.pop("update_after_digest", False) + if len(args) == 1: + if data: + raise ValueError("Initial data for hash specified twice") + data = args[0] + + if kwargs: + raise TypeError("Unknown parameters: " + str(kwargs)) + + return SHA3_256_Hash(data, update_after_digest) + +# The size of the resulting hash in bytes. +digest_size = SHA3_256_Hash.digest_size + +# Input block size for HMAC +block_size = 136 diff --git a/venv/Lib/site-packages/Cryptodome/Hash/SHA3_256.pyi b/venv/Lib/site-packages/Cryptodome/Hash/SHA3_256.pyi new file mode 100644 index 0000000..88436bd --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Hash/SHA3_256.pyi @@ -0,0 +1,19 @@ +from typing import Union, Optional + +Buffer = Union[bytes, bytearray, memoryview] + +class SHA3_256_Hash(object): + digest_size: int + block_size: int + oid: str + def __init__(self, data: Optional[Buffer], update_after_digest: bool) -> None: ... + def update(self, data: Buffer) -> SHA3_256_Hash: ... + def digest(self) -> bytes: ... + def hexdigest(self) -> str: ... + def copy(self) -> SHA3_256_Hash: ... + def new(self, data: Optional[Buffer]) -> SHA3_256_Hash: ... + +def new(__data: Buffer = ..., update_after_digest: bool = ...) -> SHA3_256_Hash: ... + +digest_size: int +block_size: int diff --git a/venv/Lib/site-packages/Cryptodome/Hash/SHA3_384.py b/venv/Lib/site-packages/Cryptodome/Hash/SHA3_384.py new file mode 100644 index 0000000..26eeb79 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Hash/SHA3_384.py @@ -0,0 +1,179 @@ +# -*- coding: utf-8 -*- +# +# =================================================================== +# The contents of this file are dedicated to the public domain. To +# the extent that dedication to the public domain is not available, +# everyone is granted a worldwide, perpetual, royalty-free, +# non-exclusive license to exercise all rights associated with the +# contents of this file for any purpose whatsoever. +# No rights are reserved. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# =================================================================== + +from Cryptodome.Util.py3compat import bord + +from Cryptodome.Util._raw_api import (load_pycryptodome_raw_lib, + VoidPointer, SmartPointer, + create_string_buffer, + get_raw_buffer, c_size_t, + c_uint8_ptr, c_ubyte) + +from Cryptodome.Hash.keccak import _raw_keccak_lib + +class SHA3_384_Hash(object): + """A SHA3-384 hash object. + Do not instantiate directly. + Use the :func:`new` function. + + :ivar oid: ASN.1 Object ID + :vartype oid: string + + :ivar digest_size: the size in bytes of the resulting hash + :vartype digest_size: integer + """ + + # The size of the resulting hash in bytes. + digest_size = 48 + + # ASN.1 Object ID + oid = "2.16.840.1.101.3.4.2.9" + + # Input block size for HMAC + block_size = 104 + + def __init__(self, data, update_after_digest): + self._update_after_digest = update_after_digest + self._digest_done = False + self._padding = 0x06 + + state = VoidPointer() + result = _raw_keccak_lib.keccak_init(state.address_of(), + c_size_t(self.digest_size * 2), + c_ubyte(24)) + if result: + raise ValueError("Error %d while instantiating SHA-3/384" + % result) + self._state = SmartPointer(state.get(), + _raw_keccak_lib.keccak_destroy) + if data: + self.update(data) + + def update(self, data): + """Continue hashing of a message by consuming the next chunk of data. + + Args: + data (byte string/byte array/memoryview): The next chunk of the message being hashed. + """ + + if self._digest_done and not self._update_after_digest: + raise TypeError("You can only call 'digest' or 'hexdigest' on this object") + + result = _raw_keccak_lib.keccak_absorb(self._state.get(), + c_uint8_ptr(data), + c_size_t(len(data))) + if result: + raise ValueError("Error %d while updating SHA-3/384" + % result) + return self + + def digest(self): + """Return the **binary** (non-printable) digest of the message that has been hashed so far. + + :return: The hash digest, computed over the data processed so far. + Binary form. + :rtype: byte string + """ + + self._digest_done = True + + bfr = create_string_buffer(self.digest_size) + result = _raw_keccak_lib.keccak_digest(self._state.get(), + bfr, + c_size_t(self.digest_size), + c_ubyte(self._padding)) + if result: + raise ValueError("Error %d while instantiating SHA-3/384" + % result) + + self._digest_value = get_raw_buffer(bfr) + return self._digest_value + + def hexdigest(self): + """Return the **printable** digest of the message that has been hashed so far. + + :return: The hash digest, computed over the data processed so far. + Hexadecimal encoded. + :rtype: string + """ + + return "".join(["%02x" % bord(x) for x in self.digest()]) + + def copy(self): + """Return a copy ("clone") of the hash object. + + The copy will have the same internal state as the original hash + object. + This can be used to efficiently compute the digests of strings that + share a common initial substring. + + :return: A hash object of the same type + """ + + clone = self.new() + result = _raw_keccak_lib.keccak_copy(self._state.get(), + clone._state.get()) + if result: + raise ValueError("Error %d while copying SHA3-384" % result) + return clone + + def new(self, data=None): + """Create a fresh SHA3-256 hash object.""" + + return type(self)(data, self._update_after_digest) + + + def new(self, data=None): + """Create a fresh SHA3-384 hash object.""" + + return type(self)(data, self._update_after_digest) + + +def new(*args, **kwargs): + """Create a new hash object. + + Args: + data (byte string/byte array/memoryview): + The very first chunk of the message to hash. + It is equivalent to an early call to :meth:`update`. + update_after_digest (boolean): + Whether :meth:`digest` can be followed by another :meth:`update` + (default: ``False``). + + :Return: A :class:`SHA3_384_Hash` hash object + """ + + data = kwargs.pop("data", None) + update_after_digest = kwargs.pop("update_after_digest", False) + if len(args) == 1: + if data: + raise ValueError("Initial data for hash specified twice") + data = args[0] + + if kwargs: + raise TypeError("Unknown parameters: " + str(kwargs)) + + return SHA3_384_Hash(data, update_after_digest) + +# The size of the resulting hash in bytes. +digest_size = SHA3_384_Hash.digest_size + +# Input block size for HMAC +block_size = 104 diff --git a/venv/Lib/site-packages/Cryptodome/Hash/SHA3_384.pyi b/venv/Lib/site-packages/Cryptodome/Hash/SHA3_384.pyi new file mode 100644 index 0000000..98d00c6 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Hash/SHA3_384.pyi @@ -0,0 +1,19 @@ +from typing import Union, Optional + +Buffer = Union[bytes, bytearray, memoryview] + +class SHA3_384_Hash(object): + digest_size: int + block_size: int + oid: str + def __init__(self, data: Optional[Buffer], update_after_digest: bool) -> None: ... + def update(self, data: Buffer) -> SHA3_384_Hash: ... + def digest(self) -> bytes: ... + def hexdigest(self) -> str: ... + def copy(self) -> SHA3_384_Hash: ... + def new(self, data: Optional[Buffer]) -> SHA3_384_Hash: ... + +def new(__data: Buffer = ..., update_after_digest: bool = ...) -> SHA3_384_Hash: ... + +digest_size: int +block_size: int diff --git a/venv/Lib/site-packages/Cryptodome/Hash/SHA3_512.py b/venv/Lib/site-packages/Cryptodome/Hash/SHA3_512.py new file mode 100644 index 0000000..99b1c37 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Hash/SHA3_512.py @@ -0,0 +1,174 @@ +# -*- coding: utf-8 -*- +# +# =================================================================== +# The contents of this file are dedicated to the public domain. To +# the extent that dedication to the public domain is not available, +# everyone is granted a worldwide, perpetual, royalty-free, +# non-exclusive license to exercise all rights associated with the +# contents of this file for any purpose whatsoever. +# No rights are reserved. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# =================================================================== + +from Cryptodome.Util.py3compat import bord + +from Cryptodome.Util._raw_api import (load_pycryptodome_raw_lib, + VoidPointer, SmartPointer, + create_string_buffer, + get_raw_buffer, c_size_t, + c_uint8_ptr, c_ubyte) + +from Cryptodome.Hash.keccak import _raw_keccak_lib + +class SHA3_512_Hash(object): + """A SHA3-512 hash object. + Do not instantiate directly. + Use the :func:`new` function. + + :ivar oid: ASN.1 Object ID + :vartype oid: string + + :ivar digest_size: the size in bytes of the resulting hash + :vartype digest_size: integer + """ + + # The size of the resulting hash in bytes. + digest_size = 64 + + # ASN.1 Object ID + oid = "2.16.840.1.101.3.4.2.10" + + # Input block size for HMAC + block_size = 72 + + def __init__(self, data, update_after_digest): + self._update_after_digest = update_after_digest + self._digest_done = False + self._padding = 0x06 + + state = VoidPointer() + result = _raw_keccak_lib.keccak_init(state.address_of(), + c_size_t(self.digest_size * 2), + c_ubyte(24)) + if result: + raise ValueError("Error %d while instantiating SHA-3/512" + % result) + self._state = SmartPointer(state.get(), + _raw_keccak_lib.keccak_destroy) + if data: + self.update(data) + + def update(self, data): + """Continue hashing of a message by consuming the next chunk of data. + + Args: + data (byte string/byte array/memoryview): The next chunk of the message being hashed. + """ + + if self._digest_done and not self._update_after_digest: + raise TypeError("You can only call 'digest' or 'hexdigest' on this object") + + result = _raw_keccak_lib.keccak_absorb(self._state.get(), + c_uint8_ptr(data), + c_size_t(len(data))) + if result: + raise ValueError("Error %d while updating SHA-3/512" + % result) + return self + + def digest(self): + + """Return the **binary** (non-printable) digest of the message that has been hashed so far. + + :return: The hash digest, computed over the data processed so far. + Binary form. + :rtype: byte string + """ + + self._digest_done = True + + bfr = create_string_buffer(self.digest_size) + result = _raw_keccak_lib.keccak_digest(self._state.get(), + bfr, + c_size_t(self.digest_size), + c_ubyte(self._padding)) + if result: + raise ValueError("Error %d while instantiating SHA-3/512" + % result) + + self._digest_value = get_raw_buffer(bfr) + return self._digest_value + + def hexdigest(self): + """Return the **printable** digest of the message that has been hashed so far. + + :return: The hash digest, computed over the data processed so far. + Hexadecimal encoded. + :rtype: string + """ + + return "".join(["%02x" % bord(x) for x in self.digest()]) + + def copy(self): + """Return a copy ("clone") of the hash object. + + The copy will have the same internal state as the original hash + object. + This can be used to efficiently compute the digests of strings that + share a common initial substring. + + :return: A hash object of the same type + """ + + clone = self.new() + result = _raw_keccak_lib.keccak_copy(self._state.get(), + clone._state.get()) + if result: + raise ValueError("Error %d while copying SHA3-512" % result) + return clone + + def new(self, data=None): + """Create a fresh SHA3-521 hash object.""" + + return type(self)(data, self._update_after_digest) + + +def new(*args, **kwargs): + """Create a new hash object. + + Args: + data (byte string/byte array/memoryview): + The very first chunk of the message to hash. + It is equivalent to an early call to :meth:`update`. + update_after_digest (boolean): + Whether :meth:`digest` can be followed by another :meth:`update` + (default: ``False``). + + :Return: A :class:`SHA3_512_Hash` hash object + """ + + data = kwargs.pop("data", None) + update_after_digest = kwargs.pop("update_after_digest", False) + if len(args) == 1: + if data: + raise ValueError("Initial data for hash specified twice") + data = args[0] + + if kwargs: + raise TypeError("Unknown parameters: " + str(kwargs)) + + return SHA3_512_Hash(data, update_after_digest) + +# The size of the resulting hash in bytes. +digest_size = SHA3_512_Hash.digest_size + +# Input block size for HMAC +block_size = 72 diff --git a/venv/Lib/site-packages/Cryptodome/Hash/SHA3_512.pyi b/venv/Lib/site-packages/Cryptodome/Hash/SHA3_512.pyi new file mode 100644 index 0000000..cdeec16 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Hash/SHA3_512.pyi @@ -0,0 +1,19 @@ +from typing import Union, Optional + +Buffer = Union[bytes, bytearray, memoryview] + +class SHA3_512_Hash(object): + digest_size: int + block_size: int + oid: str + def __init__(self, data: Optional[Buffer], update_after_digest: bool) -> None: ... + def update(self, data: Buffer) -> SHA3_512_Hash: ... + def digest(self) -> bytes: ... + def hexdigest(self) -> str: ... + def copy(self) -> SHA3_512_Hash: ... + def new(self, data: Optional[Buffer]) -> SHA3_512_Hash: ... + +def new(__data: Buffer = ..., update_after_digest: bool = ...) -> SHA3_512_Hash: ... + +digest_size: int +block_size: int diff --git a/venv/Lib/site-packages/Cryptodome/Hash/SHA512.py b/venv/Lib/site-packages/Cryptodome/Hash/SHA512.py new file mode 100644 index 0000000..5066197 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Hash/SHA512.py @@ -0,0 +1,204 @@ +# -*- coding: utf-8 -*- +# +# =================================================================== +# The contents of this file are dedicated to the public domain. To +# the extent that dedication to the public domain is not available, +# everyone is granted a worldwide, perpetual, royalty-free, +# non-exclusive license to exercise all rights associated with the +# contents of this file for any purpose whatsoever. +# No rights are reserved. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# =================================================================== + +from Cryptodome.Util.py3compat import bord + +from Cryptodome.Util._raw_api import (load_pycryptodome_raw_lib, + VoidPointer, SmartPointer, + create_string_buffer, + get_raw_buffer, c_size_t, + c_uint8_ptr) + +_raw_sha512_lib = load_pycryptodome_raw_lib("Cryptodome.Hash._SHA512", + """ + int SHA512_init(void **shaState, + size_t digest_size); + int SHA512_destroy(void *shaState); + int SHA512_update(void *hs, + const uint8_t *buf, + size_t len); + int SHA512_digest(const void *shaState, + uint8_t *digest, + size_t digest_size); + int SHA512_copy(const void *src, void *dst); + + int SHA512_pbkdf2_hmac_assist(const void *inner, + const void *outer, + const uint8_t *first_digest, + uint8_t *final_digest, + size_t iterations, + size_t digest_size); + """) + +class SHA512Hash(object): + """A SHA-512 hash object (possibly in its truncated version SHA-512/224 or + SHA-512/256. + Do not instantiate directly. Use the :func:`new` function. + + :ivar oid: ASN.1 Object ID + :vartype oid: string + + :ivar block_size: the size in bytes of the internal message block, + input to the compression function + :vartype block_size: integer + + :ivar digest_size: the size in bytes of the resulting hash + :vartype digest_size: integer + """ + + # The internal block size of the hash algorithm in bytes. + block_size = 128 + + def __init__(self, data, truncate): + self._truncate = truncate + + if truncate is None: + self.oid = "2.16.840.1.101.3.4.2.3" + self.digest_size = 64 + elif truncate == "224": + self.oid = "2.16.840.1.101.3.4.2.5" + self.digest_size = 28 + elif truncate == "256": + self.oid = "2.16.840.1.101.3.4.2.6" + self.digest_size = 32 + else: + raise ValueError("Incorrect truncation length. It must be '224' or '256'.") + + state = VoidPointer() + result = _raw_sha512_lib.SHA512_init(state.address_of(), + c_size_t(self.digest_size)) + if result: + raise ValueError("Error %d while instantiating SHA-512" + % result) + self._state = SmartPointer(state.get(), + _raw_sha512_lib.SHA512_destroy) + if data: + self.update(data) + + def update(self, data): + """Continue hashing of a message by consuming the next chunk of data. + + Args: + data (byte string/byte array/memoryview): The next chunk of the message being hashed. + """ + + result = _raw_sha512_lib.SHA512_update(self._state.get(), + c_uint8_ptr(data), + c_size_t(len(data))) + if result: + raise ValueError("Error %d while hashing data with SHA512" + % result) + + def digest(self): + """Return the **binary** (non-printable) digest of the message that has been hashed so far. + + :return: The hash digest, computed over the data processed so far. + Binary form. + :rtype: byte string + """ + + bfr = create_string_buffer(self.digest_size) + result = _raw_sha512_lib.SHA512_digest(self._state.get(), + bfr, + c_size_t(self.digest_size)) + if result: + raise ValueError("Error %d while making SHA512 digest" + % result) + + return get_raw_buffer(bfr) + + def hexdigest(self): + """Return the **printable** digest of the message that has been hashed so far. + + :return: The hash digest, computed over the data processed so far. + Hexadecimal encoded. + :rtype: string + """ + + return "".join(["%02x" % bord(x) for x in self.digest()]) + + def copy(self): + """Return a copy ("clone") of the hash object. + + The copy will have the same internal state as the original hash + object. + This can be used to efficiently compute the digests of strings that + share a common initial substring. + + :return: A hash object of the same type + """ + + clone = SHA512Hash(None, self._truncate) + result = _raw_sha512_lib.SHA512_copy(self._state.get(), + clone._state.get()) + if result: + raise ValueError("Error %d while copying SHA512" % result) + return clone + + def new(self, data=None): + """Create a fresh SHA-512 hash object.""" + + return SHA512Hash(data, self._truncate) + + +def new(data=None, truncate=None): + """Create a new hash object. + + Args: + data (bytes/bytearray/memoryview): + Optional. The very first chunk of the message to hash. + It is equivalent to an early call to :meth:`SHA512Hash.update`. + truncate (string): + Optional. The desired length of the digest. It can be either "224" or + "256". If not present, the digest is 512 bits long. + Passing this parameter is **not** equivalent to simply truncating + the output digest. + + :Return: A :class:`SHA512Hash` hash object + """ + + return SHA512Hash(data, truncate) + + +# The size of the full SHA-512 hash in bytes. +digest_size = 64 + +# The internal block size of the hash algorithm in bytes. +block_size = 128 + + +def _pbkdf2_hmac_assist(inner, outer, first_digest, iterations): + """Compute the expensive inner loop in PBKDF-HMAC.""" + + assert iterations > 0 + + bfr = create_string_buffer(len(first_digest)); + result = _raw_sha512_lib.SHA512_pbkdf2_hmac_assist( + inner._state.get(), + outer._state.get(), + first_digest, + bfr, + c_size_t(iterations), + c_size_t(len(first_digest))) + + if result: + raise ValueError("Error %d with PBKDF2-HMAC assist for SHA512" % result) + + return get_raw_buffer(bfr) diff --git a/venv/Lib/site-packages/Cryptodome/Hash/SHA512.pyi b/venv/Lib/site-packages/Cryptodome/Hash/SHA512.pyi new file mode 100644 index 0000000..f219ee9 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Hash/SHA512.pyi @@ -0,0 +1,22 @@ +from typing import Union, Optional + +Buffer = Union[bytes, bytearray, memoryview] + +class SHA512Hash(object): + digest_size: int + block_size: int + oid: str + + def __init__(self, + data: Optional[Buffer], + truncate: Optional[str]) -> None: ... + def update(self, data: Buffer) -> None: ... + def digest(self) -> bytes: ... + def hexdigest(self) -> str: ... + def copy(self) -> SHA512Hash: ... + def new(self, data: Optional[Buffer] = ...) -> SHA512Hash: ... + +def new(data: Optional[Buffer] = ..., + truncate: Optional[str] = ...) -> SHA512Hash: ... +digest_size: int +block_size: int diff --git a/venv/Lib/site-packages/Cryptodome/Hash/SHAKE128.py b/venv/Lib/site-packages/Cryptodome/Hash/SHAKE128.py new file mode 100644 index 0000000..847b514 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Hash/SHAKE128.py @@ -0,0 +1,145 @@ +# =================================================================== +# +# Copyright (c) 2015, Legrandin +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# =================================================================== + +from Cryptodome.Util.py3compat import bord + +from Cryptodome.Util._raw_api import (load_pycryptodome_raw_lib, + VoidPointer, SmartPointer, + create_string_buffer, + get_raw_buffer, c_size_t, + c_uint8_ptr, c_ubyte) + +from Cryptodome.Hash.keccak import _raw_keccak_lib + +class SHAKE128_XOF(object): + """A SHAKE128 hash object. + Do not instantiate directly. + Use the :func:`new` function. + + :ivar oid: ASN.1 Object ID + :vartype oid: string + """ + + # ASN.1 Object ID + oid = "2.16.840.1.101.3.4.2.11" + + def __init__(self, data=None): + state = VoidPointer() + result = _raw_keccak_lib.keccak_init(state.address_of(), + c_size_t(32), + c_ubyte(24)) + if result: + raise ValueError("Error %d while instantiating SHAKE128" + % result) + self._state = SmartPointer(state.get(), + _raw_keccak_lib.keccak_destroy) + self._is_squeezing = False + self._padding = 0x1F + if data: + self.update(data) + + def update(self, data): + """Continue hashing of a message by consuming the next chunk of data. + + Args: + data (byte string/byte array/memoryview): The next chunk of the message being hashed. + """ + + if self._is_squeezing: + raise TypeError("You cannot call 'update' after the first 'read'") + + result = _raw_keccak_lib.keccak_absorb(self._state.get(), + c_uint8_ptr(data), + c_size_t(len(data))) + if result: + raise ValueError("Error %d while updating SHAKE128 state" + % result) + return self + + def read(self, length): + """ + Compute the next piece of XOF output. + + .. note:: + You cannot use :meth:`update` anymore after the first call to + :meth:`read`. + + Args: + length (integer): the amount of bytes this method must return + + :return: the next piece of XOF output (of the given length) + :rtype: byte string + """ + + self._is_squeezing = True + bfr = create_string_buffer(length) + result = _raw_keccak_lib.keccak_squeeze(self._state.get(), + bfr, + c_size_t(length), + c_ubyte(self._padding)) + if result: + raise ValueError("Error %d while extracting from SHAKE128" + % result) + + return get_raw_buffer(bfr) + + def copy(self): + """Return a copy ("clone") of the hash object. + + The copy will have the same internal state as the original hash + object. + + :return: A hash object of the same type + """ + + clone = self.new() + result = _raw_keccak_lib.keccak_copy(self._state.get(), + clone._state.get()) + if result: + raise ValueError("Error %d while copying SHAKE128" % result) + return clone + + def new(self, data=None): + return type(self)(data=data) + + +def new(data=None): + """Return a fresh instance of a SHAKE128 object. + + Args: + data (bytes/bytearray/memoryview): + The very first chunk of the message to hash. + It is equivalent to an early call to :meth:`update`. + Optional. + + :Return: A :class:`SHAKE128_XOF` object + """ + + return SHAKE128_XOF(data=data) diff --git a/venv/Lib/site-packages/Cryptodome/Hash/SHAKE128.pyi b/venv/Lib/site-packages/Cryptodome/Hash/SHAKE128.pyi new file mode 100644 index 0000000..de51d8e --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Hash/SHAKE128.pyi @@ -0,0 +1,14 @@ +from typing import Union, Optional + +Buffer = Union[bytes, bytearray, memoryview] + +class SHAKE128_XOF(object): + oid: str + def __init__(self, + data: Optional[Buffer] = ...) -> None: ... + def update(self, data: Buffer) -> SHAKE128_XOF: ... + def read(self, length: int) -> bytes: ... + def copy(self) -> SHAKE128_XOF: ... + def new(self, data: Optional[Buffer] = ...) -> SHAKE128_XOF: ... + +def new(data: Optional[Buffer] = ...) -> SHAKE128_XOF: ... diff --git a/venv/Lib/site-packages/Cryptodome/Hash/SHAKE256.py b/venv/Lib/site-packages/Cryptodome/Hash/SHAKE256.py new file mode 100644 index 0000000..637044e --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Hash/SHAKE256.py @@ -0,0 +1,146 @@ +# =================================================================== +# +# Copyright (c) 2015, Legrandin +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# =================================================================== + +from Cryptodome.Util.py3compat import bord + +from Cryptodome.Util._raw_api import (load_pycryptodome_raw_lib, + VoidPointer, SmartPointer, + create_string_buffer, + get_raw_buffer, c_size_t, + c_uint8_ptr, c_ubyte) + +from Cryptodome.Hash.keccak import _raw_keccak_lib + +class SHAKE256_XOF(object): + """A SHAKE256 hash object. + Do not instantiate directly. + Use the :func:`new` function. + + :ivar oid: ASN.1 Object ID + :vartype oid: string + """ + + # ASN.1 Object ID + oid = "2.16.840.1.101.3.4.2.12" + + def __init__(self, data=None): + state = VoidPointer() + result = _raw_keccak_lib.keccak_init(state.address_of(), + c_size_t(64), + c_ubyte(24)) + if result: + raise ValueError("Error %d while instantiating SHAKE256" + % result) + self._state = SmartPointer(state.get(), + _raw_keccak_lib.keccak_destroy) + self._is_squeezing = False + self._padding = 0x1F + + if data: + self.update(data) + + def update(self, data): + """Continue hashing of a message by consuming the next chunk of data. + + Args: + data (byte string/byte array/memoryview): The next chunk of the message being hashed. + """ + + if self._is_squeezing: + raise TypeError("You cannot call 'update' after the first 'read'") + + result = _raw_keccak_lib.keccak_absorb(self._state.get(), + c_uint8_ptr(data), + c_size_t(len(data))) + if result: + raise ValueError("Error %d while updating SHAKE256 state" + % result) + return self + + def read(self, length): + """ + Compute the next piece of XOF output. + + .. note:: + You cannot use :meth:`update` anymore after the first call to + :meth:`read`. + + Args: + length (integer): the amount of bytes this method must return + + :return: the next piece of XOF output (of the given length) + :rtype: byte string + """ + + self._is_squeezing = True + bfr = create_string_buffer(length) + result = _raw_keccak_lib.keccak_squeeze(self._state.get(), + bfr, + c_size_t(length), + c_ubyte(self._padding)) + if result: + raise ValueError("Error %d while extracting from SHAKE256" + % result) + + return get_raw_buffer(bfr) + + def copy(self): + """Return a copy ("clone") of the hash object. + + The copy will have the same internal state as the original hash + object. + + :return: A hash object of the same type + """ + + clone = self.new() + result = _raw_keccak_lib.keccak_copy(self._state.get(), + clone._state.get()) + if result: + raise ValueError("Error %d while copying SHAKE256" % result) + return clone + + def new(self, data=None): + return type(self)(data=data) + + +def new(data=None): + """Return a fresh instance of a SHAKE256 object. + + Args: + data (bytes/bytearray/memoryview): + The very first chunk of the message to hash. + It is equivalent to an early call to :meth:`update`. + Optional. + + :Return: A :class:`SHAKE256_XOF` object + """ + + return SHAKE256_XOF(data=data) diff --git a/venv/Lib/site-packages/Cryptodome/Hash/SHAKE256.pyi b/venv/Lib/site-packages/Cryptodome/Hash/SHAKE256.pyi new file mode 100644 index 0000000..72eb898 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Hash/SHAKE256.pyi @@ -0,0 +1,14 @@ +from typing import Union, Optional + +Buffer = Union[bytes, bytearray, memoryview] + +class SHAKE256_XOF(object): + oid: str + def __init__(self, + data: Optional[Buffer] = ...) -> None: ... + def update(self, data: Buffer) -> SHAKE256_XOF: ... + def read(self, length: int) -> bytes: ... + def copy(self) -> SHAKE256_XOF: ... + def new(self, data: Optional[Buffer] = ...) -> SHAKE256_XOF: ... + +def new(data: Optional[Buffer] = ...) -> SHAKE256_XOF: ... diff --git a/venv/Lib/site-packages/Cryptodome/Hash/TupleHash128.py b/venv/Lib/site-packages/Cryptodome/Hash/TupleHash128.py new file mode 100644 index 0000000..49aeccc --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Hash/TupleHash128.py @@ -0,0 +1,136 @@ +# =================================================================== +# +# Copyright (c) 2021, Legrandin +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# =================================================================== + +from Cryptodome.Util.py3compat import bord, is_bytes, tobytes + +from . import cSHAKE128 +from .cSHAKE128 import _encode_str, _right_encode + + +class TupleHash(object): + """A Tuple hash object. + Do not instantiate directly. + Use the :func:`new` function. + """ + + def __init__(self, custom, cshake, digest_size): + + self.digest_size = digest_size + + self._cshake = cshake._new(b'', custom, b'TupleHash') + self._digest = None + + def update(self, *data): + """Authenticate the next tuple of byte strings. + TupleHash guarantees the logical separation between each byte string. + + Args: + data (bytes/bytearray/memoryview): One or more items to hash. + """ + + if self._digest is not None: + raise TypeError("You cannot call 'update' after 'digest' or 'hexdigest'") + + for item in data: + if not is_bytes(item): + raise TypeError("You can only call 'update' on bytes" ) + self._cshake.update(_encode_str(item)) + + return self + + def digest(self): + """Return the **binary** (non-printable) digest of the tuple of byte strings. + + :return: The hash digest. Binary form. + :rtype: byte string + """ + + if self._digest is None: + self._cshake.update(_right_encode(self.digest_size * 8)) + self._digest = self._cshake.read(self.digest_size) + + return self._digest + + def hexdigest(self): + """Return the **printable** digest of the tuple of byte strings. + + :return: The hash digest. Hexadecimal encoded. + :rtype: string + """ + + return "".join(["%02x" % bord(x) for x in tuple(self.digest())]) + + def new(self, **kwargs): + """Return a new instance of a TupleHash object. + See :func:`new`. + """ + + if "digest_bytes" not in kwargs and "digest_bits" not in kwargs: + kwargs["digest_bytes"] = self.digest_size + + return new(**kwargs) + + +def new(**kwargs): + """Create a new TupleHash128 object. + + Args: + digest_bytes (integer): + Optional. The size of the digest, in bytes. + Default is 64. Minimum is 8. + digest_bits (integer): + Optional and alternative to ``digest_bytes``. + The size of the digest, in bits (and in steps of 8). + Default is 512. Minimum is 64. + custom (bytes): + Optional. + A customization bytestring (``S`` in SP 800-185). + + :Return: A :class:`TupleHash` object + """ + + digest_bytes = kwargs.pop("digest_bytes", None) + digest_bits = kwargs.pop("digest_bits", None) + if None not in (digest_bytes, digest_bits): + raise TypeError("Only one digest parameter must be provided") + if (None, None) == (digest_bytes, digest_bits): + digest_bytes = 64 + if digest_bytes is not None: + if digest_bytes < 8: + raise ValueError("'digest_bytes' must be at least 8") + else: + if digest_bits < 64 or digest_bits % 8: + raise ValueError("'digest_bytes' must be at least 64 " + "in steps of 8") + digest_bytes = digest_bits // 8 + + custom = kwargs.pop("custom", b'') + + return TupleHash(custom, cSHAKE128, digest_bytes) diff --git a/venv/Lib/site-packages/Cryptodome/Hash/TupleHash128.pyi b/venv/Lib/site-packages/Cryptodome/Hash/TupleHash128.pyi new file mode 100644 index 0000000..2e0ea83 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Hash/TupleHash128.pyi @@ -0,0 +1,22 @@ +from typing import Any, Union, List, Tuple +from types import ModuleType + +Buffer = Union[bytes, bytearray, memoryview] + +class TupleHash(object): + digest_size: int + def __init__(self, + custom: bytes, + cshake: ModuleType, + digest_size: int) -> None: ... + def update(self, *data: Buffer) -> TupleHash: ... + def digest(self) -> bytes: ... + def hexdigest(self) -> str: ... + def new(self, + digest_bytes: int = ..., + digest_bits: int = ..., + custom: int = ...) -> TupleHash: ... + +def new(digest_bytes: int = ..., + digest_bits: int = ..., + custom: int = ...) -> TupleHash: ... diff --git a/venv/Lib/site-packages/Cryptodome/Hash/TupleHash256.py b/venv/Lib/site-packages/Cryptodome/Hash/TupleHash256.py new file mode 100644 index 0000000..40a824a --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Hash/TupleHash256.py @@ -0,0 +1,70 @@ +# =================================================================== +# +# Copyright (c) 2021, Legrandin +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# =================================================================== + +from . import cSHAKE256 +from .TupleHash128 import TupleHash + + +def new(**kwargs): + """Create a new TupleHash256 object. + + Args: + digest_bytes (integer): + Optional. The size of the digest, in bytes. + Default is 64. Minimum is 8. + digest_bits (integer): + Optional and alternative to ``digest_bytes``. + The size of the digest, in bits (and in steps of 8). + Default is 512. Minimum is 64. + custom (bytes): + Optional. + A customization bytestring (``S`` in SP 800-185). + + :Return: A :class:`TupleHash` object + """ + + digest_bytes = kwargs.pop("digest_bytes", None) + digest_bits = kwargs.pop("digest_bits", None) + if None not in (digest_bytes, digest_bits): + raise TypeError("Only one digest parameter must be provided") + if (None, None) == (digest_bytes, digest_bits): + digest_bytes = 64 + if digest_bytes is not None: + if digest_bytes < 8: + raise ValueError("'digest_bytes' must be at least 8") + else: + if digest_bits < 64 or digest_bits % 8: + raise ValueError("'digest_bytes' must be at least 64 " + "in steps of 8") + digest_bytes = digest_bits // 8 + + custom = kwargs.pop("custom", b'') + + return TupleHash(custom, cSHAKE256, digest_bytes) diff --git a/venv/Lib/site-packages/Cryptodome/Hash/TupleHash256.pyi b/venv/Lib/site-packages/Cryptodome/Hash/TupleHash256.pyi new file mode 100644 index 0000000..82d943f --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Hash/TupleHash256.pyi @@ -0,0 +1,5 @@ +from .TupleHash128 import TupleHash + +def new(digest_bytes: int = ..., + digest_bits: int = ..., + custom: int = ...) -> TupleHash: ... diff --git a/venv/Lib/site-packages/Cryptodome/Hash/TurboSHAKE128.py b/venv/Lib/site-packages/Cryptodome/Hash/TurboSHAKE128.py new file mode 100644 index 0000000..92ac59e --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Hash/TurboSHAKE128.py @@ -0,0 +1,112 @@ +from Cryptodome.Util._raw_api import (VoidPointer, SmartPointer, + create_string_buffer, + get_raw_buffer, c_size_t, + c_uint8_ptr, c_ubyte) + +from Cryptodome.Util.number import long_to_bytes +from Cryptodome.Util.py3compat import bchr + +from .keccak import _raw_keccak_lib + + +class TurboSHAKE(object): + """A TurboSHAKE hash object. + Do not instantiate directly. + Use the :func:`new` function. + """ + + def __init__(self, capacity, domain_separation, data): + + state = VoidPointer() + result = _raw_keccak_lib.keccak_init(state.address_of(), + c_size_t(capacity), + c_ubyte(12)) # Reduced number of rounds + if result: + raise ValueError("Error %d while instantiating TurboSHAKE" + % result) + self._state = SmartPointer(state.get(), _raw_keccak_lib.keccak_destroy) + + self._is_squeezing = False + self._capacity = capacity + self._domain = domain_separation + + if data: + self.update(data) + + + def update(self, data): + """Continue hashing of a message by consuming the next chunk of data. + + Args: + data (byte string/byte array/memoryview): The next chunk of the message being hashed. + """ + + if self._is_squeezing: + raise TypeError("You cannot call 'update' after the first 'read'") + + result = _raw_keccak_lib.keccak_absorb(self._state.get(), + c_uint8_ptr(data), + c_size_t(len(data))) + if result: + raise ValueError("Error %d while updating TurboSHAKE state" + % result) + return self + + def read(self, length): + """ + Compute the next piece of XOF output. + + .. note:: + You cannot use :meth:`update` anymore after the first call to + :meth:`read`. + + Args: + length (integer): the amount of bytes this method must return + + :return: the next piece of XOF output (of the given length) + :rtype: byte string + """ + + self._is_squeezing = True + bfr = create_string_buffer(length) + result = _raw_keccak_lib.keccak_squeeze(self._state.get(), + bfr, + c_size_t(length), + c_ubyte(self._domain)) + if result: + raise ValueError("Error %d while extracting from TurboSHAKE" + % result) + + return get_raw_buffer(bfr) + + def new(self, data=None): + return type(self)(self._capacity, self._domain, data) + + def _reset(self): + result = _raw_keccak_lib.keccak_reset(self._state.get()) + if result: + raise ValueError("Error %d while resetting TurboSHAKE state" + % result) + self._is_squeezing = False + + +def new(**kwargs): + """Create a new TurboSHAKE128 object. + + Args: + domain (integer): + Optional - A domain separation byte, between 0x01 and 0x7F. + The default value is 0x1F. + data (bytes/bytearray/memoryview): + Optional - The very first chunk of the message to hash. + It is equivalent to an early call to :meth:`update`. + + :Return: A :class:`TurboSHAKE` object + """ + + domain_separation = kwargs.get('domain', 0x1F) + if not (0x01 <= domain_separation <= 0x7F): + raise ValueError("Incorrect domain separation value (%d)" % + domain_separation) + data = kwargs.get('data') + return TurboSHAKE(32, domain_separation, data=data) diff --git a/venv/Lib/site-packages/Cryptodome/Hash/TurboSHAKE128.pyi b/venv/Lib/site-packages/Cryptodome/Hash/TurboSHAKE128.pyi new file mode 100644 index 0000000..d74c9c0 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Hash/TurboSHAKE128.pyi @@ -0,0 +1,17 @@ +from typing import Union, Optional +from typing_extensions import TypedDict, Unpack, NotRequired + +Buffer = Union[bytes, bytearray, memoryview] + +class TurboSHAKE(object): + + def __init__(self, capacity: int, domain_separation: int, data: Union[Buffer, None]) -> None: ... + def update(self, data: Buffer) -> TurboSHAKE : ... + def read(self, length: int) -> bytes: ... + def new(self, data: Optional[Buffer]=None) -> TurboSHAKE: ... + +class Args(TypedDict): + domain: NotRequired[int] + data: NotRequired[Buffer] + +def new(**kwargs: Unpack[Args]) -> TurboSHAKE: ... diff --git a/venv/Lib/site-packages/Cryptodome/Hash/TurboSHAKE256.py b/venv/Lib/site-packages/Cryptodome/Hash/TurboSHAKE256.py new file mode 100644 index 0000000..ce27a48 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Hash/TurboSHAKE256.py @@ -0,0 +1,22 @@ +from .TurboSHAKE128 import TurboSHAKE + +def new(**kwargs): + """Create a new TurboSHAKE256 object. + + Args: + domain (integer): + Optional - A domain separation byte, between 0x01 and 0x7F. + The default value is 0x1F. + data (bytes/bytearray/memoryview): + Optional - The very first chunk of the message to hash. + It is equivalent to an early call to :meth:`update`. + + :Return: A :class:`TurboSHAKE` object + """ + + domain_separation = kwargs.get('domain', 0x1F) + if not (0x01 <= domain_separation <= 0x7F): + raise ValueError("Incorrect domain separation value (%d)" % + domain_separation) + data = kwargs.get('data') + return TurboSHAKE(64, domain_separation, data=data) diff --git a/venv/Lib/site-packages/Cryptodome/Hash/TurboSHAKE256.pyi b/venv/Lib/site-packages/Cryptodome/Hash/TurboSHAKE256.pyi new file mode 100644 index 0000000..561e946 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Hash/TurboSHAKE256.pyi @@ -0,0 +1,12 @@ +from typing import Union +from typing_extensions import TypedDict, Unpack, NotRequired + +from .TurboSHAKE128 import TurboSHAKE + +Buffer = Union[bytes, bytearray, memoryview] + +class Args(TypedDict): + domain: NotRequired[int] + data: NotRequired[Buffer] + +def new(**kwargs: Unpack[Args]) -> TurboSHAKE: ... diff --git a/venv/Lib/site-packages/Cryptodome/Hash/_BLAKE2b.pyd b/venv/Lib/site-packages/Cryptodome/Hash/_BLAKE2b.pyd new file mode 100644 index 0000000..6595612 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Hash/_BLAKE2b.pyd differ diff --git a/venv/Lib/site-packages/Cryptodome/Hash/_BLAKE2s.pyd b/venv/Lib/site-packages/Cryptodome/Hash/_BLAKE2s.pyd new file mode 100644 index 0000000..8e72ab5 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Hash/_BLAKE2s.pyd differ diff --git a/venv/Lib/site-packages/Cryptodome/Hash/_MD2.pyd b/venv/Lib/site-packages/Cryptodome/Hash/_MD2.pyd new file mode 100644 index 0000000..6b851c4 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Hash/_MD2.pyd differ diff --git a/venv/Lib/site-packages/Cryptodome/Hash/_MD4.pyd b/venv/Lib/site-packages/Cryptodome/Hash/_MD4.pyd new file mode 100644 index 0000000..605ff65 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Hash/_MD4.pyd differ diff --git a/venv/Lib/site-packages/Cryptodome/Hash/_MD5.pyd b/venv/Lib/site-packages/Cryptodome/Hash/_MD5.pyd new file mode 100644 index 0000000..1e90224 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Hash/_MD5.pyd differ diff --git a/venv/Lib/site-packages/Cryptodome/Hash/_RIPEMD160.pyd b/venv/Lib/site-packages/Cryptodome/Hash/_RIPEMD160.pyd new file mode 100644 index 0000000..f14a4d5 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Hash/_RIPEMD160.pyd differ diff --git a/venv/Lib/site-packages/Cryptodome/Hash/_SHA1.pyd b/venv/Lib/site-packages/Cryptodome/Hash/_SHA1.pyd new file mode 100644 index 0000000..de7f64c Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Hash/_SHA1.pyd differ diff --git a/venv/Lib/site-packages/Cryptodome/Hash/_SHA224.pyd b/venv/Lib/site-packages/Cryptodome/Hash/_SHA224.pyd new file mode 100644 index 0000000..c1d5fb7 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Hash/_SHA224.pyd differ diff --git a/venv/Lib/site-packages/Cryptodome/Hash/_SHA256.pyd b/venv/Lib/site-packages/Cryptodome/Hash/_SHA256.pyd new file mode 100644 index 0000000..0b62e23 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Hash/_SHA256.pyd differ diff --git a/venv/Lib/site-packages/Cryptodome/Hash/_SHA384.pyd b/venv/Lib/site-packages/Cryptodome/Hash/_SHA384.pyd new file mode 100644 index 0000000..1d3ee59 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Hash/_SHA384.pyd differ diff --git a/venv/Lib/site-packages/Cryptodome/Hash/_SHA512.pyd b/venv/Lib/site-packages/Cryptodome/Hash/_SHA512.pyd new file mode 100644 index 0000000..e9dfbd8 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Hash/_SHA512.pyd differ diff --git a/venv/Lib/site-packages/Cryptodome/Hash/__init__.py b/venv/Lib/site-packages/Cryptodome/Hash/__init__.py new file mode 100644 index 0000000..80446e4 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Hash/__init__.py @@ -0,0 +1,69 @@ +# -*- coding: utf-8 -*- +# +# =================================================================== +# The contents of this file are dedicated to the public domain. To +# the extent that dedication to the public domain is not available, +# everyone is granted a worldwide, perpetual, royalty-free, +# non-exclusive license to exercise all rights associated with the +# contents of this file for any purpose whatsoever. +# No rights are reserved. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# =================================================================== + +__all__ = ['HMAC', 'MD2', 'MD4', 'MD5', 'RIPEMD160', 'SHA1', + 'SHA224', 'SHA256', 'SHA384', 'SHA512', + 'SHA3_224', 'SHA3_256', 'SHA3_384', 'SHA3_512', + 'CMAC', 'Poly1305', + 'cSHAKE128', 'cSHAKE256', 'KMAC128', 'KMAC256', + 'TupleHash128', 'TupleHash256', 'KangarooTwelve', + 'TurboSHAKE128', 'TurboSHAKE256'] + +def new(name): + """Return a new hash instance, based on its name or + on its ASN.1 Object ID""" + + name = name.upper() + if name in ("1.3.14.3.2.26", "SHA1", "SHA-1"): + from . import SHA1 + return SHA1.new() + if name in ("2.16.840.1.101.3.4.2.4", "SHA224", "SHA-224"): + from . import SHA224 + return SHA224.new() + if name in ("2.16.840.1.101.3.4.2.1", "SHA256", "SHA-256"): + from . import SHA256 + return SHA256.new() + if name in ("2.16.840.1.101.3.4.2.2", "SHA384", "SHA-384"): + from . import SHA384 + return SHA384.new() + if name in ("2.16.840.1.101.3.4.2.3", "SHA512", "SHA-512"): + from . import SHA512 + return SHA512.new() + if name in ("2.16.840.1.101.3.4.2.5", "SHA512-224", "SHA-512-224"): + from . import SHA512 + return SHA512.new(truncate='224') + if name in ("2.16.840.1.101.3.4.2.6", "SHA512-256", "SHA-512-256"): + from . import SHA512 + return SHA512.new(truncate='256') + if name in ("2.16.840.1.101.3.4.2.7", "SHA3-224", "SHA-3-224"): + from . import SHA3_224 + return SHA3_224.new() + if name in ("2.16.840.1.101.3.4.2.8", "SHA3-256", "SHA-3-256"): + from . import SHA3_256 + return SHA3_256.new() + if name in ("2.16.840.1.101.3.4.2.9", "SHA3-384", "SHA-3-384"): + from . import SHA3_384 + return SHA3_384.new() + if name in ("2.16.840.1.101.3.4.2.10", "SHA3-512", "SHA-3-512"): + from . import SHA3_512 + return SHA3_512.new() + else: + raise ValueError("Unknown hash %s" % str(name)) + diff --git a/venv/Lib/site-packages/Cryptodome/Hash/__init__.pyi b/venv/Lib/site-packages/Cryptodome/Hash/__init__.pyi new file mode 100644 index 0000000..b072157 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Hash/__init__.pyi @@ -0,0 +1,57 @@ +from typing import overload +from typing_extensions import Literal + +from Cryptodome.Hash.SHA1 import SHA1Hash +from Cryptodome.Hash.SHA224 import SHA224Hash +from Cryptodome.Hash.SHA256 import SHA256Hash +from Cryptodome.Hash.SHA384 import SHA384Hash +from Cryptodome.Hash.SHA512 import SHA512Hash +from Cryptodome.Hash.SHA3_224 import SHA3_224_Hash +from Cryptodome.Hash.SHA3_256 import SHA3_256_Hash +from Cryptodome.Hash.SHA3_384 import SHA3_384_Hash +from Cryptodome.Hash.SHA3_512 import SHA3_512_Hash + +@overload +def new(name: Literal["1.3.14.3.2.26"]) -> SHA1Hash: ... +@overload +def new(name: Literal["SHA1"]) -> SHA1Hash: ... +@overload +def new(name: Literal["2.16.840.1.101.3.4.2.4"]) -> SHA224Hash: ... +@overload +def new(name: Literal["SHA224"]) -> SHA224Hash: ... +@overload +def new(name: Literal["2.16.840.1.101.3.4.2.1"]) -> SHA256Hash: ... +@overload +def new(name: Literal["SHA256"]) -> SHA256Hash: ... +@overload +def new(name: Literal["2.16.840.1.101.3.4.2.2"]) -> SHA384Hash: ... +@overload +def new(name: Literal["SHA384"]) -> SHA384Hash: ... +@overload +def new(name: Literal["2.16.840.1.101.3.4.2.3"]) -> SHA512Hash: ... +@overload +def new(name: Literal["SHA512"]) -> SHA512Hash: ... +@overload +def new(name: Literal["2.16.840.1.101.3.4.2.5"]) -> SHA512Hash: ... +@overload +def new(name: Literal["SHA512-224"]) -> SHA512Hash: ... +@overload +def new(name: Literal["2.16.840.1.101.3.4.2.6"]) -> SHA512Hash: ... +@overload +def new(name: Literal["SHA512-256"]) -> SHA512Hash: ... +@overload +def new(name: Literal["2.16.840.1.101.3.4.2.7"]) -> SHA3_224_Hash: ... +@overload +def new(name: Literal["SHA3-224"]) -> SHA3_224_Hash: ... +@overload +def new(name: Literal["2.16.840.1.101.3.4.2.8"]) -> SHA3_256_Hash: ... +@overload +def new(name: Literal["SHA3-256"]) -> SHA3_256_Hash: ... +@overload +def new(name: Literal["2.16.840.1.101.3.4.2.9"]) -> SHA3_384_Hash: ... +@overload +def new(name: Literal["SHA3-384"]) -> SHA3_384_Hash: ... +@overload +def new(name: Literal["2.16.840.1.101.3.4.2.10"]) -> SHA3_512_Hash: ... +@overload +def new(name: Literal["SHA3-512"]) -> SHA3_512_Hash: ... diff --git a/venv/Lib/site-packages/Cryptodome/Hash/__pycache__/BLAKE2b.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/Hash/__pycache__/BLAKE2b.cpython-312.pyc new file mode 100644 index 0000000..56b2c0d Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Hash/__pycache__/BLAKE2b.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/Hash/__pycache__/BLAKE2s.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/Hash/__pycache__/BLAKE2s.cpython-312.pyc new file mode 100644 index 0000000..0b08ce8 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Hash/__pycache__/BLAKE2s.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/Hash/__pycache__/CMAC.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/Hash/__pycache__/CMAC.cpython-312.pyc new file mode 100644 index 0000000..4b9c4de Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Hash/__pycache__/CMAC.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/Hash/__pycache__/HMAC.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/Hash/__pycache__/HMAC.cpython-312.pyc new file mode 100644 index 0000000..9a584f1 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Hash/__pycache__/HMAC.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/Hash/__pycache__/KMAC128.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/Hash/__pycache__/KMAC128.cpython-312.pyc new file mode 100644 index 0000000..0fd3bec Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Hash/__pycache__/KMAC128.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/Hash/__pycache__/KMAC256.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/Hash/__pycache__/KMAC256.cpython-312.pyc new file mode 100644 index 0000000..2749db9 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Hash/__pycache__/KMAC256.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/Hash/__pycache__/KangarooTwelve.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/Hash/__pycache__/KangarooTwelve.cpython-312.pyc new file mode 100644 index 0000000..ceb5300 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Hash/__pycache__/KangarooTwelve.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/Hash/__pycache__/MD2.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/Hash/__pycache__/MD2.cpython-312.pyc new file mode 100644 index 0000000..317500e Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Hash/__pycache__/MD2.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/Hash/__pycache__/MD4.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/Hash/__pycache__/MD4.cpython-312.pyc new file mode 100644 index 0000000..aba0265 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Hash/__pycache__/MD4.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/Hash/__pycache__/MD5.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/Hash/__pycache__/MD5.cpython-312.pyc new file mode 100644 index 0000000..fdcadc4 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Hash/__pycache__/MD5.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/Hash/__pycache__/Poly1305.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/Hash/__pycache__/Poly1305.cpython-312.pyc new file mode 100644 index 0000000..728ea56 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Hash/__pycache__/Poly1305.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/Hash/__pycache__/RIPEMD.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/Hash/__pycache__/RIPEMD.cpython-312.pyc new file mode 100644 index 0000000..eb34845 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Hash/__pycache__/RIPEMD.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/Hash/__pycache__/RIPEMD160.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/Hash/__pycache__/RIPEMD160.cpython-312.pyc new file mode 100644 index 0000000..45da5fb Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Hash/__pycache__/RIPEMD160.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/Hash/__pycache__/SHA.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/Hash/__pycache__/SHA.cpython-312.pyc new file mode 100644 index 0000000..5ec80a1 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Hash/__pycache__/SHA.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/Hash/__pycache__/SHA1.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/Hash/__pycache__/SHA1.cpython-312.pyc new file mode 100644 index 0000000..3dafd13 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Hash/__pycache__/SHA1.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/Hash/__pycache__/SHA224.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/Hash/__pycache__/SHA224.cpython-312.pyc new file mode 100644 index 0000000..06b393b Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Hash/__pycache__/SHA224.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/Hash/__pycache__/SHA256.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/Hash/__pycache__/SHA256.cpython-312.pyc new file mode 100644 index 0000000..cea3767 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Hash/__pycache__/SHA256.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/Hash/__pycache__/SHA384.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/Hash/__pycache__/SHA384.cpython-312.pyc new file mode 100644 index 0000000..0344ebe Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Hash/__pycache__/SHA384.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/Hash/__pycache__/SHA3_224.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/Hash/__pycache__/SHA3_224.cpython-312.pyc new file mode 100644 index 0000000..94aae1d Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Hash/__pycache__/SHA3_224.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/Hash/__pycache__/SHA3_256.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/Hash/__pycache__/SHA3_256.cpython-312.pyc new file mode 100644 index 0000000..5905c0c Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Hash/__pycache__/SHA3_256.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/Hash/__pycache__/SHA3_384.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/Hash/__pycache__/SHA3_384.cpython-312.pyc new file mode 100644 index 0000000..a26c2c4 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Hash/__pycache__/SHA3_384.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/Hash/__pycache__/SHA3_512.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/Hash/__pycache__/SHA3_512.cpython-312.pyc new file mode 100644 index 0000000..6578ce9 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Hash/__pycache__/SHA3_512.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/Hash/__pycache__/SHA512.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/Hash/__pycache__/SHA512.cpython-312.pyc new file mode 100644 index 0000000..24eaa80 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Hash/__pycache__/SHA512.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/Hash/__pycache__/SHAKE128.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/Hash/__pycache__/SHAKE128.cpython-312.pyc new file mode 100644 index 0000000..135bec8 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Hash/__pycache__/SHAKE128.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/Hash/__pycache__/SHAKE256.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/Hash/__pycache__/SHAKE256.cpython-312.pyc new file mode 100644 index 0000000..fdf961e Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Hash/__pycache__/SHAKE256.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/Hash/__pycache__/TupleHash128.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/Hash/__pycache__/TupleHash128.cpython-312.pyc new file mode 100644 index 0000000..00c2327 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Hash/__pycache__/TupleHash128.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/Hash/__pycache__/TupleHash256.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/Hash/__pycache__/TupleHash256.cpython-312.pyc new file mode 100644 index 0000000..3948dc7 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Hash/__pycache__/TupleHash256.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/Hash/__pycache__/TurboSHAKE128.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/Hash/__pycache__/TurboSHAKE128.cpython-312.pyc new file mode 100644 index 0000000..fb86242 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Hash/__pycache__/TurboSHAKE128.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/Hash/__pycache__/TurboSHAKE256.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/Hash/__pycache__/TurboSHAKE256.cpython-312.pyc new file mode 100644 index 0000000..b82d18d Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Hash/__pycache__/TurboSHAKE256.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/Hash/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/Hash/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000..48b0353 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Hash/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/Hash/__pycache__/cSHAKE128.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/Hash/__pycache__/cSHAKE128.cpython-312.pyc new file mode 100644 index 0000000..3670a2a Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Hash/__pycache__/cSHAKE128.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/Hash/__pycache__/cSHAKE256.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/Hash/__pycache__/cSHAKE256.cpython-312.pyc new file mode 100644 index 0000000..33e57f9 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Hash/__pycache__/cSHAKE256.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/Hash/__pycache__/keccak.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/Hash/__pycache__/keccak.cpython-312.pyc new file mode 100644 index 0000000..2957108 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Hash/__pycache__/keccak.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/Hash/_ghash_clmul.pyd b/venv/Lib/site-packages/Cryptodome/Hash/_ghash_clmul.pyd new file mode 100644 index 0000000..55b4f71 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Hash/_ghash_clmul.pyd differ diff --git a/venv/Lib/site-packages/Cryptodome/Hash/_ghash_portable.pyd b/venv/Lib/site-packages/Cryptodome/Hash/_ghash_portable.pyd new file mode 100644 index 0000000..4da569c Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Hash/_ghash_portable.pyd differ diff --git a/venv/Lib/site-packages/Cryptodome/Hash/_keccak.pyd b/venv/Lib/site-packages/Cryptodome/Hash/_keccak.pyd new file mode 100644 index 0000000..9aee0e8 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Hash/_keccak.pyd differ diff --git a/venv/Lib/site-packages/Cryptodome/Hash/_poly1305.pyd b/venv/Lib/site-packages/Cryptodome/Hash/_poly1305.pyd new file mode 100644 index 0000000..0b7756e Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Hash/_poly1305.pyd differ diff --git a/venv/Lib/site-packages/Cryptodome/Hash/cSHAKE128.py b/venv/Lib/site-packages/Cryptodome/Hash/cSHAKE128.py new file mode 100644 index 0000000..064b3d6 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Hash/cSHAKE128.py @@ -0,0 +1,187 @@ +# =================================================================== +# +# Copyright (c) 2021, Legrandin +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# =================================================================== + +from Cryptodome.Util.py3compat import bchr, concat_buffers + +from Cryptodome.Util._raw_api import (VoidPointer, SmartPointer, + create_string_buffer, + get_raw_buffer, c_size_t, + c_uint8_ptr, c_ubyte) + +from Cryptodome.Util.number import long_to_bytes + +from Cryptodome.Hash.keccak import _raw_keccak_lib + + +def _left_encode(x): + """Left encode function as defined in NIST SP 800-185""" + + assert (x < (1 << 2040) and x >= 0) + + # Get number of bytes needed to represent this integer. + num = 1 if x == 0 else (x.bit_length() + 7) // 8 + + return bchr(num) + long_to_bytes(x) + + +def _right_encode(x): + """Right encode function as defined in NIST SP 800-185""" + + assert (x < (1 << 2040) and x >= 0) + + # Get number of bytes needed to represent this integer. + num = 1 if x == 0 else (x.bit_length() + 7) // 8 + + return long_to_bytes(x) + bchr(num) + + +def _encode_str(x): + """Encode string function as defined in NIST SP 800-185""" + + bitlen = len(x) * 8 + if bitlen >= (1 << 2040): + raise ValueError("String too large to encode in cSHAKE") + + return concat_buffers(_left_encode(bitlen), x) + + +def _bytepad(x, length): + """Zero pad byte string as defined in NIST SP 800-185""" + + to_pad = concat_buffers(_left_encode(length), x) + + # Note: this implementation works with byte aligned strings, + # hence no additional bit padding is needed at this point. + npad = (length - len(to_pad) % length) % length + + return to_pad + b'\x00' * npad + + +class cSHAKE_XOF(object): + """A cSHAKE hash object. + Do not instantiate directly. + Use the :func:`new` function. + """ + + def __init__(self, data, custom, capacity, function): + state = VoidPointer() + + if custom or function: + prefix_unpad = _encode_str(function) + _encode_str(custom) + prefix = _bytepad(prefix_unpad, (1600 - capacity)//8) + self._padding = 0x04 + else: + prefix = None + self._padding = 0x1F # for SHAKE + + result = _raw_keccak_lib.keccak_init(state.address_of(), + c_size_t(capacity//8), + c_ubyte(24)) + if result: + raise ValueError("Error %d while instantiating cSHAKE" + % result) + self._state = SmartPointer(state.get(), + _raw_keccak_lib.keccak_destroy) + self._is_squeezing = False + + if prefix: + self.update(prefix) + + if data: + self.update(data) + + def update(self, data): + """Continue hashing of a message by consuming the next chunk of data. + + Args: + data (byte string/byte array/memoryview): The next chunk of the message being hashed. + """ + + if self._is_squeezing: + raise TypeError("You cannot call 'update' after the first 'read'") + + result = _raw_keccak_lib.keccak_absorb(self._state.get(), + c_uint8_ptr(data), + c_size_t(len(data))) + if result: + raise ValueError("Error %d while updating %s state" + % (result, self.name)) + return self + + def read(self, length): + """ + Compute the next piece of XOF output. + + .. note:: + You cannot use :meth:`update` anymore after the first call to + :meth:`read`. + + Args: + length (integer): the amount of bytes this method must return + + :return: the next piece of XOF output (of the given length) + :rtype: byte string + """ + + self._is_squeezing = True + bfr = create_string_buffer(length) + result = _raw_keccak_lib.keccak_squeeze(self._state.get(), + bfr, + c_size_t(length), + c_ubyte(self._padding)) + if result: + raise ValueError("Error %d while extracting from %s" + % (result, self.name)) + + return get_raw_buffer(bfr) + + +def _new(data, custom, function): + # Use Keccak[256] + return cSHAKE_XOF(data, custom, 256, function) + + +def new(data=None, custom=None): + """Return a fresh instance of a cSHAKE128 object. + + Args: + data (bytes/bytearray/memoryview): + Optional. + The very first chunk of the message to hash. + It is equivalent to an early call to :meth:`update`. + custom (bytes): + Optional. + A customization bytestring (``S`` in SP 800-185). + + :Return: A :class:`cSHAKE_XOF` object + """ + + # Use Keccak[256] + return cSHAKE_XOF(data, custom, 256, b'') diff --git a/venv/Lib/site-packages/Cryptodome/Hash/cSHAKE128.pyi b/venv/Lib/site-packages/Cryptodome/Hash/cSHAKE128.pyi new file mode 100644 index 0000000..1452fea --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Hash/cSHAKE128.pyi @@ -0,0 +1,14 @@ +from typing import Union, Optional + +Buffer = Union[bytes, bytearray, memoryview] + +class cSHAKE_XOF(object): + def __init__(self, + data: Optional[Buffer] = ..., + function: Optional[bytes] = ..., + custom: Optional[bytes] = ...) -> None: ... + def update(self, data: Buffer) -> cSHAKE_XOF: ... + def read(self, length: int) -> bytes: ... + +def new(data: Optional[Buffer] = ..., + custom: Optional[Buffer] = ...) -> cSHAKE_XOF: ... diff --git a/venv/Lib/site-packages/Cryptodome/Hash/cSHAKE256.py b/venv/Lib/site-packages/Cryptodome/Hash/cSHAKE256.py new file mode 100644 index 0000000..a5b8701 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Hash/cSHAKE256.py @@ -0,0 +1,56 @@ +# =================================================================== +# +# Copyright (c) 2021, Legrandin +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# =================================================================== + +from Cryptodome.Util._raw_api import c_size_t +from Cryptodome.Hash.cSHAKE128 import cSHAKE_XOF + + +def _new(data, custom, function): + # Use Keccak[512] + return cSHAKE_XOF(data, custom, 512, function) + + +def new(data=None, custom=None): + """Return a fresh instance of a cSHAKE256 object. + + Args: + data (bytes/bytearray/memoryview): + The very first chunk of the message to hash. + It is equivalent to an early call to :meth:`update`. + Optional. + custom (bytes): + Optional. + A customization bytestring (``S`` in SP 800-185). + + :Return: A :class:`cSHAKE_XOF` object + """ + + # Use Keccak[512] + return cSHAKE_XOF(data, custom, 512, b'') diff --git a/venv/Lib/site-packages/Cryptodome/Hash/cSHAKE256.pyi b/venv/Lib/site-packages/Cryptodome/Hash/cSHAKE256.pyi new file mode 100644 index 0000000..b910bb6 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Hash/cSHAKE256.pyi @@ -0,0 +1,8 @@ +from typing import Union, Optional + +from Cryptodome.Hash.cSHAKE128 import cSHAKE_XOF + +Buffer = Union[bytes, bytearray, memoryview] + +def new(data: Optional[Buffer] = ..., + custom: Optional[Buffer] = ...) -> cSHAKE_XOF: ... diff --git a/venv/Lib/site-packages/Cryptodome/Hash/keccak.py b/venv/Lib/site-packages/Cryptodome/Hash/keccak.py new file mode 100644 index 0000000..f2af202 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Hash/keccak.py @@ -0,0 +1,181 @@ +# =================================================================== +# +# Copyright (c) 2015, Legrandin +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# =================================================================== + +from Cryptodome.Util.py3compat import bord + +from Cryptodome.Util._raw_api import (load_pycryptodome_raw_lib, + VoidPointer, SmartPointer, + create_string_buffer, + get_raw_buffer, c_size_t, + c_uint8_ptr, c_ubyte) + +_raw_keccak_lib = load_pycryptodome_raw_lib("Cryptodome.Hash._keccak", + """ + int keccak_init(void **state, + size_t capacity_bytes, + uint8_t rounds); + int keccak_destroy(void *state); + int keccak_absorb(void *state, + const uint8_t *in, + size_t len); + int keccak_squeeze(const void *state, + uint8_t *out, + size_t len, + uint8_t padding); + int keccak_digest(void *state, + uint8_t *digest, + size_t len, + uint8_t padding); + int keccak_copy(const void *src, void *dst); + int keccak_reset(void *state); + """) + +class Keccak_Hash(object): + """A Keccak hash object. + Do not instantiate directly. + Use the :func:`new` function. + + :ivar digest_size: the size in bytes of the resulting hash + :vartype digest_size: integer + """ + + def __init__(self, data, digest_bytes, update_after_digest): + # The size of the resulting hash in bytes. + self.digest_size = digest_bytes + + self._update_after_digest = update_after_digest + self._digest_done = False + self._padding = 0x01 + + state = VoidPointer() + result = _raw_keccak_lib.keccak_init(state.address_of(), + c_size_t(self.digest_size * 2), + c_ubyte(24)) + if result: + raise ValueError("Error %d while instantiating keccak" % result) + self._state = SmartPointer(state.get(), + _raw_keccak_lib.keccak_destroy) + if data: + self.update(data) + + def update(self, data): + """Continue hashing of a message by consuming the next chunk of data. + + Args: + data (byte string/byte array/memoryview): The next chunk of the message being hashed. + """ + + if self._digest_done and not self._update_after_digest: + raise TypeError("You can only call 'digest' or 'hexdigest' on this object") + + result = _raw_keccak_lib.keccak_absorb(self._state.get(), + c_uint8_ptr(data), + c_size_t(len(data))) + if result: + raise ValueError("Error %d while updating keccak" % result) + return self + + def digest(self): + """Return the **binary** (non-printable) digest of the message that has been hashed so far. + + :return: The hash digest, computed over the data processed so far. + Binary form. + :rtype: byte string + """ + + self._digest_done = True + bfr = create_string_buffer(self.digest_size) + result = _raw_keccak_lib.keccak_digest(self._state.get(), + bfr, + c_size_t(self.digest_size), + c_ubyte(self._padding)) + if result: + raise ValueError("Error %d while squeezing keccak" % result) + + return get_raw_buffer(bfr) + + def hexdigest(self): + """Return the **printable** digest of the message that has been hashed so far. + + :return: The hash digest, computed over the data processed so far. + Hexadecimal encoded. + :rtype: string + """ + + return "".join(["%02x" % bord(x) for x in self.digest()]) + + def new(self, **kwargs): + """Create a fresh Keccak hash object.""" + + if "digest_bytes" not in kwargs and "digest_bits" not in kwargs: + kwargs["digest_bytes"] = self.digest_size + + return new(**kwargs) + + +def new(**kwargs): + """Create a new hash object. + + Args: + data (bytes/bytearray/memoryview): + The very first chunk of the message to hash. + It is equivalent to an early call to :meth:`Keccak_Hash.update`. + digest_bytes (integer): + The size of the digest, in bytes (28, 32, 48, 64). + digest_bits (integer): + The size of the digest, in bits (224, 256, 384, 512). + update_after_digest (boolean): + Whether :meth:`Keccak.digest` can be followed by another + :meth:`Keccak.update` (default: ``False``). + + :Return: A :class:`Keccak_Hash` hash object + """ + + data = kwargs.pop("data", None) + update_after_digest = kwargs.pop("update_after_digest", False) + + digest_bytes = kwargs.pop("digest_bytes", None) + digest_bits = kwargs.pop("digest_bits", None) + if None not in (digest_bytes, digest_bits): + raise TypeError("Only one digest parameter must be provided") + if (None, None) == (digest_bytes, digest_bits): + raise TypeError("Digest size (bits, bytes) not provided") + if digest_bytes is not None: + if digest_bytes not in (28, 32, 48, 64): + raise ValueError("'digest_bytes' must be: 28, 32, 48 or 64") + else: + if digest_bits not in (224, 256, 384, 512): + raise ValueError("'digest_bytes' must be: 224, 256, 384 or 512") + digest_bytes = digest_bits // 8 + + if kwargs: + raise TypeError("Unknown parameters: " + str(kwargs)) + + return Keccak_Hash(data, digest_bytes, update_after_digest) diff --git a/venv/Lib/site-packages/Cryptodome/Hash/keccak.pyi b/venv/Lib/site-packages/Cryptodome/Hash/keccak.pyi new file mode 100644 index 0000000..844d256 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Hash/keccak.pyi @@ -0,0 +1,23 @@ +from typing import Union, Any + +Buffer = Union[bytes, bytearray, memoryview] + +class Keccak_Hash(object): + digest_size: int + def __init__(self, + data: Buffer, + digest_bytes: int, + update_after_digest: bool) -> None: ... + def update(self, data: Buffer) -> Keccak_Hash: ... + def digest(self) -> bytes: ... + def hexdigest(self) -> str: ... + def new(self, + data: Buffer = ..., + digest_bytes: int = ..., + digest_bits: int = ..., + update_after_digest: bool = ...) -> Keccak_Hash: ... + +def new(data: Buffer = ..., + digest_bytes: int = ..., + digest_bits: int = ..., + update_after_digest: bool = ...) -> Keccak_Hash: ... diff --git a/venv/Lib/site-packages/Cryptodome/IO/PEM.py b/venv/Lib/site-packages/Cryptodome/IO/PEM.py new file mode 100644 index 0000000..61fe920 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/IO/PEM.py @@ -0,0 +1,191 @@ +# +# Util/PEM.py : Privacy Enhanced Mail utilities +# +# =================================================================== +# +# Copyright (c) 2014, Legrandin +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# =================================================================== + +__all__ = ['encode', 'decode'] + +import re +from binascii import a2b_base64, b2a_base64, hexlify, unhexlify + +from Cryptodome.Hash import MD5 +from Cryptodome.Util.Padding import pad, unpad +from Cryptodome.Cipher import DES, DES3, AES +from Cryptodome.Protocol.KDF import PBKDF1 +from Cryptodome.Random import get_random_bytes +from Cryptodome.Util.py3compat import tobytes, tostr + + +def encode(data, marker, passphrase=None, randfunc=None): + """Encode a piece of binary data into PEM format. + + Args: + data (byte string): + The piece of binary data to encode. + marker (string): + The marker for the PEM block (e.g. "PUBLIC KEY"). + Note that there is no official master list for all allowed markers. + Still, you can refer to the OpenSSL_ source code. + passphrase (byte string): + If given, the PEM block will be encrypted. The key is derived from + the passphrase. + randfunc (callable): + Random number generation function; it accepts an integer N and returns + a byte string of random data, N bytes long. If not given, a new one is + instantiated. + + Returns: + The PEM block, as a string. + + .. _OpenSSL: https://github.com/openssl/openssl/blob/master/include/openssl/pem.h + """ + + if randfunc is None: + randfunc = get_random_bytes + + out = "-----BEGIN %s-----\n" % marker + if passphrase: + # We only support 3DES for encryption + salt = randfunc(8) + key = PBKDF1(passphrase, salt, 16, 1, MD5) + key += PBKDF1(key + passphrase, salt, 8, 1, MD5) + objenc = DES3.new(key, DES3.MODE_CBC, salt) + out += "Proc-Type: 4,ENCRYPTED\nDEK-Info: DES-EDE3-CBC,%s\n\n" %\ + tostr(hexlify(salt).upper()) + # Encrypt with PKCS#7 padding + data = objenc.encrypt(pad(data, objenc.block_size)) + elif passphrase is not None: + raise ValueError("Empty password") + + # Each BASE64 line can take up to 64 characters (=48 bytes of data) + # b2a_base64 adds a new line character! + chunks = [tostr(b2a_base64(data[i:i + 48])) + for i in range(0, len(data), 48)] + out += "".join(chunks) + out += "-----END %s-----" % marker + return out + + +def _EVP_BytesToKey(data, salt, key_len): + d = [ b'' ] + m = (key_len + 15 ) // 16 + for _ in range(m): + nd = MD5.new(d[-1] + data + salt).digest() + d.append(nd) + return b"".join(d)[:key_len] + + +def decode(pem_data, passphrase=None): + """Decode a PEM block into binary. + + Args: + pem_data (string): + The PEM block. + passphrase (byte string): + If given and the PEM block is encrypted, + the key will be derived from the passphrase. + + Returns: + A tuple with the binary data, the marker string, and a boolean to + indicate if decryption was performed. + + Raises: + ValueError: if decoding fails, if the PEM file is encrypted and no passphrase has + been provided or if the passphrase is incorrect. + """ + + # Verify Pre-Encapsulation Boundary + r = re.compile(r"\s*-----BEGIN (.*)-----\s+") + m = r.match(pem_data) + if not m: + raise ValueError("Not a valid PEM pre boundary") + marker = m.group(1) + + # Verify Post-Encapsulation Boundary + r = re.compile(r"-----END (.*)-----\s*$") + m = r.search(pem_data) + if not m or m.group(1) != marker: + raise ValueError("Not a valid PEM post boundary") + + # Removes spaces and slit on lines + lines = pem_data.replace(" ", '').split() + if len(lines) < 3: + raise ValueError("A PEM file must have at least 3 lines") + + # Decrypts, if necessary + if lines[1].startswith('Proc-Type:4,ENCRYPTED'): + if not passphrase: + raise ValueError("PEM is encrypted, but no passphrase available") + DEK = lines[2].split(':') + if len(DEK) != 2 or DEK[0] != 'DEK-Info': + raise ValueError("PEM encryption format not supported.") + algo, salt = DEK[1].split(',') + salt = unhexlify(tobytes(salt)) + + padding = True + + if algo == "DES-CBC": + key = _EVP_BytesToKey(passphrase, salt, 8) + objdec = DES.new(key, DES.MODE_CBC, salt) + elif algo == "DES-EDE3-CBC": + key = _EVP_BytesToKey(passphrase, salt, 24) + objdec = DES3.new(key, DES3.MODE_CBC, salt) + elif algo == "AES-128-CBC": + key = _EVP_BytesToKey(passphrase, salt[:8], 16) + objdec = AES.new(key, AES.MODE_CBC, salt) + elif algo == "AES-192-CBC": + key = _EVP_BytesToKey(passphrase, salt[:8], 24) + objdec = AES.new(key, AES.MODE_CBC, salt) + elif algo == "AES-256-CBC": + key = _EVP_BytesToKey(passphrase, salt[:8], 32) + objdec = AES.new(key, AES.MODE_CBC, salt) + elif algo.lower() == "id-aes256-gcm": + key = _EVP_BytesToKey(passphrase, salt[:8], 32) + objdec = AES.new(key, AES.MODE_GCM, nonce=salt) + padding = False + else: + raise ValueError("Unsupport PEM encryption algorithm (%s)." % algo) + lines = lines[2:] + else: + objdec = None + + # Decode body + data = a2b_base64(''.join(lines[1:-1])) + enc_flag = False + if objdec: + if padding: + data = unpad(objdec.decrypt(data), objdec.block_size) + else: + # There is no tag, so we don't use decrypt_and_verify + data = objdec.decrypt(data) + enc_flag = True + + return (data, marker, enc_flag) diff --git a/venv/Lib/site-packages/Cryptodome/IO/PEM.pyi b/venv/Lib/site-packages/Cryptodome/IO/PEM.pyi new file mode 100644 index 0000000..2e324c4 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/IO/PEM.pyi @@ -0,0 +1,10 @@ +from typing import Tuple, Optional, Callable + +def encode(data: bytes, + marke: str, + passphrase: Optional[bytes] = ..., + randfunc: Optional[Callable[[int],bytes]] = ...) -> str: ... + + +def decode(pem_data: str, + passphrase: Optional[bytes] = ...) -> Tuple[bytes, str, bool]: ... diff --git a/venv/Lib/site-packages/Cryptodome/IO/PKCS8.py b/venv/Lib/site-packages/Cryptodome/IO/PKCS8.py new file mode 100644 index 0000000..e770199 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/IO/PKCS8.py @@ -0,0 +1,226 @@ +# +# PublicKey/PKCS8.py : PKCS#8 functions +# +# =================================================================== +# +# Copyright (c) 2014, Legrandin +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# =================================================================== + + +from Cryptodome.Util.py3compat import * + +from Cryptodome.Util.asn1 import ( + DerNull, + DerSequence, + DerObjectId, + DerOctetString, + ) + +from Cryptodome.IO._PBES import PBES1, PBES2, PbesError + + +__all__ = ['wrap', 'unwrap'] + + +def wrap(private_key, key_oid, passphrase=None, protection=None, + prot_params=None, key_params=DerNull(), randfunc=None): + """Wrap a private key into a PKCS#8 blob (clear or encrypted). + + Args: + + private_key (bytes): + The private key encoded in binary form. The actual encoding is + algorithm specific. In most cases, it is DER. + + key_oid (string): + The object identifier (OID) of the private key to wrap. + It is a dotted string, like ``'1.2.840.113549.1.1.1'`` (for RSA keys) + or ``'1.2.840.10045.2.1'`` (for ECC keys). + + Keyword Args: + + passphrase (bytes or string): + The secret passphrase from which the wrapping key is derived. + Set it only if encryption is required. + + protection (string): + The identifier of the algorithm to use for securely wrapping the key. + Refer to :ref:`the encryption parameters` . + The default value is ``'PBKDF2WithHMAC-SHA1AndDES-EDE3-CBC'``. + + prot_params (dictionary): + Parameters for the key derivation function (KDF). + Refer to :ref:`the encryption parameters` . + + key_params (DER object or None): + The ``parameters`` field to use in the ``AlgorithmIdentifier`` + SEQUENCE. If ``None``, no ``parameters`` field will be added. + By default, the ASN.1 type ``NULL`` is used. + + randfunc (callable): + Random number generation function; it should accept a single integer + N and return a string of random data, N bytes long. + If not specified, a new RNG will be instantiated + from :mod:`Cryptodome.Random`. + + Returns: + bytes: The PKCS#8-wrapped private key (possibly encrypted). + """ + + # + # PrivateKeyInfo ::= SEQUENCE { + # version Version, + # privateKeyAlgorithm PrivateKeyAlgorithmIdentifier, + # privateKey PrivateKey, + # attributes [0] IMPLICIT Attributes OPTIONAL + # } + # + if key_params is None: + algorithm = DerSequence([DerObjectId(key_oid)]) + else: + algorithm = DerSequence([DerObjectId(key_oid), key_params]) + + pk_info = DerSequence([ + 0, + algorithm, + DerOctetString(private_key) + ]) + pk_info_der = pk_info.encode() + + if passphrase is None: + return pk_info_der + + if not passphrase: + raise ValueError("Empty passphrase") + + # Encryption with PBES2 + passphrase = tobytes(passphrase) + if protection is None: + protection = 'PBKDF2WithHMAC-SHA1AndDES-EDE3-CBC' + return PBES2.encrypt(pk_info_der, passphrase, + protection, prot_params, randfunc) + + +def unwrap(p8_private_key, passphrase=None): + """Unwrap a private key from a PKCS#8 blob (clear or encrypted). + + Args: + p8_private_key (bytes): + The private key wrapped into a PKCS#8 container, DER encoded. + + Keyword Args: + passphrase (byte string or string): + The passphrase to use to decrypt the blob (if it is encrypted). + + Return: + A tuple containing + + #. the algorithm identifier of the wrapped key (OID, dotted string) + #. the private key (bytes, DER encoded) + #. the associated parameters (bytes, DER encoded) or ``None`` + + Raises: + ValueError : if decoding fails + """ + + if passphrase is not None: + passphrase = tobytes(passphrase) + + found = False + try: + p8_private_key = PBES1.decrypt(p8_private_key, passphrase) + found = True + except PbesError as e: + error_str = "PBES1[%s]" % str(e) + except ValueError: + error_str = "PBES1[Invalid]" + + if not found: + try: + p8_private_key = PBES2.decrypt(p8_private_key, passphrase) + found = True + except PbesError as e: + error_str += ",PBES2[%s]" % str(e) + except ValueError: + error_str += ",PBES2[Invalid]" + + if not found: + raise ValueError("Error decoding PKCS#8 (%s)" % error_str) + + pk_info = DerSequence().decode(p8_private_key, nr_elements=(2, 3, 4, 5)) + if len(pk_info) == 2 and not passphrase: + raise ValueError("Not a valid clear PKCS#8 structure " + "(maybe it is encrypted?)") + + # RFC5208, PKCS#8, version is v1(0) + # + # PrivateKeyInfo ::= SEQUENCE { + # version Version, + # privateKeyAlgorithm PrivateKeyAlgorithmIdentifier, + # privateKey PrivateKey, + # attributes [0] IMPLICIT Attributes OPTIONAL + # } + # + # RFC5915, Asymmetric Key Package, version is v2(1) + # + # OneAsymmetricKey ::= SEQUENCE { + # version Version, + # privateKeyAlgorithm PrivateKeyAlgorithmIdentifier, + # privateKey PrivateKey, + # attributes [0] Attributes OPTIONAL, + # ..., + # [[2: publicKey [1] PublicKey OPTIONAL ]], + # ... + # } + + if pk_info[0] == 0: + if len(pk_info) not in (3, 4): + raise ValueError("Not a valid PrivateKeyInfo SEQUENCE") + elif pk_info[0] == 1: + if len(pk_info) not in (3, 4, 5): + raise ValueError("Not a valid PrivateKeyInfo SEQUENCE") + else: + raise ValueError("Not a valid PrivateKeyInfo SEQUENCE") + + algo = DerSequence().decode(pk_info[1], nr_elements=(1, 2)) + algo_oid = DerObjectId().decode(algo[0]).value + if len(algo) == 1: + algo_params = None + else: + try: + DerNull().decode(algo[1]) + algo_params = None + except: + algo_params = algo[1] + + # PrivateKey ::= OCTET STRING + private_key = DerOctetString().decode(pk_info[2]).payload + + # We ignore attributes and (for v2 only) publickey + + return (algo_oid, private_key, algo_params) diff --git a/venv/Lib/site-packages/Cryptodome/IO/PKCS8.pyi b/venv/Lib/site-packages/Cryptodome/IO/PKCS8.pyi new file mode 100644 index 0000000..c8d0c10 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/IO/PKCS8.pyi @@ -0,0 +1,17 @@ +from typing import Tuple, Optional, Union, Callable +from typing_extensions import NotRequired + +from Cryptodome.Util.asn1 import DerObject +from Cryptodome.IO._PBES import ProtParams + + +def wrap(private_key: bytes, + key_oid: str, + passphrase: Union[bytes, str] = ..., + protection: str = ..., + prot_params: Optional[ProtParams] = ..., + key_params: Optional[DerObject] = ..., + randfunc: Optional[Callable[[int], str]] = ...) -> bytes: ... + + +def unwrap(p8_private_key: bytes, passphrase: Optional[Union[bytes, str]] = ...) -> Tuple[str, bytes, Optional[bytes]]: ... diff --git a/venv/Lib/site-packages/Cryptodome/IO/_PBES.py b/venv/Lib/site-packages/Cryptodome/IO/_PBES.py new file mode 100644 index 0000000..75d8cde --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/IO/_PBES.py @@ -0,0 +1,546 @@ +# +# PublicKey/_PBES.py : Password-Based Encryption functions +# +# =================================================================== +# +# Copyright (c) 2014, Legrandin +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# =================================================================== + +import re + +from Cryptodome import Hash +from Cryptodome import Random +from Cryptodome.Util.asn1 import ( + DerSequence, DerOctetString, + DerObjectId, DerInteger, + ) + +from Cryptodome.Cipher import AES +from Cryptodome.Util.Padding import pad, unpad +from Cryptodome.Protocol.KDF import PBKDF1, PBKDF2, scrypt + +_OID_PBE_WITH_MD5_AND_DES_CBC = "1.2.840.113549.1.5.3" +_OID_PBE_WITH_MD5_AND_RC2_CBC = "1.2.840.113549.1.5.6" +_OID_PBE_WITH_SHA1_AND_DES_CBC = "1.2.840.113549.1.5.10" +_OID_PBE_WITH_SHA1_AND_RC2_CBC = "1.2.840.113549.1.5.11" + +_OID_PBES2 = "1.2.840.113549.1.5.13" + +_OID_PBKDF2 = "1.2.840.113549.1.5.12" +_OID_SCRYPT = "1.3.6.1.4.1.11591.4.11" + +_OID_HMAC_SHA1 = "1.2.840.113549.2.7" + +_OID_DES_EDE3_CBC = "1.2.840.113549.3.7" +_OID_AES128_CBC = "2.16.840.1.101.3.4.1.2" +_OID_AES192_CBC = "2.16.840.1.101.3.4.1.22" +_OID_AES256_CBC = "2.16.840.1.101.3.4.1.42" +_OID_AES128_GCM = "2.16.840.1.101.3.4.1.6" +_OID_AES192_GCM = "2.16.840.1.101.3.4.1.26" +_OID_AES256_GCM = "2.16.840.1.101.3.4.1.46" + +class PbesError(ValueError): + pass + +# These are the ASN.1 definitions used by the PBES1/2 logic: +# +# EncryptedPrivateKeyInfo ::= SEQUENCE { +# encryptionAlgorithm EncryptionAlgorithmIdentifier, +# encryptedData EncryptedData +# } +# +# EncryptionAlgorithmIdentifier ::= AlgorithmIdentifier +# +# EncryptedData ::= OCTET STRING +# +# AlgorithmIdentifier ::= SEQUENCE { +# algorithm OBJECT IDENTIFIER, +# parameters ANY DEFINED BY algorithm OPTIONAL +# } +# +# PBEParameter ::= SEQUENCE { +# salt OCTET STRING (SIZE(8)), +# iterationCount INTEGER +# } +# +# PBES2-params ::= SEQUENCE { +# keyDerivationFunc AlgorithmIdentifier {{PBES2-KDFs}}, +# encryptionScheme AlgorithmIdentifier {{PBES2-Encs}} +# } +# +# PBKDF2-params ::= SEQUENCE { +# salt CHOICE { +# specified OCTET STRING, +# otherSource AlgorithmIdentifier {{PBKDF2-SaltSources}} +# }, +# iterationCount INTEGER (1..MAX), +# keyLength INTEGER (1..MAX) OPTIONAL, +# prf AlgorithmIdentifier {{PBKDF2-PRFs}} DEFAULT algid-hmacWithSHA1 +# } +# +# PBKDF2-PRFs ALGORITHM-IDENTIFIER ::= { +# {NULL IDENTIFIED BY id-hmacWithSHA1}, +# {NULL IDENTIFIED BY id-hmacWithSHA224}, +# {NULL IDENTIFIED BY id-hmacWithSHA256}, +# {NULL IDENTIFIED BY id-hmacWithSHA384}, +# {NULL IDENTIFIED BY id-hmacWithSHA512}, +# {NULL IDENTIFIED BY id-hmacWithSHA512-224}, +# {NULL IDENTIFIED BY id-hmacWithSHA512-256}, +# ... +# } +# scrypt-params ::= SEQUENCE { +# salt OCTET STRING, +# costParameter INTEGER (1..MAX), +# blockSize INTEGER (1..MAX), +# parallelizationParameter INTEGER (1..MAX), +# keyLength INTEGER (1..MAX) OPTIONAL +# } + + +class PBES1(object): + """Deprecated encryption scheme with password-based key derivation + (originally defined in PKCS#5 v1.5, but still present in `v2.0`__). + + .. __: http://www.ietf.org/rfc/rfc2898.txt + """ + + @staticmethod + def decrypt(data, passphrase): + """Decrypt a piece of data using a passphrase and *PBES1*. + + The algorithm to use is automatically detected. + + :Parameters: + data : byte string + The piece of data to decrypt. + passphrase : byte string + The passphrase to use for decrypting the data. + :Returns: + The decrypted data, as a binary string. + """ + + enc_private_key_info = DerSequence().decode(data) + encrypted_algorithm = DerSequence().decode(enc_private_key_info[0]) + encrypted_data = DerOctetString().decode(enc_private_key_info[1]).payload + + pbe_oid = DerObjectId().decode(encrypted_algorithm[0]).value + cipher_params = {} + if pbe_oid == _OID_PBE_WITH_MD5_AND_DES_CBC: + # PBE_MD5_DES_CBC + from Cryptodome.Hash import MD5 + from Cryptodome.Cipher import DES + hashmod = MD5 + module = DES + elif pbe_oid == _OID_PBE_WITH_MD5_AND_RC2_CBC: + # PBE_MD5_RC2_CBC + from Cryptodome.Hash import MD5 + from Cryptodome.Cipher import ARC2 + hashmod = MD5 + module = ARC2 + cipher_params['effective_keylen'] = 64 + elif pbe_oid == _OID_PBE_WITH_SHA1_AND_DES_CBC: + # PBE_SHA1_DES_CBC + from Cryptodome.Hash import SHA1 + from Cryptodome.Cipher import DES + hashmod = SHA1 + module = DES + elif pbe_oid == _OID_PBE_WITH_SHA1_AND_RC2_CBC: + # PBE_SHA1_RC2_CBC + from Cryptodome.Hash import SHA1 + from Cryptodome.Cipher import ARC2 + hashmod = SHA1 + module = ARC2 + cipher_params['effective_keylen'] = 64 + else: + raise PbesError("Unknown OID for PBES1") + + pbe_params = DerSequence().decode(encrypted_algorithm[1], nr_elements=2) + salt = DerOctetString().decode(pbe_params[0]).payload + iterations = pbe_params[1] + + key_iv = PBKDF1(passphrase, salt, 16, iterations, hashmod) + key, iv = key_iv[:8], key_iv[8:] + + cipher = module.new(key, module.MODE_CBC, iv, **cipher_params) + pt = cipher.decrypt(encrypted_data) + return unpad(pt, cipher.block_size) + + +class PBES2(object): + """Encryption scheme with password-based key derivation + (defined in `PKCS#5 v2.0`__). + + .. __: http://www.ietf.org/rfc/rfc2898.txt.""" + + @staticmethod + def encrypt(data, passphrase, protection, prot_params=None, randfunc=None): + """Encrypt a piece of data using a passphrase and *PBES2*. + + :Parameters: + data : byte string + The piece of data to encrypt. + passphrase : byte string + The passphrase to use for encrypting the data. + protection : string + The identifier of the encryption algorithm to use. + The default value is '``PBKDF2WithHMAC-SHA1AndDES-EDE3-CBC``'. + prot_params : dictionary + Parameters of the protection algorithm. + + +------------------+-----------------------------------------------+ + | Key | Description | + +==================+===============================================+ + | iteration_count | The KDF algorithm is repeated several times to| + | | slow down brute force attacks on passwords | + | | (called *N* or CPU/memory cost in scrypt). | + | | | + | | The default value for PBKDF2 is 1 000. | + | | The default value for scrypt is 16 384. | + +------------------+-----------------------------------------------+ + | salt_size | Salt is used to thwart dictionary and rainbow | + | | attacks on passwords. The default value is 8 | + | | bytes. | + +------------------+-----------------------------------------------+ + | block_size | *(scrypt only)* Memory-cost (r). The default | + | | value is 8. | + +------------------+-----------------------------------------------+ + | parallelization | *(scrypt only)* CPU-cost (p). The default | + | | value is 1. | + +------------------+-----------------------------------------------+ + + + randfunc : callable + Random number generation function; it should accept + a single integer N and return a string of random data, + N bytes long. If not specified, a new RNG will be + instantiated from ``Cryptodome.Random``. + + :Returns: + The encrypted data, as a binary string. + """ + + if prot_params is None: + prot_params = {} + + if randfunc is None: + randfunc = Random.new().read + + pattern = re.compile(r'^(PBKDF2WithHMAC-([0-9A-Z-]+)|scrypt)And([0-9A-Z-]+)$') + res = pattern.match(protection) + if res is None: + raise ValueError("Unknown protection %s" % protection) + + if protection.startswith("PBKDF"): + pbkdf = "pbkdf2" + pbkdf2_hmac_algo = res.group(2) + enc_algo = res.group(3) + else: + pbkdf = "scrypt" + enc_algo = res.group(3) + + aead = False + if enc_algo == 'DES-EDE3-CBC': + from Cryptodome.Cipher import DES3 + key_size = 24 + module = DES3 + cipher_mode = DES3.MODE_CBC + enc_oid = _OID_DES_EDE3_CBC + enc_param = {'iv': randfunc(8)} + elif enc_algo == 'AES128-CBC': + key_size = 16 + module = AES + cipher_mode = AES.MODE_CBC + enc_oid = _OID_AES128_CBC + enc_param = {'iv': randfunc(16)} + elif enc_algo == 'AES192-CBC': + key_size = 24 + module = AES + cipher_mode = AES.MODE_CBC + enc_oid = _OID_AES192_CBC + enc_param = {'iv': randfunc(16)} + elif enc_algo == 'AES256-CBC': + key_size = 32 + module = AES + cipher_mode = AES.MODE_CBC + enc_oid = _OID_AES256_CBC + enc_param = {'iv': randfunc(16)} + elif enc_algo == 'AES128-GCM': + key_size = 16 + module = AES + cipher_mode = AES.MODE_GCM + enc_oid = _OID_AES128_GCM + enc_param = {'nonce': randfunc(12)} + aead = True + elif enc_algo == 'AES192-GCM': + key_size = 24 + module = AES + cipher_mode = AES.MODE_GCM + enc_oid = _OID_AES192_GCM + enc_param = {'nonce': randfunc(12)} + aead = True + elif enc_algo == 'AES256-GCM': + key_size = 32 + module = AES + cipher_mode = AES.MODE_GCM + enc_oid = _OID_AES256_GCM + enc_param = {'nonce': randfunc(12)} + aead = True + else: + raise ValueError("Unknown encryption mode '%s'" % enc_algo) + + iv_nonce = list(enc_param.values())[0] + salt = randfunc(prot_params.get("salt_size", 8)) + + # Derive key from password + if pbkdf == 'pbkdf2': + + count = prot_params.get("iteration_count", 1000) + digestmod = Hash.new(pbkdf2_hmac_algo) + + key = PBKDF2(passphrase, + salt, + key_size, + count, + hmac_hash_module=digestmod) + + pbkdf2_params = DerSequence([ + DerOctetString(salt), + DerInteger(count) + ]) + + if pbkdf2_hmac_algo != 'SHA1': + try: + hmac_oid = Hash.HMAC.new(b'', digestmod=digestmod).oid + except KeyError: + raise ValueError("No OID for HMAC hash algorithm") + pbkdf2_params.append(DerSequence([DerObjectId(hmac_oid)])) + + kdf_info = DerSequence([ + DerObjectId(_OID_PBKDF2), # PBKDF2 + pbkdf2_params + ]) + + elif pbkdf == 'scrypt': + + count = prot_params.get("iteration_count", 16384) + scrypt_r = prot_params.get('block_size', 8) + scrypt_p = prot_params.get('parallelization', 1) + key = scrypt(passphrase, salt, key_size, + count, scrypt_r, scrypt_p) + kdf_info = DerSequence([ + DerObjectId(_OID_SCRYPT), # scrypt + DerSequence([ + DerOctetString(salt), + DerInteger(count), + DerInteger(scrypt_r), + DerInteger(scrypt_p) + ]) + ]) + + else: + raise ValueError("Unknown KDF " + res.group(1)) + + # Create cipher and use it + cipher = module.new(key, cipher_mode, **enc_param) + if aead: + ct, tag = cipher.encrypt_and_digest(data) + encrypted_data = ct + tag + else: + encrypted_data = cipher.encrypt(pad(data, cipher.block_size)) + enc_info = DerSequence([ + DerObjectId(enc_oid), + DerOctetString(iv_nonce) + ]) + + # Result + enc_private_key_info = DerSequence([ + # encryptionAlgorithm + DerSequence([ + DerObjectId(_OID_PBES2), + DerSequence([ + kdf_info, + enc_info + ]), + ]), + DerOctetString(encrypted_data) + ]) + return enc_private_key_info.encode() + + @staticmethod + def decrypt(data, passphrase): + """Decrypt a piece of data using a passphrase and *PBES2*. + + The algorithm to use is automatically detected. + + :Parameters: + data : byte string + The piece of data to decrypt. + passphrase : byte string + The passphrase to use for decrypting the data. + :Returns: + The decrypted data, as a binary string. + """ + + enc_private_key_info = DerSequence().decode(data, nr_elements=2) + enc_algo = DerSequence().decode(enc_private_key_info[0]) + encrypted_data = DerOctetString().decode(enc_private_key_info[1]).payload + + pbe_oid = DerObjectId().decode(enc_algo[0]).value + if pbe_oid != _OID_PBES2: + raise PbesError("Not a PBES2 object") + + pbes2_params = DerSequence().decode(enc_algo[1], nr_elements=2) + + # Key Derivation Function selection + kdf_info = DerSequence().decode(pbes2_params[0], nr_elements=2) + kdf_oid = DerObjectId().decode(kdf_info[0]).value + + kdf_key_length = None + + # We only support PBKDF2 or scrypt + if kdf_oid == _OID_PBKDF2: + + pbkdf2_params = DerSequence().decode(kdf_info[1], nr_elements=(2, 3, 4)) + salt = DerOctetString().decode(pbkdf2_params[0]).payload + iteration_count = pbkdf2_params[1] + + left = len(pbkdf2_params) - 2 + idx = 2 + + if left > 0: + try: + # Check if it's an INTEGER + kdf_key_length = pbkdf2_params[idx] - 0 + left -= 1 + idx += 1 + except TypeError: + # keyLength is not present + pass + + # Default is HMAC-SHA1 + pbkdf2_prf_oid = _OID_HMAC_SHA1 + if left > 0: + pbkdf2_prf_algo_id = DerSequence().decode(pbkdf2_params[idx]) + pbkdf2_prf_oid = DerObjectId().decode(pbkdf2_prf_algo_id[0]).value + + elif kdf_oid == _OID_SCRYPT: + + scrypt_params = DerSequence().decode(kdf_info[1], nr_elements=(4, 5)) + salt = DerOctetString().decode(scrypt_params[0]).payload + iteration_count, scrypt_r, scrypt_p = [scrypt_params[x] + for x in (1, 2, 3)] + if len(scrypt_params) > 4: + kdf_key_length = scrypt_params[4] + else: + kdf_key_length = None + else: + raise PbesError("Unsupported PBES2 KDF") + + # Cipher selection + enc_info = DerSequence().decode(pbes2_params[1]) + enc_oid = DerObjectId().decode(enc_info[0]).value + + aead = False + if enc_oid == _OID_DES_EDE3_CBC: + # DES_EDE3_CBC + from Cryptodome.Cipher import DES3 + module = DES3 + cipher_mode = DES3.MODE_CBC + key_size = 24 + cipher_param = 'iv' + elif enc_oid == _OID_AES128_CBC: + module = AES + cipher_mode = AES.MODE_CBC + key_size = 16 + cipher_param = 'iv' + elif enc_oid == _OID_AES192_CBC: + module = AES + cipher_mode = AES.MODE_CBC + key_size = 24 + cipher_param = 'iv' + elif enc_oid == _OID_AES256_CBC: + module = AES + cipher_mode = AES.MODE_CBC + key_size = 32 + cipher_param = 'iv' + elif enc_oid == _OID_AES128_GCM: + module = AES + cipher_mode = AES.MODE_GCM + key_size = 16 + cipher_param = 'nonce' + aead = True + elif enc_oid == _OID_AES192_GCM: + module = AES + cipher_mode = AES.MODE_GCM + key_size = 24 + cipher_param = 'nonce' + aead = True + elif enc_oid == _OID_AES256_GCM: + module = AES + cipher_mode = AES.MODE_GCM + key_size = 32 + cipher_param = 'nonce' + aead = True + else: + raise PbesError("Unsupported PBES2 cipher " + enc_algo) + + if kdf_key_length and kdf_key_length != key_size: + raise PbesError("Mismatch between PBES2 KDF parameters" + " and selected cipher") + + iv_nonce = DerOctetString().decode(enc_info[1]).payload + + # Create cipher + if kdf_oid == _OID_PBKDF2: + + try: + hmac_hash_module_oid = Hash.HMAC._hmac2hash_oid[pbkdf2_prf_oid] + except KeyError: + raise PbesError("Unsupported HMAC %s" % pbkdf2_prf_oid) + hmac_hash_module = Hash.new(hmac_hash_module_oid) + + key = PBKDF2(passphrase, salt, key_size, iteration_count, + hmac_hash_module=hmac_hash_module) + else: + key = scrypt(passphrase, salt, key_size, iteration_count, + scrypt_r, scrypt_p) + cipher = module.new(key, cipher_mode, **{cipher_param:iv_nonce}) + + # Decrypt data + if len(encrypted_data) < cipher.block_size: + raise ValueError("Too little data to decrypt") + + if aead: + tag_len = cipher.block_size + pt = cipher.decrypt_and_verify(encrypted_data[:-tag_len], + encrypted_data[-tag_len:]) + else: + pt_padded = cipher.decrypt(encrypted_data) + pt = unpad(pt_padded, cipher.block_size) + + return pt diff --git a/venv/Lib/site-packages/Cryptodome/IO/_PBES.pyi b/venv/Lib/site-packages/Cryptodome/IO/_PBES.pyi new file mode 100644 index 0000000..0673364 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/IO/_PBES.pyi @@ -0,0 +1,26 @@ +from typing import Optional, Callable, TypedDict +from typing_extensions import NotRequired + +class PbesError(ValueError): + ... + +class PBES1(object): + @staticmethod + def decrypt(data: bytes, passphrase: bytes) -> bytes: ... + +class ProtParams(TypedDict): + iteration_count: NotRequired[int] + salt_size: NotRequired[int] + block_size: NotRequired[int] + parallelization: NotRequired[int] + +class PBES2(object): + @staticmethod + def encrypt(data: bytes, + passphrase: bytes, + protection: str, + prot_params: Optional[ProtParams] = ..., + randfunc: Optional[Callable[[int],bytes]] = ...) -> bytes: ... + + @staticmethod + def decrypt(data:bytes, passphrase: bytes) -> bytes: ... diff --git a/venv/Lib/site-packages/Cryptodome/IO/__init__.py b/venv/Lib/site-packages/Cryptodome/IO/__init__.py new file mode 100644 index 0000000..85a0d0b --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/IO/__init__.py @@ -0,0 +1,31 @@ +# =================================================================== +# +# Copyright (c) 2014, Legrandin +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# =================================================================== + +__all__ = ['PEM', 'PKCS8'] diff --git a/venv/Lib/site-packages/Cryptodome/IO/__pycache__/PEM.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/IO/__pycache__/PEM.cpython-312.pyc new file mode 100644 index 0000000..e04d1e8 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/IO/__pycache__/PEM.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/IO/__pycache__/PKCS8.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/IO/__pycache__/PKCS8.cpython-312.pyc new file mode 100644 index 0000000..dc8d913 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/IO/__pycache__/PKCS8.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/IO/__pycache__/_PBES.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/IO/__pycache__/_PBES.cpython-312.pyc new file mode 100644 index 0000000..377b0b2 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/IO/__pycache__/_PBES.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/IO/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/IO/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000..fa4a0b5 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/IO/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/Math/Numbers.py b/venv/Lib/site-packages/Cryptodome/Math/Numbers.py new file mode 100644 index 0000000..9e96686 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Math/Numbers.py @@ -0,0 +1,47 @@ +# =================================================================== +# +# Copyright (c) 2014, Legrandin +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# =================================================================== + +__all__ = ["Integer"] + +import os + +try: + if os.getenv("PYCRYPTODOME_DISABLE_GMP"): + raise ImportError() + + from Cryptodome.Math._IntegerGMP import IntegerGMP as Integer + from Cryptodome.Math._IntegerGMP import implementation as _implementation +except (ImportError, OSError, AttributeError): + try: + from Cryptodome.Math._IntegerCustom import IntegerCustom as Integer + from Cryptodome.Math._IntegerCustom import implementation as _implementation + except (ImportError, OSError): + from Cryptodome.Math._IntegerNative import IntegerNative as Integer + _implementation = {} diff --git a/venv/Lib/site-packages/Cryptodome/Math/Numbers.pyi b/venv/Lib/site-packages/Cryptodome/Math/Numbers.pyi new file mode 100644 index 0000000..b0206ca --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Math/Numbers.pyi @@ -0,0 +1,2 @@ +from Cryptodome.Math._IntegerBase import IntegerBase as Integer +__all__ = ['Integer'] diff --git a/venv/Lib/site-packages/Cryptodome/Math/Primality.py b/venv/Lib/site-packages/Cryptodome/Math/Primality.py new file mode 100644 index 0000000..33814fa --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Math/Primality.py @@ -0,0 +1,369 @@ +# =================================================================== +# +# Copyright (c) 2014, Legrandin +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# =================================================================== + +"""Functions to create and test prime numbers. + +:undocumented: __package__ +""" + +from Cryptodome import Random +from Cryptodome.Math.Numbers import Integer + +from Cryptodome.Util.py3compat import iter_range + +COMPOSITE = 0 +PROBABLY_PRIME = 1 + + +def miller_rabin_test(candidate, iterations, randfunc=None): + """Perform a Miller-Rabin primality test on an integer. + + The test is specified in Section C.3.1 of `FIPS PUB 186-4`__. + + :Parameters: + candidate : integer + The number to test for primality. + iterations : integer + The maximum number of iterations to perform before + declaring a candidate a probable prime. + randfunc : callable + An RNG function where bases are taken from. + + :Returns: + ``Primality.COMPOSITE`` or ``Primality.PROBABLY_PRIME``. + + .. __: http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf + """ + + if not isinstance(candidate, Integer): + candidate = Integer(candidate) + + if candidate in (1, 2, 3, 5): + return PROBABLY_PRIME + + if candidate.is_even(): + return COMPOSITE + + one = Integer(1) + minus_one = Integer(candidate - 1) + + if randfunc is None: + randfunc = Random.new().read + + # Step 1 and 2 + m = Integer(minus_one) + a = 0 + while m.is_even(): + m >>= 1 + a += 1 + + # Skip step 3 + + # Step 4 + for i in iter_range(iterations): + + # Step 4.1-2 + base = 1 + while base in (one, minus_one): + base = Integer.random_range(min_inclusive=2, + max_inclusive=candidate - 2, + randfunc=randfunc) + assert(2 <= base <= candidate - 2) + + # Step 4.3-4.4 + z = pow(base, m, candidate) + if z in (one, minus_one): + continue + + # Step 4.5 + for j in iter_range(1, a): + z = pow(z, 2, candidate) + if z == minus_one: + break + if z == one: + return COMPOSITE + else: + return COMPOSITE + + # Step 5 + return PROBABLY_PRIME + + +def lucas_test(candidate): + """Perform a Lucas primality test on an integer. + + The test is specified in Section C.3.3 of `FIPS PUB 186-4`__. + + :Parameters: + candidate : integer + The number to test for primality. + + :Returns: + ``Primality.COMPOSITE`` or ``Primality.PROBABLY_PRIME``. + + .. __: http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf + """ + + if not isinstance(candidate, Integer): + candidate = Integer(candidate) + + # Step 1 + if candidate in (1, 2, 3, 5): + return PROBABLY_PRIME + if candidate.is_even() or candidate.is_perfect_square(): + return COMPOSITE + + # Step 2 + def alternate(): + value = 5 + while True: + yield value + if value > 0: + value += 2 + else: + value -= 2 + value = -value + + for D in alternate(): + if candidate in (D, -D): + continue + js = Integer.jacobi_symbol(D, candidate) + if js == 0: + return COMPOSITE + if js == -1: + break + # Found D. P=1 and Q=(1-D)/4 (note that Q is guaranteed to be an integer) + + # Step 3 + # This is \delta(n) = n - jacobi(D/n) + K = candidate + 1 + # Step 4 + r = K.size_in_bits() - 1 + # Step 5 + # U_1=1 and V_1=P + U_i = Integer(1) + V_i = Integer(1) + U_temp = Integer(0) + V_temp = Integer(0) + # Step 6 + for i in iter_range(r - 1, -1, -1): + # Square + # U_temp = U_i * V_i % candidate + U_temp.set(U_i) + U_temp *= V_i + U_temp %= candidate + # V_temp = (((V_i ** 2 + (U_i ** 2 * D)) * K) >> 1) % candidate + V_temp.set(U_i) + V_temp *= U_i + V_temp *= D + V_temp.multiply_accumulate(V_i, V_i) + if V_temp.is_odd(): + V_temp += candidate + V_temp >>= 1 + V_temp %= candidate + # Multiply + if K.get_bit(i): + # U_i = (((U_temp + V_temp) * K) >> 1) % candidate + U_i.set(U_temp) + U_i += V_temp + if U_i.is_odd(): + U_i += candidate + U_i >>= 1 + U_i %= candidate + # V_i = (((V_temp + U_temp * D) * K) >> 1) % candidate + V_i.set(V_temp) + V_i.multiply_accumulate(U_temp, D) + if V_i.is_odd(): + V_i += candidate + V_i >>= 1 + V_i %= candidate + else: + U_i.set(U_temp) + V_i.set(V_temp) + # Step 7 + if U_i == 0: + return PROBABLY_PRIME + return COMPOSITE + + +from Cryptodome.Util.number import sieve_base as _sieve_base_large +## The optimal number of small primes to use for the sieve +## is probably dependent on the platform and the candidate size +_sieve_base = set(_sieve_base_large[:100]) + + +def test_probable_prime(candidate, randfunc=None): + """Test if a number is prime. + + A number is qualified as prime if it passes a certain + number of Miller-Rabin tests (dependent on the size + of the number, but such that probability of a false + positive is less than 10^-30) and a single Lucas test. + + For instance, a 1024-bit candidate will need to pass + 4 Miller-Rabin tests. + + :Parameters: + candidate : integer + The number to test for primality. + randfunc : callable + The routine to draw random bytes from to select Miller-Rabin bases. + :Returns: + ``PROBABLE_PRIME`` if the number if prime with very high probability. + ``COMPOSITE`` if the number is a composite. + For efficiency reasons, ``COMPOSITE`` is also returned for small primes. + """ + + if randfunc is None: + randfunc = Random.new().read + + if not isinstance(candidate, Integer): + candidate = Integer(candidate) + + # First, check trial division by the smallest primes + if int(candidate) in _sieve_base: + return PROBABLY_PRIME + try: + map(candidate.fail_if_divisible_by, _sieve_base) + except ValueError: + return COMPOSITE + + # These are the number of Miller-Rabin iterations s.t. p(k, t) < 1E-30, + # with p(k, t) being the probability that a randomly chosen k-bit number + # is composite but still survives t MR iterations. + mr_ranges = ((220, 30), (280, 20), (390, 15), (512, 10), + (620, 7), (740, 6), (890, 5), (1200, 4), + (1700, 3), (3700, 2)) + + bit_size = candidate.size_in_bits() + try: + mr_iterations = list(filter(lambda x: bit_size < x[0], + mr_ranges))[0][1] + except IndexError: + mr_iterations = 1 + + if miller_rabin_test(candidate, mr_iterations, + randfunc=randfunc) == COMPOSITE: + return COMPOSITE + if lucas_test(candidate) == COMPOSITE: + return COMPOSITE + return PROBABLY_PRIME + + +def generate_probable_prime(**kwargs): + """Generate a random probable prime. + + The prime will not have any specific properties + (e.g. it will not be a *strong* prime). + + Random numbers are evaluated for primality until one + passes all tests, consisting of a certain number of + Miller-Rabin tests with random bases followed by + a single Lucas test. + + The number of Miller-Rabin iterations is chosen such that + the probability that the output number is a non-prime is + less than 1E-30 (roughly 2^{-100}). + + This approach is compliant to `FIPS PUB 186-4`__. + + :Keywords: + exact_bits : integer + The desired size in bits of the probable prime. + It must be at least 160. + randfunc : callable + An RNG function where candidate primes are taken from. + prime_filter : callable + A function that takes an Integer as parameter and returns + True if the number can be passed to further primality tests, + False if it should be immediately discarded. + + :Return: + A probable prime in the range 2^exact_bits > p > 2^(exact_bits-1). + + .. __: http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf + """ + + exact_bits = kwargs.pop("exact_bits", None) + randfunc = kwargs.pop("randfunc", None) + prime_filter = kwargs.pop("prime_filter", lambda x: True) + if kwargs: + raise ValueError("Unknown parameters: " + kwargs.keys()) + + if exact_bits is None: + raise ValueError("Missing exact_bits parameter") + if exact_bits < 160: + raise ValueError("Prime number is not big enough.") + + if randfunc is None: + randfunc = Random.new().read + + result = COMPOSITE + while result == COMPOSITE: + candidate = Integer.random(exact_bits=exact_bits, + randfunc=randfunc) | 1 + if not prime_filter(candidate): + continue + result = test_probable_prime(candidate, randfunc) + return candidate + + +def generate_probable_safe_prime(**kwargs): + """Generate a random, probable safe prime. + + Note this operation is much slower than generating a simple prime. + + :Keywords: + exact_bits : integer + The desired size in bits of the probable safe prime. + randfunc : callable + An RNG function where candidate primes are taken from. + + :Return: + A probable safe prime in the range + 2^exact_bits > p > 2^(exact_bits-1). + """ + + exact_bits = kwargs.pop("exact_bits", None) + randfunc = kwargs.pop("randfunc", None) + if kwargs: + raise ValueError("Unknown parameters: " + kwargs.keys()) + + if randfunc is None: + randfunc = Random.new().read + + result = COMPOSITE + while result == COMPOSITE: + q = generate_probable_prime(exact_bits=exact_bits - 1, randfunc=randfunc) + candidate = q * 2 + 1 + if candidate.size_in_bits() != exact_bits: + continue + result = test_probable_prime(candidate, randfunc=randfunc) + return candidate diff --git a/venv/Lib/site-packages/Cryptodome/Math/Primality.pyi b/venv/Lib/site-packages/Cryptodome/Math/Primality.pyi new file mode 100644 index 0000000..7813483 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Math/Primality.pyi @@ -0,0 +1,18 @@ +from typing import Callable, Optional, Union, Set + +PrimeResult = int + +COMPOSITE: PrimeResult +PROBABLY_PRIME: PrimeResult + +def miller_rabin_test(candidate: int, iterations: int, randfunc: Optional[Callable[[int],bytes]]=None) -> PrimeResult: ... +def lucas_test(candidate: int) -> PrimeResult: ... +_sieve_base: Set[int] +def test_probable_prime(candidate: int, randfunc: Optional[Callable[[int],bytes]]=None) -> PrimeResult: ... +def generate_probable_prime(*, + exact_bits: int = ..., + randfunc: Callable[[int],bytes] = ..., + prime_filter: Callable[[int],bool] = ...) -> int: ... +def generate_probable_safe_prime(*, + exact_bits: int = ..., + randfunc: Callable[[int],bytes] = ...) -> int: ... diff --git a/venv/Lib/site-packages/Cryptodome/Math/_IntegerBase.py b/venv/Lib/site-packages/Cryptodome/Math/_IntegerBase.py new file mode 100644 index 0000000..03dd591 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Math/_IntegerBase.py @@ -0,0 +1,412 @@ +# =================================================================== +# +# Copyright (c) 2018, Helder Eijs +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# =================================================================== + +import abc + +from Cryptodome.Util.py3compat import iter_range, bord, bchr, ABC + +from Cryptodome import Random + + +class IntegerBase(ABC): + + # Conversions + @abc.abstractmethod + def __int__(self): + pass + + @abc.abstractmethod + def __str__(self): + pass + + @abc.abstractmethod + def __repr__(self): + pass + + @abc.abstractmethod + def to_bytes(self, block_size=0, byteorder='big'): + pass + + @staticmethod + @abc.abstractmethod + def from_bytes(byte_string, byteorder='big'): + pass + + # Relations + @abc.abstractmethod + def __eq__(self, term): + pass + + @abc.abstractmethod + def __ne__(self, term): + pass + + @abc.abstractmethod + def __lt__(self, term): + pass + + @abc.abstractmethod + def __le__(self, term): + pass + + @abc.abstractmethod + def __gt__(self, term): + pass + + @abc.abstractmethod + def __ge__(self, term): + pass + + @abc.abstractmethod + def __nonzero__(self): + pass + __bool__ = __nonzero__ + + @abc.abstractmethod + def is_negative(self): + pass + + # Arithmetic operations + @abc.abstractmethod + def __add__(self, term): + pass + + @abc.abstractmethod + def __sub__(self, term): + pass + + @abc.abstractmethod + def __mul__(self, factor): + pass + + @abc.abstractmethod + def __floordiv__(self, divisor): + pass + + @abc.abstractmethod + def __mod__(self, divisor): + pass + + @abc.abstractmethod + def inplace_pow(self, exponent, modulus=None): + pass + + @abc.abstractmethod + def __pow__(self, exponent, modulus=None): + pass + + @abc.abstractmethod + def __abs__(self): + pass + + @abc.abstractmethod + def sqrt(self, modulus=None): + pass + + @abc.abstractmethod + def __iadd__(self, term): + pass + + @abc.abstractmethod + def __isub__(self, term): + pass + + @abc.abstractmethod + def __imul__(self, term): + pass + + @abc.abstractmethod + def __imod__(self, term): + pass + + # Boolean/bit operations + @abc.abstractmethod + def __and__(self, term): + pass + + @abc.abstractmethod + def __or__(self, term): + pass + + @abc.abstractmethod + def __rshift__(self, pos): + pass + + @abc.abstractmethod + def __irshift__(self, pos): + pass + + @abc.abstractmethod + def __lshift__(self, pos): + pass + + @abc.abstractmethod + def __ilshift__(self, pos): + pass + + @abc.abstractmethod + def get_bit(self, n): + pass + + # Extra + @abc.abstractmethod + def is_odd(self): + pass + + @abc.abstractmethod + def is_even(self): + pass + + @abc.abstractmethod + def size_in_bits(self): + pass + + @abc.abstractmethod + def size_in_bytes(self): + pass + + @abc.abstractmethod + def is_perfect_square(self): + pass + + @abc.abstractmethod + def fail_if_divisible_by(self, small_prime): + pass + + @abc.abstractmethod + def multiply_accumulate(self, a, b): + pass + + @abc.abstractmethod + def set(self, source): + pass + + @abc.abstractmethod + def inplace_inverse(self, modulus): + pass + + @abc.abstractmethod + def inverse(self, modulus): + pass + + @abc.abstractmethod + def gcd(self, term): + pass + + @abc.abstractmethod + def lcm(self, term): + pass + + @staticmethod + @abc.abstractmethod + def jacobi_symbol(a, n): + pass + + @staticmethod + def _tonelli_shanks(n, p): + """Tonelli-shanks algorithm for computing the square root + of n modulo a prime p. + + n must be in the range [0..p-1]. + p must be at least even. + + The return value r is the square root of modulo p. If non-zero, + another solution will also exist (p-r). + + Note we cannot assume that p is really a prime: if it's not, + we can either raise an exception or return the correct value. + """ + + # See https://rosettacode.org/wiki/Tonelli-Shanks_algorithm + + if n in (0, 1): + return n + + if p % 4 == 3: + root = pow(n, (p + 1) // 4, p) + if pow(root, 2, p) != n: + raise ValueError("Cannot compute square root") + return root + + s = 1 + q = (p - 1) // 2 + while not (q & 1): + s += 1 + q >>= 1 + + z = n.__class__(2) + while True: + euler = pow(z, (p - 1) // 2, p) + if euler == 1: + z += 1 + continue + if euler == p - 1: + break + # Most probably p is not a prime + raise ValueError("Cannot compute square root") + + m = s + c = pow(z, q, p) + t = pow(n, q, p) + r = pow(n, (q + 1) // 2, p) + + while t != 1: + for i in iter_range(0, m): + if pow(t, 2**i, p) == 1: + break + if i == m: + raise ValueError("Cannot compute square root of %d mod %d" % (n, p)) + b = pow(c, 2**(m - i - 1), p) + m = i + c = b**2 % p + t = (t * b**2) % p + r = (r * b) % p + + if pow(r, 2, p) != n: + raise ValueError("Cannot compute square root") + + return r + + @classmethod + def random(cls, **kwargs): + """Generate a random natural integer of a certain size. + + :Keywords: + exact_bits : positive integer + The length in bits of the resulting random Integer number. + The number is guaranteed to fulfil the relation: + + 2^bits > result >= 2^(bits - 1) + + max_bits : positive integer + The maximum length in bits of the resulting random Integer number. + The number is guaranteed to fulfil the relation: + + 2^bits > result >=0 + + randfunc : callable + A function that returns a random byte string. The length of the + byte string is passed as parameter. Optional. + If not provided (or ``None``), randomness is read from the system RNG. + + :Return: a Integer object + """ + + exact_bits = kwargs.pop("exact_bits", None) + max_bits = kwargs.pop("max_bits", None) + randfunc = kwargs.pop("randfunc", None) + + if randfunc is None: + randfunc = Random.new().read + + if exact_bits is None and max_bits is None: + raise ValueError("Either 'exact_bits' or 'max_bits' must be specified") + + if exact_bits is not None and max_bits is not None: + raise ValueError("'exact_bits' and 'max_bits' are mutually exclusive") + + bits = exact_bits or max_bits + bytes_needed = ((bits - 1) // 8) + 1 + significant_bits_msb = 8 - (bytes_needed * 8 - bits) + msb = bord(randfunc(1)[0]) + if exact_bits is not None: + msb |= 1 << (significant_bits_msb - 1) + msb &= (1 << significant_bits_msb) - 1 + + return cls.from_bytes(bchr(msb) + randfunc(bytes_needed - 1)) + + @classmethod + def random_range(cls, **kwargs): + """Generate a random integer within a given internal. + + :Keywords: + min_inclusive : integer + The lower end of the interval (inclusive). + max_inclusive : integer + The higher end of the interval (inclusive). + max_exclusive : integer + The higher end of the interval (exclusive). + randfunc : callable + A function that returns a random byte string. The length of the + byte string is passed as parameter. Optional. + If not provided (or ``None``), randomness is read from the system RNG. + :Returns: + An Integer randomly taken in the given interval. + """ + + min_inclusive = kwargs.pop("min_inclusive", None) + max_inclusive = kwargs.pop("max_inclusive", None) + max_exclusive = kwargs.pop("max_exclusive", None) + randfunc = kwargs.pop("randfunc", None) + + if kwargs: + raise ValueError("Unknown keywords: " + str(kwargs.keys)) + if None not in (max_inclusive, max_exclusive): + raise ValueError("max_inclusive and max_exclusive cannot be both" + " specified") + if max_exclusive is not None: + max_inclusive = max_exclusive - 1 + if None in (min_inclusive, max_inclusive): + raise ValueError("Missing keyword to identify the interval") + + if randfunc is None: + randfunc = Random.new().read + + norm_maximum = max_inclusive - min_inclusive + bits_needed = cls(norm_maximum).size_in_bits() + + norm_candidate = -1 + while not 0 <= norm_candidate <= norm_maximum: + norm_candidate = cls.random( + max_bits=bits_needed, + randfunc=randfunc + ) + return norm_candidate + min_inclusive + + @staticmethod + @abc.abstractmethod + def _mult_modulo_bytes(term1, term2, modulus): + """Multiply two integers, take the modulo, and encode as big endian. + This specialized method is used for RSA decryption. + + Args: + term1 : integer + The first term of the multiplication, non-negative. + term2 : integer + The second term of the multiplication, non-negative. + modulus: integer + The modulus, a positive odd number. + :Returns: + A byte string, with the result of the modular multiplication + encoded in big endian mode. + It is as long as the modulus would be, with zero padding + on the left if needed. + """ + pass diff --git a/venv/Lib/site-packages/Cryptodome/Math/_IntegerBase.pyi b/venv/Lib/site-packages/Cryptodome/Math/_IntegerBase.pyi new file mode 100644 index 0000000..ea23532 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Math/_IntegerBase.pyi @@ -0,0 +1,67 @@ +from typing import Optional, Union, Callable + +RandFunc = Callable[[int],int] + +class IntegerBase: + + def __init__(self, value: Union[IntegerBase, int]): ... + + def __int__(self) -> int: ... + def __str__(self) -> str: ... + def __repr__(self) -> str: ... + def to_bytes(self, block_size: Optional[int]=0, byteorder: str= ...) -> bytes: ... + @staticmethod + def from_bytes(byte_string: bytes, byteorder: Optional[str] = ...) -> IntegerBase: ... + def __eq__(self, term: object) -> bool: ... + def __ne__(self, term: object) -> bool: ... + def __lt__(self, term: Union[IntegerBase, int]) -> bool: ... + def __le__(self, term: Union[IntegerBase, int]) -> bool: ... + def __gt__(self, term: Union[IntegerBase, int]) -> bool: ... + def __ge__(self, term: Union[IntegerBase, int]) -> bool: ... + def __nonzero__(self) -> bool: ... + def is_negative(self) -> bool: ... + def __add__(self, term: Union[IntegerBase, int]) -> IntegerBase: ... + def __sub__(self, term: Union[IntegerBase, int]) -> IntegerBase: ... + def __mul__(self, term: Union[IntegerBase, int]) -> IntegerBase: ... + def __floordiv__(self, divisor: Union[IntegerBase, int]) -> IntegerBase: ... + def __mod__(self, divisor: Union[IntegerBase, int]) -> IntegerBase: ... + def inplace_pow(self, exponent: int, modulus: Optional[Union[IntegerBase, int]]=None) -> IntegerBase: ... + def __pow__(self, exponent: int, modulus: Optional[int]) -> IntegerBase: ... + def __abs__(self) -> IntegerBase: ... + def sqrt(self, modulus: Optional[int]) -> IntegerBase: ... + def __iadd__(self, term: Union[IntegerBase, int]) -> IntegerBase: ... + def __isub__(self, term: Union[IntegerBase, int]) -> IntegerBase: ... + def __imul__(self, term: Union[IntegerBase, int]) -> IntegerBase: ... + def __imod__(self, divisor: Union[IntegerBase, int]) -> IntegerBase: ... + def __and__(self, term: Union[IntegerBase, int]) -> IntegerBase: ... + def __or__(self, term: Union[IntegerBase, int]) -> IntegerBase: ... + def __rshift__(self, pos: Union[IntegerBase, int]) -> IntegerBase: ... + def __irshift__(self, pos: Union[IntegerBase, int]) -> IntegerBase: ... + def __lshift__(self, pos: Union[IntegerBase, int]) -> IntegerBase: ... + def __ilshift__(self, pos: Union[IntegerBase, int]) -> IntegerBase: ... + def get_bit(self, n: int) -> bool: ... + def is_odd(self) -> bool: ... + def is_even(self) -> bool: ... + def size_in_bits(self) -> int: ... + def size_in_bytes(self) -> int: ... + def is_perfect_square(self) -> bool: ... + def fail_if_divisible_by(self, small_prime: Union[IntegerBase, int]) -> None: ... + def multiply_accumulate(self, a: Union[IntegerBase, int], b: Union[IntegerBase, int]) -> IntegerBase: ... + def set(self, source: Union[IntegerBase, int]) -> IntegerBase: ... + def inplace_inverse(self, modulus: Union[IntegerBase, int]) -> IntegerBase: ... + def inverse(self, modulus: Union[IntegerBase, int]) -> IntegerBase: ... + def gcd(self, term: Union[IntegerBase, int]) -> IntegerBase: ... + def lcm(self, term: Union[IntegerBase, int]) -> IntegerBase: ... + @staticmethod + def jacobi_symbol(a: Union[IntegerBase, int], n: Union[IntegerBase, int]) -> IntegerBase: ... + @staticmethod + def _tonelli_shanks(n: Union[IntegerBase, int], p: Union[IntegerBase, int]) -> IntegerBase : ... + @classmethod + def random(cls, **kwargs: Union[int,RandFunc]) -> IntegerBase : ... + @classmethod + def random_range(cls, **kwargs: Union[int,RandFunc]) -> IntegerBase : ... + @staticmethod + def _mult_modulo_bytes(term1: Union[IntegerBase, int], + term2: Union[IntegerBase, int], + modulus: Union[IntegerBase, int]) -> bytes: ... + diff --git a/venv/Lib/site-packages/Cryptodome/Math/_IntegerCustom.py b/venv/Lib/site-packages/Cryptodome/Math/_IntegerCustom.py new file mode 100644 index 0000000..20eadca --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Math/_IntegerCustom.py @@ -0,0 +1,162 @@ +# =================================================================== +# +# Copyright (c) 2018, Helder Eijs +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# =================================================================== + +from ._IntegerNative import IntegerNative + +from Cryptodome.Util.number import long_to_bytes, bytes_to_long + +from Cryptodome.Util._raw_api import (load_pycryptodome_raw_lib, + create_string_buffer, + get_raw_buffer, backend, + c_size_t, c_ulonglong) + + +from Cryptodome.Random.random import getrandbits + +c_defs = """ +int monty_pow(uint8_t *out, + const uint8_t *base, + const uint8_t *exp, + const uint8_t *modulus, + size_t len, + uint64_t seed); + +int monty_multiply(uint8_t *out, + const uint8_t *term1, + const uint8_t *term2, + const uint8_t *modulus, + size_t len); +""" + + +_raw_montgomery = load_pycryptodome_raw_lib("Cryptodome.Math._modexp", c_defs) +implementation = {"library": "custom", "api": backend} + + +class IntegerCustom(IntegerNative): + + @staticmethod + def from_bytes(byte_string, byteorder='big'): + if byteorder == 'big': + pass + elif byteorder == 'little': + byte_string = bytearray(byte_string) + byte_string.reverse() + else: + raise ValueError("Incorrect byteorder") + return IntegerCustom(bytes_to_long(byte_string)) + + def inplace_pow(self, exponent, modulus=None): + exp_value = int(exponent) + if exp_value < 0: + raise ValueError("Exponent must not be negative") + + # No modular reduction + if modulus is None: + self._value = pow(self._value, exp_value) + return self + + # With modular reduction + mod_value = int(modulus) + if mod_value < 0: + raise ValueError("Modulus must be positive") + if mod_value == 0: + raise ZeroDivisionError("Modulus cannot be zero") + + # C extension only works with odd moduli + if (mod_value & 1) == 0: + self._value = pow(self._value, exp_value, mod_value) + return self + + # C extension only works with bases smaller than modulus + if self._value >= mod_value: + self._value %= mod_value + + max_len = len(long_to_bytes(max(self._value, exp_value, mod_value))) + + base_b = long_to_bytes(self._value, max_len) + exp_b = long_to_bytes(exp_value, max_len) + modulus_b = long_to_bytes(mod_value, max_len) + + out = create_string_buffer(max_len) + + error = _raw_montgomery.monty_pow( + out, + base_b, + exp_b, + modulus_b, + c_size_t(max_len), + c_ulonglong(getrandbits(64)) + ) + + if error: + raise ValueError("monty_pow failed with error: %d" % error) + + result = bytes_to_long(get_raw_buffer(out)) + self._value = result + return self + + @staticmethod + def _mult_modulo_bytes(term1, term2, modulus): + + # With modular reduction + mod_value = int(modulus) + if mod_value < 0: + raise ValueError("Modulus must be positive") + if mod_value == 0: + raise ZeroDivisionError("Modulus cannot be zero") + + # C extension only works with odd moduli + if (mod_value & 1) == 0: + raise ValueError("Odd modulus is required") + + # C extension only works with non-negative terms smaller than modulus + if term1 >= mod_value or term1 < 0: + term1 %= mod_value + if term2 >= mod_value or term2 < 0: + term2 %= mod_value + + modulus_b = long_to_bytes(mod_value) + numbers_len = len(modulus_b) + term1_b = long_to_bytes(term1, numbers_len) + term2_b = long_to_bytes(term2, numbers_len) + out = create_string_buffer(numbers_len) + + error = _raw_montgomery.monty_multiply( + out, + term1_b, + term2_b, + modulus_b, + c_size_t(numbers_len) + ) + if error: + raise ValueError("monty_multiply failed with error: %d" % error) + + return get_raw_buffer(out) diff --git a/venv/Lib/site-packages/Cryptodome/Math/_IntegerCustom.pyi b/venv/Lib/site-packages/Cryptodome/Math/_IntegerCustom.pyi new file mode 100644 index 0000000..2dd75c7 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Math/_IntegerCustom.pyi @@ -0,0 +1,8 @@ +from typing import Any + +from ._IntegerNative import IntegerNative + +_raw_montgomery = Any + +class IntegerCustom(IntegerNative): + pass diff --git a/venv/Lib/site-packages/Cryptodome/Math/_IntegerGMP.py b/venv/Lib/site-packages/Cryptodome/Math/_IntegerGMP.py new file mode 100644 index 0000000..be77372 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Math/_IntegerGMP.py @@ -0,0 +1,799 @@ +# =================================================================== +# +# Copyright (c) 2014, Legrandin +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# =================================================================== + +import sys +import struct + +from Cryptodome.Util.py3compat import is_native_int + +from Cryptodome.Util._raw_api import (backend, load_lib, + c_ulong, c_size_t, c_uint8_ptr) + +from ._IntegerBase import IntegerBase + +gmp_defs = """typedef unsigned long UNIX_ULONG; + typedef struct { int a; int b; void *c; } MPZ; + typedef MPZ mpz_t[1]; + typedef UNIX_ULONG mp_bitcnt_t; + + void __gmpz_init (mpz_t x); + void __gmpz_init_set (mpz_t rop, const mpz_t op); + void __gmpz_init_set_ui (mpz_t rop, UNIX_ULONG op); + + UNIX_ULONG __gmpz_get_ui (const mpz_t op); + void __gmpz_set (mpz_t rop, const mpz_t op); + void __gmpz_set_ui (mpz_t rop, UNIX_ULONG op); + void __gmpz_add (mpz_t rop, const mpz_t op1, const mpz_t op2); + void __gmpz_add_ui (mpz_t rop, const mpz_t op1, UNIX_ULONG op2); + void __gmpz_sub_ui (mpz_t rop, const mpz_t op1, UNIX_ULONG op2); + void __gmpz_addmul (mpz_t rop, const mpz_t op1, const mpz_t op2); + void __gmpz_addmul_ui (mpz_t rop, const mpz_t op1, UNIX_ULONG op2); + void __gmpz_submul_ui (mpz_t rop, const mpz_t op1, UNIX_ULONG op2); + void __gmpz_import (mpz_t rop, size_t count, int order, size_t size, + int endian, size_t nails, const void *op); + void * __gmpz_export (void *rop, size_t *countp, int order, + size_t size, + int endian, size_t nails, const mpz_t op); + size_t __gmpz_sizeinbase (const mpz_t op, int base); + void __gmpz_sub (mpz_t rop, const mpz_t op1, const mpz_t op2); + void __gmpz_mul (mpz_t rop, const mpz_t op1, const mpz_t op2); + void __gmpz_mul_ui (mpz_t rop, const mpz_t op1, UNIX_ULONG op2); + int __gmpz_cmp (const mpz_t op1, const mpz_t op2); + void __gmpz_powm (mpz_t rop, const mpz_t base, const mpz_t exp, const + mpz_t mod); + void __gmpz_powm_ui (mpz_t rop, const mpz_t base, UNIX_ULONG exp, + const mpz_t mod); + void __gmpz_pow_ui (mpz_t rop, const mpz_t base, UNIX_ULONG exp); + void __gmpz_sqrt(mpz_t rop, const mpz_t op); + void __gmpz_mod (mpz_t r, const mpz_t n, const mpz_t d); + void __gmpz_neg (mpz_t rop, const mpz_t op); + void __gmpz_abs (mpz_t rop, const mpz_t op); + void __gmpz_and (mpz_t rop, const mpz_t op1, const mpz_t op2); + void __gmpz_ior (mpz_t rop, const mpz_t op1, const mpz_t op2); + void __gmpz_clear (mpz_t x); + void __gmpz_tdiv_q_2exp (mpz_t q, const mpz_t n, mp_bitcnt_t b); + void __gmpz_fdiv_q (mpz_t q, const mpz_t n, const mpz_t d); + void __gmpz_mul_2exp (mpz_t rop, const mpz_t op1, mp_bitcnt_t op2); + int __gmpz_tstbit (const mpz_t op, mp_bitcnt_t bit_index); + int __gmpz_perfect_square_p (const mpz_t op); + int __gmpz_jacobi (const mpz_t a, const mpz_t b); + void __gmpz_gcd (mpz_t rop, const mpz_t op1, const mpz_t op2); + UNIX_ULONG __gmpz_gcd_ui (mpz_t rop, const mpz_t op1, + UNIX_ULONG op2); + void __gmpz_lcm (mpz_t rop, const mpz_t op1, const mpz_t op2); + int __gmpz_invert (mpz_t rop, const mpz_t op1, const mpz_t op2); + int __gmpz_divisible_p (const mpz_t n, const mpz_t d); + int __gmpz_divisible_ui_p (const mpz_t n, UNIX_ULONG d); + + size_t __gmpz_size (const mpz_t op); + UNIX_ULONG __gmpz_getlimbn (const mpz_t op, size_t n); + """ + +if sys.platform == "win32": + raise ImportError("Not using GMP on Windows") + +lib = load_lib("gmp", gmp_defs) +implementation = {"library": "gmp", "api": backend} + +if hasattr(lib, "__mpir_version"): + raise ImportError("MPIR library detected") + + +# Lazy creation of GMP methods +class _GMP(object): + + def __getattr__(self, name): + if name.startswith("mpz_"): + func_name = "__gmpz_" + name[4:] + elif name.startswith("gmp_"): + func_name = "__gmp_" + name[4:] + else: + raise AttributeError("Attribute %s is invalid" % name) + func = getattr(lib, func_name) + setattr(self, name, func) + return func + + +_gmp = _GMP() + + +# In order to create a function that returns a pointer to +# a new MPZ structure, we need to break the abstraction +# and know exactly what ffi backend we have +if implementation["api"] == "ctypes": + from ctypes import Structure, c_int, c_void_p, byref + + class _MPZ(Structure): + _fields_ = [('_mp_alloc', c_int), + ('_mp_size', c_int), + ('_mp_d', c_void_p)] + + def new_mpz(): + return byref(_MPZ()) + + _gmp.mpz_getlimbn.restype = c_ulong + +else: + # We are using CFFI + from Cryptodome.Util._raw_api import ffi + + def new_mpz(): + return ffi.new("MPZ*") + + +# Size of a native word +_sys_bits = 8 * struct.calcsize("P") + + +class IntegerGMP(IntegerBase): + """A fast, arbitrary precision integer""" + + _zero_mpz_p = new_mpz() + _gmp.mpz_init_set_ui(_zero_mpz_p, c_ulong(0)) + + def __init__(self, value): + """Initialize the integer to the given value.""" + + self._mpz_p = new_mpz() + self._initialized = False + + if isinstance(value, float): + raise ValueError("A floating point type is not a natural number") + + if is_native_int(value): + _gmp.mpz_init(self._mpz_p) + self._initialized = True + if value == 0: + return + + tmp = new_mpz() + _gmp.mpz_init(tmp) + + try: + positive = value >= 0 + reduce = abs(value) + slots = (reduce.bit_length() - 1) // 32 + 1 + + while slots > 0: + slots = slots - 1 + _gmp.mpz_set_ui(tmp, + c_ulong(0xFFFFFFFF & (reduce >> (slots * 32)))) + _gmp.mpz_mul_2exp(tmp, tmp, c_ulong(slots * 32)) + _gmp.mpz_add(self._mpz_p, self._mpz_p, tmp) + finally: + _gmp.mpz_clear(tmp) + + if not positive: + _gmp.mpz_neg(self._mpz_p, self._mpz_p) + + elif isinstance(value, IntegerGMP): + _gmp.mpz_init_set(self._mpz_p, value._mpz_p) + self._initialized = True + else: + raise NotImplementedError + + # Conversions + def __int__(self): + tmp = new_mpz() + _gmp.mpz_init_set(tmp, self._mpz_p) + + try: + value = 0 + slot = 0 + while _gmp.mpz_cmp(tmp, self._zero_mpz_p) != 0: + lsb = _gmp.mpz_get_ui(tmp) & 0xFFFFFFFF + value |= lsb << (slot * 32) + _gmp.mpz_tdiv_q_2exp(tmp, tmp, c_ulong(32)) + slot = slot + 1 + finally: + _gmp.mpz_clear(tmp) + + if self < 0: + value = -value + return int(value) + + def __str__(self): + return str(int(self)) + + def __repr__(self): + return "Integer(%s)" % str(self) + + # Only Python 2.x + def __hex__(self): + return hex(int(self)) + + # Only Python 3.x + def __index__(self): + return int(self) + + def to_bytes(self, block_size=0, byteorder='big'): + """Convert the number into a byte string. + + This method encodes the number in network order and prepends + as many zero bytes as required. It only works for non-negative + values. + + :Parameters: + block_size : integer + The exact size the output byte string must have. + If zero, the string has the minimal length. + byteorder : string + 'big' for big-endian integers (default), 'little' for litte-endian. + :Returns: + A byte string. + :Raise ValueError: + If the value is negative or if ``block_size`` is + provided and the length of the byte string would exceed it. + """ + + if self < 0: + raise ValueError("Conversion only valid for non-negative numbers") + + num_limbs = _gmp.mpz_size(self._mpz_p) + if _sys_bits == 32: + spchar = "L" + num_limbs = max(1, num_limbs, (block_size + 3) // 4) + elif _sys_bits == 64: + spchar = "Q" + num_limbs = max(1, num_limbs, (block_size + 7) // 8) + else: + raise ValueError("Unknown limb size") + + # mpz_getlimbn returns 0 if i is larger than the number of actual limbs + limbs = [_gmp.mpz_getlimbn(self._mpz_p, num_limbs - i - 1) for i in range(num_limbs)] + + result = struct.pack(">" + spchar * num_limbs, *limbs) + cutoff_len = len(result) - block_size + if block_size == 0: + result = result.lstrip(b'\x00') + elif cutoff_len > 0: + if result[:cutoff_len] != b'\x00' * (cutoff_len): + raise ValueError("Number is too big to convert to " + "byte string of prescribed length") + result = result[cutoff_len:] + elif cutoff_len < 0: + result = b'\x00' * (-cutoff_len) + result + + if byteorder == 'little': + result = result[::-1] + elif byteorder == 'big': + pass + else: + raise ValueError("Incorrect byteorder") + + if len(result) == 0: + result = b'\x00' + + return result + + @staticmethod + def from_bytes(byte_string, byteorder='big'): + """Convert a byte string into a number. + + :Parameters: + byte_string : byte string + The input number, encoded in network order. + It can only be non-negative. + byteorder : string + 'big' for big-endian integers (default), 'little' for litte-endian. + + :Return: + The ``Integer`` object carrying the same value as the input. + """ + result = IntegerGMP(0) + if byteorder == 'big': + pass + elif byteorder == 'little': + byte_string = bytearray(byte_string) + byte_string.reverse() + else: + raise ValueError("Incorrect byteorder") + _gmp.mpz_import( + result._mpz_p, + c_size_t(len(byte_string)), # Amount of words to read + 1, # Big endian + c_size_t(1), # Each word is 1 byte long + 0, # Endianess within a word - not relevant + c_size_t(0), # No nails + c_uint8_ptr(byte_string)) + return result + + # Relations + def _apply_and_return(self, func, term): + if not isinstance(term, IntegerGMP): + term = IntegerGMP(term) + return func(self._mpz_p, term._mpz_p) + + def __eq__(self, term): + if not (isinstance(term, IntegerGMP) or is_native_int(term)): + return False + return self._apply_and_return(_gmp.mpz_cmp, term) == 0 + + def __ne__(self, term): + if not (isinstance(term, IntegerGMP) or is_native_int(term)): + return True + return self._apply_and_return(_gmp.mpz_cmp, term) != 0 + + def __lt__(self, term): + return self._apply_and_return(_gmp.mpz_cmp, term) < 0 + + def __le__(self, term): + return self._apply_and_return(_gmp.mpz_cmp, term) <= 0 + + def __gt__(self, term): + return self._apply_and_return(_gmp.mpz_cmp, term) > 0 + + def __ge__(self, term): + return self._apply_and_return(_gmp.mpz_cmp, term) >= 0 + + def __nonzero__(self): + return _gmp.mpz_cmp(self._mpz_p, self._zero_mpz_p) != 0 + __bool__ = __nonzero__ + + def is_negative(self): + return _gmp.mpz_cmp(self._mpz_p, self._zero_mpz_p) < 0 + + # Arithmetic operations + def __add__(self, term): + result = IntegerGMP(0) + if not isinstance(term, IntegerGMP): + try: + term = IntegerGMP(term) + except NotImplementedError: + return NotImplemented + _gmp.mpz_add(result._mpz_p, + self._mpz_p, + term._mpz_p) + return result + + def __sub__(self, term): + result = IntegerGMP(0) + if not isinstance(term, IntegerGMP): + try: + term = IntegerGMP(term) + except NotImplementedError: + return NotImplemented + _gmp.mpz_sub(result._mpz_p, + self._mpz_p, + term._mpz_p) + return result + + def __mul__(self, term): + result = IntegerGMP(0) + if not isinstance(term, IntegerGMP): + try: + term = IntegerGMP(term) + except NotImplementedError: + return NotImplemented + _gmp.mpz_mul(result._mpz_p, + self._mpz_p, + term._mpz_p) + return result + + def __floordiv__(self, divisor): + if not isinstance(divisor, IntegerGMP): + divisor = IntegerGMP(divisor) + if _gmp.mpz_cmp(divisor._mpz_p, + self._zero_mpz_p) == 0: + raise ZeroDivisionError("Division by zero") + result = IntegerGMP(0) + _gmp.mpz_fdiv_q(result._mpz_p, + self._mpz_p, + divisor._mpz_p) + return result + + def __mod__(self, divisor): + if not isinstance(divisor, IntegerGMP): + divisor = IntegerGMP(divisor) + comp = _gmp.mpz_cmp(divisor._mpz_p, + self._zero_mpz_p) + if comp == 0: + raise ZeroDivisionError("Division by zero") + if comp < 0: + raise ValueError("Modulus must be positive") + result = IntegerGMP(0) + _gmp.mpz_mod(result._mpz_p, + self._mpz_p, + divisor._mpz_p) + return result + + def inplace_pow(self, exponent, modulus=None): + + if modulus is None: + if exponent < 0: + raise ValueError("Exponent must not be negative") + + # Normal exponentiation + if exponent > 256: + raise ValueError("Exponent is too big") + _gmp.mpz_pow_ui(self._mpz_p, + self._mpz_p, # Base + c_ulong(int(exponent)) + ) + else: + # Modular exponentiation + if not isinstance(modulus, IntegerGMP): + modulus = IntegerGMP(modulus) + if not modulus: + raise ZeroDivisionError("Division by zero") + if modulus.is_negative(): + raise ValueError("Modulus must be positive") + if is_native_int(exponent): + if exponent < 0: + raise ValueError("Exponent must not be negative") + if exponent < 65536: + _gmp.mpz_powm_ui(self._mpz_p, + self._mpz_p, + c_ulong(exponent), + modulus._mpz_p) + return self + exponent = IntegerGMP(exponent) + elif exponent.is_negative(): + raise ValueError("Exponent must not be negative") + _gmp.mpz_powm(self._mpz_p, + self._mpz_p, + exponent._mpz_p, + modulus._mpz_p) + return self + + def __pow__(self, exponent, modulus=None): + result = IntegerGMP(self) + return result.inplace_pow(exponent, modulus) + + def __abs__(self): + result = IntegerGMP(0) + _gmp.mpz_abs(result._mpz_p, self._mpz_p) + return result + + def sqrt(self, modulus=None): + """Return the largest Integer that does not + exceed the square root""" + + if modulus is None: + if self < 0: + raise ValueError("Square root of negative value") + result = IntegerGMP(0) + _gmp.mpz_sqrt(result._mpz_p, + self._mpz_p) + else: + if modulus <= 0: + raise ValueError("Modulus must be positive") + modulus = int(modulus) + result = IntegerGMP(self._tonelli_shanks(int(self) % modulus, modulus)) + + return result + + def __iadd__(self, term): + if is_native_int(term): + if 0 <= term < 65536: + _gmp.mpz_add_ui(self._mpz_p, + self._mpz_p, + c_ulong(term)) + return self + if -65535 < term < 0: + _gmp.mpz_sub_ui(self._mpz_p, + self._mpz_p, + c_ulong(-term)) + return self + term = IntegerGMP(term) + _gmp.mpz_add(self._mpz_p, + self._mpz_p, + term._mpz_p) + return self + + def __isub__(self, term): + if is_native_int(term): + if 0 <= term < 65536: + _gmp.mpz_sub_ui(self._mpz_p, + self._mpz_p, + c_ulong(term)) + return self + if -65535 < term < 0: + _gmp.mpz_add_ui(self._mpz_p, + self._mpz_p, + c_ulong(-term)) + return self + term = IntegerGMP(term) + _gmp.mpz_sub(self._mpz_p, + self._mpz_p, + term._mpz_p) + return self + + def __imul__(self, term): + if is_native_int(term): + if 0 <= term < 65536: + _gmp.mpz_mul_ui(self._mpz_p, + self._mpz_p, + c_ulong(term)) + return self + if -65535 < term < 0: + _gmp.mpz_mul_ui(self._mpz_p, + self._mpz_p, + c_ulong(-term)) + _gmp.mpz_neg(self._mpz_p, self._mpz_p) + return self + term = IntegerGMP(term) + _gmp.mpz_mul(self._mpz_p, + self._mpz_p, + term._mpz_p) + return self + + def __imod__(self, divisor): + if not isinstance(divisor, IntegerGMP): + divisor = IntegerGMP(divisor) + comp = _gmp.mpz_cmp(divisor._mpz_p, + divisor._zero_mpz_p) + if comp == 0: + raise ZeroDivisionError("Division by zero") + if comp < 0: + raise ValueError("Modulus must be positive") + _gmp.mpz_mod(self._mpz_p, + self._mpz_p, + divisor._mpz_p) + return self + + # Boolean/bit operations + def __and__(self, term): + result = IntegerGMP(0) + if not isinstance(term, IntegerGMP): + term = IntegerGMP(term) + _gmp.mpz_and(result._mpz_p, + self._mpz_p, + term._mpz_p) + return result + + def __or__(self, term): + result = IntegerGMP(0) + if not isinstance(term, IntegerGMP): + term = IntegerGMP(term) + _gmp.mpz_ior(result._mpz_p, + self._mpz_p, + term._mpz_p) + return result + + def __rshift__(self, pos): + result = IntegerGMP(0) + if pos < 0: + raise ValueError("negative shift count") + if pos > 65536: + if self < 0: + return -1 + else: + return 0 + _gmp.mpz_tdiv_q_2exp(result._mpz_p, + self._mpz_p, + c_ulong(int(pos))) + return result + + def __irshift__(self, pos): + if pos < 0: + raise ValueError("negative shift count") + if pos > 65536: + if self < 0: + return -1 + else: + return 0 + _gmp.mpz_tdiv_q_2exp(self._mpz_p, + self._mpz_p, + c_ulong(int(pos))) + return self + + def __lshift__(self, pos): + result = IntegerGMP(0) + if not 0 <= pos < 65536: + raise ValueError("Incorrect shift count") + _gmp.mpz_mul_2exp(result._mpz_p, + self._mpz_p, + c_ulong(int(pos))) + return result + + def __ilshift__(self, pos): + if not 0 <= pos < 65536: + raise ValueError("Incorrect shift count") + _gmp.mpz_mul_2exp(self._mpz_p, + self._mpz_p, + c_ulong(int(pos))) + return self + + def get_bit(self, n): + """Return True if the n-th bit is set to 1. + Bit 0 is the least significant.""" + + if self < 0: + raise ValueError("no bit representation for negative values") + if n < 0: + raise ValueError("negative bit count") + if n > 65536: + return 0 + return bool(_gmp.mpz_tstbit(self._mpz_p, + c_ulong(int(n)))) + + # Extra + def is_odd(self): + return _gmp.mpz_tstbit(self._mpz_p, 0) == 1 + + def is_even(self): + return _gmp.mpz_tstbit(self._mpz_p, 0) == 0 + + def size_in_bits(self): + """Return the minimum number of bits that can encode the number.""" + + if self < 0: + raise ValueError("Conversion only valid for non-negative numbers") + return _gmp.mpz_sizeinbase(self._mpz_p, 2) + + def size_in_bytes(self): + """Return the minimum number of bytes that can encode the number.""" + return (self.size_in_bits() - 1) // 8 + 1 + + def is_perfect_square(self): + return _gmp.mpz_perfect_square_p(self._mpz_p) != 0 + + def fail_if_divisible_by(self, small_prime): + """Raise an exception if the small prime is a divisor.""" + + if is_native_int(small_prime): + if 0 < small_prime < 65536: + if _gmp.mpz_divisible_ui_p(self._mpz_p, + c_ulong(small_prime)): + raise ValueError("The value is composite") + return + small_prime = IntegerGMP(small_prime) + if _gmp.mpz_divisible_p(self._mpz_p, + small_prime._mpz_p): + raise ValueError("The value is composite") + + def multiply_accumulate(self, a, b): + """Increment the number by the product of a and b.""" + + if not isinstance(a, IntegerGMP): + a = IntegerGMP(a) + if is_native_int(b): + if 0 < b < 65536: + _gmp.mpz_addmul_ui(self._mpz_p, + a._mpz_p, + c_ulong(b)) + return self + if -65535 < b < 0: + _gmp.mpz_submul_ui(self._mpz_p, + a._mpz_p, + c_ulong(-b)) + return self + b = IntegerGMP(b) + _gmp.mpz_addmul(self._mpz_p, + a._mpz_p, + b._mpz_p) + return self + + def set(self, source): + """Set the Integer to have the given value""" + + if not isinstance(source, IntegerGMP): + source = IntegerGMP(source) + _gmp.mpz_set(self._mpz_p, + source._mpz_p) + return self + + def inplace_inverse(self, modulus): + """Compute the inverse of this number in the ring of + modulo integers. + + Raise an exception if no inverse exists. + """ + + if not isinstance(modulus, IntegerGMP): + modulus = IntegerGMP(modulus) + + comp = _gmp.mpz_cmp(modulus._mpz_p, + self._zero_mpz_p) + if comp == 0: + raise ZeroDivisionError("Modulus cannot be zero") + if comp < 0: + raise ValueError("Modulus must be positive") + + result = _gmp.mpz_invert(self._mpz_p, + self._mpz_p, + modulus._mpz_p) + if not result: + raise ValueError("No inverse value can be computed") + return self + + def inverse(self, modulus): + result = IntegerGMP(self) + result.inplace_inverse(modulus) + return result + + def gcd(self, term): + """Compute the greatest common denominator between this + number and another term.""" + + result = IntegerGMP(0) + if is_native_int(term): + if 0 < term < 65535: + _gmp.mpz_gcd_ui(result._mpz_p, + self._mpz_p, + c_ulong(term)) + return result + term = IntegerGMP(term) + _gmp.mpz_gcd(result._mpz_p, self._mpz_p, term._mpz_p) + return result + + def lcm(self, term): + """Compute the least common multiplier between this + number and another term.""" + + result = IntegerGMP(0) + if not isinstance(term, IntegerGMP): + term = IntegerGMP(term) + _gmp.mpz_lcm(result._mpz_p, self._mpz_p, term._mpz_p) + return result + + @staticmethod + def jacobi_symbol(a, n): + """Compute the Jacobi symbol""" + + if not isinstance(a, IntegerGMP): + a = IntegerGMP(a) + if not isinstance(n, IntegerGMP): + n = IntegerGMP(n) + if n <= 0 or n.is_even(): + raise ValueError("n must be positive odd for the Jacobi symbol") + return _gmp.mpz_jacobi(a._mpz_p, n._mpz_p) + + @staticmethod + def _mult_modulo_bytes(term1, term2, modulus): + if not isinstance(term1, IntegerGMP): + term1 = IntegerGMP(term1) + if not isinstance(term2, IntegerGMP): + term2 = IntegerGMP(term2) + if not isinstance(modulus, IntegerGMP): + modulus = IntegerGMP(modulus) + + if modulus < 0: + raise ValueError("Modulus must be positive") + if modulus == 0: + raise ZeroDivisionError("Modulus cannot be zero") + if (modulus & 1) == 0: + raise ValueError("Odd modulus is required") + + product = (term1 * term2) % modulus + return product.to_bytes(modulus.size_in_bytes()) + + # Clean-up + def __del__(self): + + try: + if self._mpz_p is not None: + if self._initialized: + _gmp.mpz_clear(self._mpz_p) + + self._mpz_p = None + except AttributeError: + pass diff --git a/venv/Lib/site-packages/Cryptodome/Math/_IntegerGMP.pyi b/venv/Lib/site-packages/Cryptodome/Math/_IntegerGMP.pyi new file mode 100644 index 0000000..2181b47 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Math/_IntegerGMP.pyi @@ -0,0 +1,3 @@ +from ._IntegerBase import IntegerBase +class IntegerGMP(IntegerBase): + pass diff --git a/venv/Lib/site-packages/Cryptodome/Math/_IntegerNative.py b/venv/Lib/site-packages/Cryptodome/Math/_IntegerNative.py new file mode 100644 index 0000000..5f768e2 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Math/_IntegerNative.py @@ -0,0 +1,382 @@ +# =================================================================== +# +# Copyright (c) 2014, Legrandin +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# =================================================================== + +from ._IntegerBase import IntegerBase + +from Cryptodome.Util.number import long_to_bytes, bytes_to_long, inverse, GCD + + +class IntegerNative(IntegerBase): + """A class to model a natural integer (including zero)""" + + def __init__(self, value): + if isinstance(value, float): + raise ValueError("A floating point type is not a natural number") + try: + self._value = value._value + except AttributeError: + self._value = value + + # Conversions + def __int__(self): + return self._value + + def __str__(self): + return str(int(self)) + + def __repr__(self): + return "Integer(%s)" % str(self) + + # Only Python 2.x + def __hex__(self): + return hex(self._value) + + # Only Python 3.x + def __index__(self): + return int(self._value) + + def to_bytes(self, block_size=0, byteorder='big'): + if self._value < 0: + raise ValueError("Conversion only valid for non-negative numbers") + result = long_to_bytes(self._value, block_size) + if len(result) > block_size > 0: + raise ValueError("Value too large to encode") + if byteorder == 'big': + pass + elif byteorder == 'little': + result = bytearray(result) + result.reverse() + result = bytes(result) + else: + raise ValueError("Incorrect byteorder") + return result + + @classmethod + def from_bytes(cls, byte_string, byteorder='big'): + if byteorder == 'big': + pass + elif byteorder == 'little': + byte_string = bytearray(byte_string) + byte_string.reverse() + else: + raise ValueError("Incorrect byteorder") + return cls(bytes_to_long(byte_string)) + + # Relations + def __eq__(self, term): + if term is None: + return False + return self._value == int(term) + + def __ne__(self, term): + return not self.__eq__(term) + + def __lt__(self, term): + return self._value < int(term) + + def __le__(self, term): + return self.__lt__(term) or self.__eq__(term) + + def __gt__(self, term): + return not self.__le__(term) + + def __ge__(self, term): + return not self.__lt__(term) + + def __nonzero__(self): + return self._value != 0 + __bool__ = __nonzero__ + + def is_negative(self): + return self._value < 0 + + # Arithmetic operations + def __add__(self, term): + try: + return self.__class__(self._value + int(term)) + except (ValueError, AttributeError, TypeError): + return NotImplemented + + def __sub__(self, term): + try: + return self.__class__(self._value - int(term)) + except (ValueError, AttributeError, TypeError): + return NotImplemented + + def __mul__(self, factor): + try: + return self.__class__(self._value * int(factor)) + except (ValueError, AttributeError, TypeError): + return NotImplemented + + def __floordiv__(self, divisor): + return self.__class__(self._value // int(divisor)) + + def __mod__(self, divisor): + divisor_value = int(divisor) + if divisor_value < 0: + raise ValueError("Modulus must be positive") + return self.__class__(self._value % divisor_value) + + def inplace_pow(self, exponent, modulus=None): + exp_value = int(exponent) + if exp_value < 0: + raise ValueError("Exponent must not be negative") + + if modulus is not None: + mod_value = int(modulus) + if mod_value < 0: + raise ValueError("Modulus must be positive") + if mod_value == 0: + raise ZeroDivisionError("Modulus cannot be zero") + else: + mod_value = None + self._value = pow(self._value, exp_value, mod_value) + return self + + def __pow__(self, exponent, modulus=None): + result = self.__class__(self) + return result.inplace_pow(exponent, modulus) + + def __abs__(self): + return abs(self._value) + + def sqrt(self, modulus=None): + + value = self._value + if modulus is None: + if value < 0: + raise ValueError("Square root of negative value") + # http://stackoverflow.com/questions/15390807/integer-square-root-in-python + + x = value + y = (x + 1) // 2 + while y < x: + x = y + y = (x + value // x) // 2 + result = x + else: + if modulus <= 0: + raise ValueError("Modulus must be positive") + result = self._tonelli_shanks(self % modulus, modulus) + + return self.__class__(result) + + def __iadd__(self, term): + self._value += int(term) + return self + + def __isub__(self, term): + self._value -= int(term) + return self + + def __imul__(self, term): + self._value *= int(term) + return self + + def __imod__(self, term): + modulus = int(term) + if modulus == 0: + raise ZeroDivisionError("Division by zero") + if modulus < 0: + raise ValueError("Modulus must be positive") + self._value %= modulus + return self + + # Boolean/bit operations + def __and__(self, term): + return self.__class__(self._value & int(term)) + + def __or__(self, term): + return self.__class__(self._value | int(term)) + + def __rshift__(self, pos): + try: + return self.__class__(self._value >> int(pos)) + except OverflowError: + if self._value >= 0: + return 0 + else: + return -1 + + def __irshift__(self, pos): + try: + self._value >>= int(pos) + except OverflowError: + if self._value >= 0: + return 0 + else: + return -1 + return self + + def __lshift__(self, pos): + try: + return self.__class__(self._value << int(pos)) + except OverflowError: + raise ValueError("Incorrect shift count") + + def __ilshift__(self, pos): + try: + self._value <<= int(pos) + except OverflowError: + raise ValueError("Incorrect shift count") + return self + + def get_bit(self, n): + if self._value < 0: + raise ValueError("no bit representation for negative values") + try: + try: + result = (self._value >> n._value) & 1 + if n._value < 0: + raise ValueError("negative bit count") + except AttributeError: + result = (self._value >> n) & 1 + if n < 0: + raise ValueError("negative bit count") + except OverflowError: + result = 0 + return result + + # Extra + def is_odd(self): + return (self._value & 1) == 1 + + def is_even(self): + return (self._value & 1) == 0 + + def size_in_bits(self): + + if self._value < 0: + raise ValueError("Conversion only valid for non-negative numbers") + + if self._value == 0: + return 1 + + return self._value.bit_length() + + def size_in_bytes(self): + return (self.size_in_bits() - 1) // 8 + 1 + + def is_perfect_square(self): + if self._value < 0: + return False + if self._value in (0, 1): + return True + + x = self._value // 2 + square_x = x ** 2 + + while square_x > self._value: + x = (square_x + self._value) // (2 * x) + square_x = x ** 2 + + return self._value == x ** 2 + + def fail_if_divisible_by(self, small_prime): + if (self._value % int(small_prime)) == 0: + raise ValueError("Value is composite") + + def multiply_accumulate(self, a, b): + self._value += int(a) * int(b) + return self + + def set(self, source): + self._value = int(source) + + def inplace_inverse(self, modulus): + self._value = inverse(self._value, int(modulus)) + return self + + def inverse(self, modulus): + result = self.__class__(self) + result.inplace_inverse(modulus) + return result + + def gcd(self, term): + return self.__class__(GCD(abs(self._value), abs(int(term)))) + + def lcm(self, term): + term = int(term) + if self._value == 0 or term == 0: + return self.__class__(0) + return self.__class__(abs((self._value * term) // self.gcd(term)._value)) + + @staticmethod + def jacobi_symbol(a, n): + a = int(a) + n = int(n) + + if n <= 0: + raise ValueError("n must be a positive integer") + + if (n & 1) == 0: + raise ValueError("n must be odd for the Jacobi symbol") + + # Step 1 + a = a % n + # Step 2 + if a == 1 or n == 1: + return 1 + # Step 3 + if a == 0: + return 0 + # Step 4 + e = 0 + a1 = a + while (a1 & 1) == 0: + a1 >>= 1 + e += 1 + # Step 5 + if (e & 1) == 0: + s = 1 + elif n % 8 in (1, 7): + s = 1 + else: + s = -1 + # Step 6 + if n % 4 == 3 and a1 % 4 == 3: + s = -s + # Step 7 + n1 = n % a1 + # Step 8 + return s * IntegerNative.jacobi_symbol(n1, a1) + + @staticmethod + def _mult_modulo_bytes(term1, term2, modulus): + if modulus < 0: + raise ValueError("Modulus must be positive") + if modulus == 0: + raise ZeroDivisionError("Modulus cannot be zero") + if (modulus & 1) == 0: + raise ValueError("Odd modulus is required") + + number_len = len(long_to_bytes(modulus)) + return long_to_bytes((term1 * term2) % modulus, number_len) diff --git a/venv/Lib/site-packages/Cryptodome/Math/_IntegerNative.pyi b/venv/Lib/site-packages/Cryptodome/Math/_IntegerNative.pyi new file mode 100644 index 0000000..3f65a39 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Math/_IntegerNative.pyi @@ -0,0 +1,3 @@ +from ._IntegerBase import IntegerBase +class IntegerNative(IntegerBase): + pass diff --git a/venv/Lib/site-packages/Cryptodome/Math/__init__.py b/venv/Lib/site-packages/Cryptodome/Math/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/venv/Lib/site-packages/Cryptodome/Math/__pycache__/Numbers.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/Math/__pycache__/Numbers.cpython-312.pyc new file mode 100644 index 0000000..83ca990 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Math/__pycache__/Numbers.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/Math/__pycache__/Primality.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/Math/__pycache__/Primality.cpython-312.pyc new file mode 100644 index 0000000..93df83d Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Math/__pycache__/Primality.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/Math/__pycache__/_IntegerBase.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/Math/__pycache__/_IntegerBase.cpython-312.pyc new file mode 100644 index 0000000..8bcdd55 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Math/__pycache__/_IntegerBase.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/Math/__pycache__/_IntegerCustom.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/Math/__pycache__/_IntegerCustom.cpython-312.pyc new file mode 100644 index 0000000..4a8251c Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Math/__pycache__/_IntegerCustom.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/Math/__pycache__/_IntegerGMP.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/Math/__pycache__/_IntegerGMP.cpython-312.pyc new file mode 100644 index 0000000..f036a0c Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Math/__pycache__/_IntegerGMP.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/Math/__pycache__/_IntegerNative.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/Math/__pycache__/_IntegerNative.cpython-312.pyc new file mode 100644 index 0000000..6df66bc Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Math/__pycache__/_IntegerNative.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/Math/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/Math/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000..00045e6 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Math/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/Math/_modexp.pyd b/venv/Lib/site-packages/Cryptodome/Math/_modexp.pyd new file mode 100644 index 0000000..d783b62 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Math/_modexp.pyd differ diff --git a/venv/Lib/site-packages/Cryptodome/Protocol/DH.py b/venv/Lib/site-packages/Cryptodome/Protocol/DH.py new file mode 100644 index 0000000..41793c1 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Protocol/DH.py @@ -0,0 +1,192 @@ +from Cryptodome.Util.number import long_to_bytes +from Cryptodome.PublicKey.ECC import (EccKey, + construct, + _import_curve25519_public_key, + _import_curve448_public_key) + + +def _compute_ecdh(key_priv, key_pub): + pointP = key_pub.pointQ * key_priv.d + if pointP.is_point_at_infinity(): + raise ValueError("Invalid ECDH point") + + if key_priv.curve == "Curve25519": + z = bytearray(pointP.x.to_bytes(32, byteorder='little')) + elif key_priv.curve == "Curve448": + z = bytearray(pointP.x.to_bytes(56, byteorder='little')) + else: + # See Section 5.7.1.2 in NIST SP 800-56Ar3 + z = long_to_bytes(pointP.x, pointP.size_in_bytes()) + return z + + +def import_x25519_public_key(encoded): + """Create a new X25519 public key object, + starting from the key encoded as raw ``bytes``, + in the format described in RFC7748. + + Args: + encoded (bytes): + The x25519 public key to import. + It must be 32 bytes. + + Returns: + :class:`Cryptodome.PublicKey.EccKey` : a new ECC key object. + + Raises: + ValueError: when the given key cannot be parsed. + """ + + x = _import_curve25519_public_key(encoded) + return construct(curve='Curve25519', point_x=x) + + +def import_x25519_private_key(encoded): + """Create a new X25519 private key object, + starting from the key encoded as raw ``bytes``, + in the format described in RFC7748. + + Args: + encoded (bytes): + The X25519 private key to import. + It must be 32 bytes. + + Returns: + :class:`Cryptodome.PublicKey.EccKey` : a new ECC key object. + + Raises: + ValueError: when the given key cannot be parsed. + """ + + return construct(seed=encoded, curve="Curve25519") + + +def import_x448_public_key(encoded): + """Create a new X448 public key object, + starting from the key encoded as raw ``bytes``, + in the format described in RFC7748. + + Args: + encoded (bytes): + The x448 public key to import. + It must be 56 bytes. + + Returns: + :class:`Cryptodome.PublicKey.EccKey` : a new ECC key object. + + Raises: + ValueError: when the given key cannot be parsed. + """ + + x = _import_curve448_public_key(encoded) + return construct(curve='Curve448', point_x=x) + + +def import_x448_private_key(encoded): + """Create a new X448 private key object, + starting from the key encoded as raw ``bytes``, + in the format described in RFC7748. + + Args: + encoded (bytes): + The X448 private key to import. + It must be 56 bytes. + + Returns: + :class:`Cryptodome.PublicKey.EccKey` : a new ECC key object. + + Raises: + ValueError: when the given key cannot be parsed. + """ + + return construct(seed=encoded, curve="Curve448") + + +def key_agreement(**kwargs): + """Perform a Diffie-Hellman key agreement. + + Keywords: + kdf (callable): + A key derivation function that accepts ``bytes`` as input and returns + ``bytes``. + static_priv (EccKey): + The local static private key. Optional. + static_pub (EccKey): + The static public key that belongs to the peer. Optional. + eph_priv (EccKey): + The local ephemeral private key, generated for this session. Optional. + eph_pub (EccKey): + The ephemeral public key, received from the peer for this session. Optional. + + At least two keys must be passed, of which one is a private key and one + a public key. + + Returns (bytes): + The derived secret key material. + """ + + static_priv = kwargs.get('static_priv', None) + static_pub = kwargs.get('static_pub', None) + eph_priv = kwargs.get('eph_priv', None) + eph_pub = kwargs.get('eph_pub', None) + kdf = kwargs.get('kdf', None) + + if kdf is None: + raise ValueError("'kdf' is mandatory") + + count_priv = 0 + count_pub = 0 + curve = None + + def check_curve(curve, key, name, private): + if not isinstance(key, EccKey): + raise TypeError("'%s' must be an ECC key" % name) + if private and not key.has_private(): + raise TypeError("'%s' must be a private ECC key" % name) + if curve is None: + curve = key.curve + elif curve != key.curve: + raise TypeError("'%s' is defined on an incompatible curve" % name) + return curve + + if static_priv is not None: + curve = check_curve(curve, static_priv, 'static_priv', True) + count_priv += 1 + + if static_pub is not None: + curve = check_curve(curve, static_pub, 'static_pub', False) + count_pub += 1 + + if eph_priv is not None: + curve = check_curve(curve, eph_priv, 'eph_priv', True) + count_priv += 1 + + if eph_pub is not None: + curve = check_curve(curve, eph_pub, 'eph_pub', False) + count_pub += 1 + + if (count_priv + count_pub) < 2 or count_priv == 0 or count_pub == 0: + raise ValueError("Too few keys for the ECDH key agreement") + + Zs = b'' + Ze = b'' + + if static_priv and static_pub: + # C(*, 2s) + Zs = _compute_ecdh(static_priv, static_pub) + + if eph_priv and eph_pub: + # C(2e, 0s) or C(2e, 2s) + if bool(static_priv) != bool(static_pub): + raise ValueError("DH mode C(2e, 1s) is not supported") + Ze = _compute_ecdh(eph_priv, eph_pub) + elif eph_priv and static_pub: + # C(1e, 2s) or C(1e, 1s) + Ze = _compute_ecdh(eph_priv, static_pub) + elif eph_pub and static_priv: + # C(1e, 2s) or C(1e, 1s) + Ze = _compute_ecdh(static_priv, eph_pub) + + Z = Ze + Zs + + return kdf(Z) diff --git a/venv/Lib/site-packages/Cryptodome/Protocol/DH.pyi b/venv/Lib/site-packages/Cryptodome/Protocol/DH.pyi new file mode 100644 index 0000000..017d863 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Protocol/DH.pyi @@ -0,0 +1,19 @@ +from typing import TypedDict, Callable, TypeVar, Generic +from typing_extensions import Unpack, NotRequired + +from Cryptodome.PublicKey.ECC import EccKey + +T = TypeVar('T') + +class RequestParams(TypedDict, Generic[T]): + kdf: Callable[[bytes|bytearray|memoryview], T] + static_priv: NotRequired[EccKey] + static_pub: NotRequired[EccKey] + eph_priv: NotRequired[EccKey] + eph_pub: NotRequired[EccKey] + +def import_x25519_public_key(encoded: bytes) -> EccKey: ... +def import_x25519_private_key(encoded: bytes) -> EccKey: ... +def import_x448_public_key(encoded: bytes) -> EccKey: ... +def import_x448_private_key(encoded: bytes) -> EccKey: ... +def key_agreement(**kwargs: Unpack[RequestParams[T]]) -> T: ... diff --git a/venv/Lib/site-packages/Cryptodome/Protocol/HPKE.py b/venv/Lib/site-packages/Cryptodome/Protocol/HPKE.py new file mode 100644 index 0000000..13823ec --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Protocol/HPKE.py @@ -0,0 +1,483 @@ +import struct +from enum import IntEnum + +from types import ModuleType +from typing import Optional + +from .KDF import _HKDF_extract, _HKDF_expand +from .DH import key_agreement, import_x25519_public_key, import_x448_public_key +from Cryptodome.Util.strxor import strxor +from Cryptodome.PublicKey import ECC +from Cryptodome.PublicKey.ECC import EccKey +from Cryptodome.Hash import SHA256, SHA384, SHA512 +from Cryptodome.Cipher import AES, ChaCha20_Poly1305 + + +class MODE(IntEnum): + """HPKE modes""" + BASE = 0x00 + PSK = 0x01 + AUTH = 0x02 + AUTH_PSK = 0x03 + + +class AEAD(IntEnum): + """Authenticated Encryption with Associated Data (AEAD) Functions""" + AES128_GCM = 0x0001 + AES256_GCM = 0x0002 + CHACHA20_POLY1305 = 0x0003 + + +class DeserializeError(ValueError): + pass + +class MessageLimitReachedError(ValueError): + pass + +# CURVE to (KEM ID, KDF ID, HASH) +_Curve_Config = { + "NIST P-256": (0x0010, 0x0001, SHA256), + "NIST P-384": (0x0011, 0x0002, SHA384), + "NIST P-521": (0x0012, 0x0003, SHA512), + "Curve25519": (0x0020, 0x0001, SHA256), + "Curve448": (0x0021, 0x0003, SHA512), +} + + +def _labeled_extract(salt: bytes, + label: bytes, + ikm: bytes, + suite_id: bytes, + hashmod: ModuleType): + labeled_ikm = b"HPKE-v1" + suite_id + label + ikm + return _HKDF_extract(salt, labeled_ikm, hashmod) + + +def _labeled_expand(prk: bytes, + label: bytes, + info: bytes, + L: int, + suite_id: bytes, + hashmod: ModuleType): + labeled_info = struct.pack('>H', L) + b"HPKE-v1" + suite_id + \ + label + info + return _HKDF_expand(prk, labeled_info, L, hashmod) + + +def _extract_and_expand(dh: bytes, + kem_context: bytes, + suite_id: bytes, + hashmod: ModuleType): + Nsecret = hashmod.digest_size + + eae_prk = _labeled_extract(b"", + b"eae_prk", + dh, + suite_id, + hashmod) + + shared_secret = _labeled_expand(eae_prk, + b"shared_secret", + kem_context, + Nsecret, + suite_id, + hashmod) + return shared_secret + + +class HPKE_Cipher: + + def __init__(self, + receiver_key: EccKey, + enc: Optional[bytes], + sender_key: Optional[EccKey], + psk_pair: tuple[bytes, bytes], + info: bytes, + aead_id: AEAD, + mode: MODE): + + self.enc: bytes = b'' if enc is None else enc + """The encapsulated session key.""" + + self._verify_psk_inputs(mode, psk_pair) + + self._curve = receiver_key.curve + self._aead_id = aead_id + self._mode = mode + + try: + self._kem_id, \ + self._kdf_id, \ + self._hashmod = _Curve_Config[self._curve] + except KeyError as ke: + raise ValueError("Curve {} is not supported by HPKE".format(self._curve)) from ke + + self._Nk = 16 if self._aead_id == AEAD.AES128_GCM else 32 + self._Nn = 12 + self._Nt = 16 + self._Nh = self._hashmod.digest_size + + self._encrypt = not receiver_key.has_private() + + if self._encrypt: + # SetupBaseS (encryption) + if enc is not None: + raise ValueError("Parameter 'enc' cannot be an input when sealing") + shared_secret, self.enc = self._encap(receiver_key, + self._kem_id, + self._hashmod, + sender_key) + else: + # SetupBaseR (decryption) + if enc is None: + raise ValueError("Parameter 'enc' required when unsealing") + shared_secret = self._decap(enc, + receiver_key, + self._kem_id, + self._hashmod, + sender_key) + + self._sequence = 0 + self._max_sequence = (1 << (8 * self._Nn)) - 1 + + self._key, \ + self._base_nonce, \ + self._export_secret = self._key_schedule(shared_secret, + info, + *psk_pair) + + @staticmethod + def _encap(receiver_key: EccKey, + kem_id: int, + hashmod: ModuleType, + sender_key: Optional[EccKey] = None, + eph_key: Optional[EccKey] = None): + + assert (sender_key is None) or sender_key.has_private() + assert (eph_key is None) or eph_key.has_private() + + if eph_key is None: + eph_key = ECC.generate(curve=receiver_key.curve) + enc = eph_key.public_key().export_key(format='raw') + + pkRm = receiver_key.public_key().export_key(format='raw') + kem_context = enc + pkRm + extra_param = {} + if sender_key: + kem_context += sender_key.public_key().export_key(format='raw') + extra_param = {'static_priv': sender_key} + + suite_id = b"KEM" + struct.pack('>H', kem_id) + + def kdf(dh, + kem_context=kem_context, + suite_id=suite_id, + hashmod=hashmod): + return _extract_and_expand(dh, kem_context, suite_id, hashmod) + + shared_secret = key_agreement(eph_priv=eph_key, + static_pub=receiver_key, + kdf=kdf, + **extra_param) + return shared_secret, enc + + @staticmethod + def _decap(enc: bytes, + receiver_key: EccKey, + kem_id: int, + hashmod: ModuleType, + sender_key: Optional[EccKey] = None): + + assert receiver_key.has_private() + + try: + if receiver_key.curve == 'Curve25519': + pkE = import_x25519_public_key(enc) + elif receiver_key.curve == 'Curve448': + pkE = import_x448_public_key(enc) + else: + pkE = ECC.import_key(enc, curve_name=receiver_key.curve) + except ValueError as ve: + raise DeserializeError("'enc' is not a valid encapsulated HPKE key") from ve + + pkRm = receiver_key.public_key().export_key(format='raw') + kem_context = enc + pkRm + extra_param = {} + if sender_key: + kem_context += sender_key.public_key().export_key(format='raw') + extra_param = {'static_pub': sender_key} + + suite_id = b"KEM" + struct.pack('>H', kem_id) + + def kdf(dh, + kem_context=kem_context, + suite_id=suite_id, + hashmod=hashmod): + return _extract_and_expand(dh, kem_context, suite_id, hashmod) + + shared_secret = key_agreement(eph_pub=pkE, + static_priv=receiver_key, + kdf=kdf, + **extra_param) + return shared_secret + + @staticmethod + def _verify_psk_inputs(mode: MODE, psk_pair: tuple[bytes, bytes]): + psk_id, psk = psk_pair + + if (psk == b'') ^ (psk_id == b''): + raise ValueError("Inconsistent PSK inputs") + + if (psk == b''): + if mode in (MODE.PSK, MODE.AUTH_PSK): + raise ValueError(f"PSK is required with mode {mode.name}") + else: + if len(psk) < 32: + raise ValueError("PSK must be at least 32 byte long") + if mode in (MODE.BASE, MODE.AUTH): + raise ValueError("PSK is not compatible with this mode") + + def _key_schedule(self, + shared_secret: bytes, + info: bytes, + psk_id: bytes, + psk: bytes): + + suite_id = b"HPKE" + struct.pack('>HHH', + self._kem_id, + self._kdf_id, + self._aead_id) + + psk_id_hash = _labeled_extract(b'', + b'psk_id_hash', + psk_id, + suite_id, + self._hashmod) + + info_hash = _labeled_extract(b'', + b'info_hash', + info, + suite_id, + self._hashmod) + + key_schedule_context = self._mode.to_bytes(1, 'big') + psk_id_hash + info_hash + + secret = _labeled_extract(shared_secret, + b'secret', + psk, + suite_id, + self._hashmod) + + key = _labeled_expand(secret, + b'key', + key_schedule_context, + self._Nk, + suite_id, + self._hashmod) + + base_nonce = _labeled_expand(secret, + b'base_nonce', + key_schedule_context, + self._Nn, + suite_id, + self._hashmod) + + exporter_secret = _labeled_expand(secret, + b'exp', + key_schedule_context, + self._Nh, + suite_id, + self._hashmod) + + return key, base_nonce, exporter_secret + + def _new_cipher(self): + nonce = strxor(self._base_nonce, self._sequence.to_bytes(self._Nn, 'big')) + if self._aead_id in (AEAD.AES128_GCM, AEAD.AES256_GCM): + cipher = AES.new(self._key, AES.MODE_GCM, nonce=nonce, mac_len=self._Nt) + elif self._aead_id == AEAD.CHACHA20_POLY1305: + cipher = ChaCha20_Poly1305.new(key=self._key, nonce=nonce) + else: + raise ValueError(f"Unknown AEAD cipher ID {self._aead_id:#x}") + if self._sequence >= self._max_sequence: + raise MessageLimitReachedError() + self._sequence += 1 + return cipher + + def seal(self, plaintext: bytes, auth_data: Optional[bytes] = None): + """Encrypt and authenticate a message. + + This method can be invoked multiple times + to seal an ordered sequence of messages. + + Arguments: + plaintext: bytes + The message to seal. + auth_data: bytes + Optional. Additional Authenticated data (AAD) that is not encrypted + but that will be also covered by the authentication tag. + + Returns: + The ciphertext concatenated with the authentication tag. + """ + + if not self._encrypt: + raise ValueError("This cipher can only be used to seal") + cipher = self._new_cipher() + if auth_data: + cipher.update(auth_data) + ct, tag = cipher.encrypt_and_digest(plaintext) + return ct + tag + + def unseal(self, ciphertext: bytes, auth_data: Optional[bytes] = None): + """Decrypt a message and validate its authenticity. + + This method can be invoked multiple times + to unseal an ordered sequence of messages. + + Arguments: + cipertext: bytes + The message to unseal. + auth_data: bytes + Optional. Additional Authenticated data (AAD) that + was also covered by the authentication tag. + + Returns: + The original plaintext. + + Raises: ValueError + If the ciphertext (in combination with the AAD) is not valid. + + But if it is the first time you call ``unseal()`` this + exception may also mean that any of the parameters or keys + used to establish the session is wrong or that one is missing. + """ + + if self._encrypt: + raise ValueError("This cipher can only be used to unseal") + if len(ciphertext) < self._Nt: + raise ValueError("Ciphertext is too small") + cipher = self._new_cipher() + if auth_data: + cipher.update(auth_data) + + try: + pt = cipher.decrypt_and_verify(ciphertext[:-self._Nt], + ciphertext[-self._Nt:]) + except ValueError: + if self._sequence == 1: + raise ValueError("Incorrect HPKE keys/parameters or invalid message (wrong MAC tag)") + raise ValueError("Invalid message (wrong MAC tag)") + return pt + + +def new(*, receiver_key: EccKey, + aead_id: AEAD, + enc: Optional[bytes] = None, + sender_key: Optional[EccKey] = None, + psk: Optional[tuple[bytes, bytes]] = None, + info: Optional[bytes] = None) -> HPKE_Cipher: + """Create an HPKE context which can be used: + + - by the sender to seal (encrypt) a message or + - by the receiver to unseal (decrypt) it. + + As a minimum, the two parties agree on the receiver's asymmetric key + (of which the sender will only know the public half). + + Additionally, for authentication purposes, they may also agree on: + + * the sender's asymmetric key (of which the receiver will only know the public half) + + * a shared secret (e.g., a symmetric key derived from a password) + + Args: + receiver_key: + The ECC key of the receiver. + It must be on one of the following curves: ``NIST P-256``, + ``NIST P-384``, ``NIST P-521``, ``X25519`` or ``X448``. + + If this is a **public** key, the HPKE context can only be used to + **seal** (**encrypt**). + + If this is a **private** key, the HPKE context can only be used to + **unseal** (**decrypt**). + + aead_id: + The HPKE identifier of the symmetric cipher. + The possible values are: + + * ``HPKE.AEAD.AES128_GCM`` + * ``HPKE.AEAD.AES256_GCM`` + * ``HPKE.AEAD.CHACHA20_POLY1305`` + + enc: + The encapsulated session key (i.e., the KEM shared secret). + + The receiver must always specify this parameter. + + The sender must always omit this parameter. + + sender_key: + The ECC key of the sender. + It must be on the same curve as the ``receiver_key``. + If the ``receiver_key`` is a public key, ``sender_key`` must be a + private key, and vice versa. + + psk: + A Pre-Shared Key (PSK) as a 2-tuple of non-empty + byte strings: the identifier and the actual secret value. + Sender and receiver must use the same PSK (or none). + + The secret value must be at least 32 bytes long, + but it must not be a low-entropy password + (use a KDF like PBKDF2 or scrypt to derive a secret + from a password). + + info: + A non-secret parameter that contributes + to the generation of all session keys. + Sender and receive must use the same **info** parameter (or none). + + Returns: + An object that can be used for + sealing (if ``receiver_key`` is a public key) or + unsealing (if ``receiver_key`` is a private key). + In the latter case, + correctness of all the keys and parameters will only + be assessed with the first call to ``unseal()``. + """ + + if aead_id not in AEAD: + raise ValueError(f"Unknown AEAD cipher ID {aead_id:#x}") + + curve = receiver_key.curve + if curve not in ('NIST P-256', 'NIST P-384', 'NIST P-521', + 'Curve25519', 'Curve448'): + raise ValueError(f"Unsupported curve {curve}") + + if sender_key: + count_private_keys = int(receiver_key.has_private()) + \ + int(sender_key.has_private()) + if count_private_keys != 1: + raise ValueError("Exactly 1 private key required") + if sender_key.curve != curve: + raise ValueError("Sender key uses {} but recipient key {}". + format(sender_key.curve, curve)) + mode = MODE.AUTH if psk is None else MODE.AUTH_PSK + else: + mode = MODE.BASE if psk is None else MODE.PSK + + if psk is None: + psk = b'', b'' + + if info is None: + info = b'' + + return HPKE_Cipher(receiver_key, + enc, + sender_key, + psk, + info, + aead_id, + mode) diff --git a/venv/Lib/site-packages/Cryptodome/Protocol/KDF.py b/venv/Lib/site-packages/Cryptodome/Protocol/KDF.py new file mode 100644 index 0000000..5f8170a --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Protocol/KDF.py @@ -0,0 +1,647 @@ +# coding=utf-8 +# +# KDF.py : a collection of Key Derivation Functions +# +# Part of the Python Cryptography Toolkit +# +# =================================================================== +# The contents of this file are dedicated to the public domain. To +# the extent that dedication to the public domain is not available, +# everyone is granted a worldwide, perpetual, royalty-free, +# non-exclusive license to exercise all rights associated with the +# contents of this file for any purpose whatsoever. +# No rights are reserved. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# =================================================================== + +import re +import struct +from functools import reduce + +from Cryptodome.Util.py3compat import (tobytes, bord, _copy_bytes, iter_range, + tostr, bchr, bstr) + +from Cryptodome.Hash import SHA1, SHA256, HMAC, CMAC, BLAKE2s +from Cryptodome.Util.strxor import strxor +from Cryptodome.Random import get_random_bytes +from Cryptodome.Util.number import size as bit_size, long_to_bytes, bytes_to_long + +from Cryptodome.Util._raw_api import (load_pycryptodome_raw_lib, + create_string_buffer, + get_raw_buffer, c_size_t) + +_raw_salsa20_lib = load_pycryptodome_raw_lib( + "Cryptodome.Cipher._Salsa20", + """ + int Salsa20_8_core(const uint8_t *x, const uint8_t *y, + uint8_t *out); + """) + +_raw_scrypt_lib = load_pycryptodome_raw_lib( + "Cryptodome.Protocol._scrypt", + """ + typedef int (core_t)(const uint8_t [64], const uint8_t [64], uint8_t [64]); + int scryptROMix(const uint8_t *data_in, uint8_t *data_out, + size_t data_len, unsigned N, core_t *core); + """) + + +def PBKDF1(password, salt, dkLen, count=1000, hashAlgo=None): + """Derive one key from a password (or passphrase). + + This function performs key derivation according to an old version of + the PKCS#5 standard (v1.5) or `RFC2898 + `_. + + Args: + password (string): + The secret password to generate the key from. + salt (byte string): + An 8 byte string to use for better protection from dictionary attacks. + This value does not need to be kept secret, but it should be randomly + chosen for each derivation. + dkLen (integer): + The length of the desired key. The default is 16 bytes, suitable for + instance for :mod:`Cryptodome.Cipher.AES`. + count (integer): + The number of iterations to carry out. The recommendation is 1000 or + more. + hashAlgo (module): + The hash algorithm to use, as a module or an object from the :mod:`Cryptodome.Hash` package. + The digest length must be no shorter than ``dkLen``. + The default algorithm is :mod:`Cryptodome.Hash.SHA1`. + + Return: + A byte string of length ``dkLen`` that can be used as key. + """ + + if not hashAlgo: + hashAlgo = SHA1 + password = tobytes(password) + pHash = hashAlgo.new(password+salt) + digest = pHash.digest_size + if dkLen > digest: + raise TypeError("Selected hash algorithm has a too short digest (%d bytes)." % digest) + if len(salt) != 8: + raise ValueError("Salt is not 8 bytes long (%d bytes instead)." % len(salt)) + for i in iter_range(count-1): + pHash = pHash.new(pHash.digest()) + return pHash.digest()[:dkLen] + + +def PBKDF2(password, salt, dkLen=16, count=1000, prf=None, hmac_hash_module=None): + """Derive one or more keys from a password (or passphrase). + + This function performs key derivation according to the PKCS#5 standard (v2.0). + + Args: + password (string or byte string): + The secret password to generate the key from. + + Strings will be encoded as ISO 8859-1 (also known as Latin-1), + which does not allow any characters with codepoints > 255. + salt (string or byte string): + A (byte) string to use for better protection from dictionary attacks. + This value does not need to be kept secret, but it should be randomly + chosen for each derivation. It is recommended to use at least 16 bytes. + + Strings will be encoded as ISO 8859-1 (also known as Latin-1), + which does not allow any characters with codepoints > 255. + dkLen (integer): + The cumulative length of the keys to produce. + + Due to a flaw in the PBKDF2 design, you should not request more bytes + than the ``prf`` can output. For instance, ``dkLen`` should not exceed + 20 bytes in combination with ``HMAC-SHA1``. + count (integer): + The number of iterations to carry out. The higher the value, the slower + and the more secure the function becomes. + + You should find the maximum number of iterations that keeps the + key derivation still acceptable on the slowest hardware you must support. + + Although the default value is 1000, **it is recommended to use at least + 1000000 (1 million) iterations**. + prf (callable): + A pseudorandom function. It must be a function that returns a + pseudorandom byte string from two parameters: a secret and a salt. + The slower the algorithm, the more secure the derivation function. + If not specified, **HMAC-SHA1** is used. + hmac_hash_module (module): + A module from ``Cryptodome.Hash`` implementing a Merkle-Damgard cryptographic + hash, which PBKDF2 must use in combination with HMAC. + This parameter is mutually exclusive with ``prf``. + + Return: + A byte string of length ``dkLen`` that can be used as key material. + If you want multiple keys, just break up this string into segments of the desired length. + """ + + password = tobytes(password) + salt = tobytes(salt) + + if prf and hmac_hash_module: + raise ValueError("'prf' and 'hmac_hash_module' are mutually exlusive") + + if prf is None and hmac_hash_module is None: + hmac_hash_module = SHA1 + + if prf or not hasattr(hmac_hash_module, "_pbkdf2_hmac_assist"): + # Generic (and slow) implementation + + if prf is None: + prf = lambda p, s: HMAC.new(p, s, hmac_hash_module).digest() + + def link(s): + s[0], s[1] = s[1], prf(password, s[1]) + return s[0] + + key = b'' + i = 1 + while len(key) < dkLen: + s = [prf(password, salt + struct.pack(">I", i))] * 2 + key += reduce(strxor, (link(s) for j in range(count))) + i += 1 + + else: + # Optimized implementation + key = b'' + i = 1 + while len(key) < dkLen: + base = HMAC.new(password, b"", hmac_hash_module) + first_digest = base.copy().update(salt + struct.pack(">I", i)).digest() + key += base._pbkdf2_hmac_assist(first_digest, count) + i += 1 + + return key[:dkLen] + + +class _S2V(object): + """String-to-vector PRF as defined in `RFC5297`_. + + This class implements a pseudorandom function family + based on CMAC that takes as input a vector of strings. + + .. _RFC5297: http://tools.ietf.org/html/rfc5297 + """ + + def __init__(self, key, ciphermod, cipher_params=None): + """Initialize the S2V PRF. + + :Parameters: + key : byte string + A secret that can be used as key for CMACs + based on ciphers from ``ciphermod``. + ciphermod : module + A block cipher module from `Cryptodome.Cipher`. + cipher_params : dictionary + A set of extra parameters to use to create a cipher instance. + """ + + self._key = _copy_bytes(None, None, key) + self._ciphermod = ciphermod + self._last_string = self._cache = b'\x00' * ciphermod.block_size + + # Max number of update() call we can process + self._n_updates = ciphermod.block_size * 8 - 1 + + if cipher_params is None: + self._cipher_params = {} + else: + self._cipher_params = dict(cipher_params) + + @staticmethod + def new(key, ciphermod): + """Create a new S2V PRF. + + :Parameters: + key : byte string + A secret that can be used as key for CMACs + based on ciphers from ``ciphermod``. + ciphermod : module + A block cipher module from `Cryptodome.Cipher`. + """ + return _S2V(key, ciphermod) + + def _double(self, bs): + doubled = bytes_to_long(bs) << 1 + if bord(bs[0]) & 0x80: + doubled ^= 0x87 + return long_to_bytes(doubled, len(bs))[-len(bs):] + + def update(self, item): + """Pass the next component of the vector. + + The maximum number of components you can pass is equal to the block + length of the cipher (in bits) minus 1. + + :Parameters: + item : byte string + The next component of the vector. + :Raise TypeError: when the limit on the number of components has been reached. + """ + + if self._n_updates == 0: + raise TypeError("Too many components passed to S2V") + self._n_updates -= 1 + + mac = CMAC.new(self._key, + msg=self._last_string, + ciphermod=self._ciphermod, + cipher_params=self._cipher_params) + self._cache = strxor(self._double(self._cache), mac.digest()) + self._last_string = _copy_bytes(None, None, item) + + def derive(self): + """"Derive a secret from the vector of components. + + :Return: a byte string, as long as the block length of the cipher. + """ + + if len(self._last_string) >= 16: + # xorend + final = self._last_string[:-16] + strxor(self._last_string[-16:], self._cache) + else: + # zero-pad & xor + padded = (self._last_string + b'\x80' + b'\x00' * 15)[:16] + final = strxor(padded, self._double(self._cache)) + mac = CMAC.new(self._key, + msg=final, + ciphermod=self._ciphermod, + cipher_params=self._cipher_params) + return mac.digest() + + +def _HKDF_extract(salt, ikm, hashmod): + prk = HMAC.new(salt, ikm, digestmod=hashmod).digest() + return prk + + +def _HKDF_expand(prk, info, L, hashmod): + t = [b""] + n = 1 + tlen = 0 + while tlen < L: + hmac = HMAC.new(prk, t[-1] + info + struct.pack('B', n), digestmod=hashmod) + t.append(hmac.digest()) + tlen += hashmod.digest_size + n += 1 + okm = b"".join(t) + return okm[:L] + + +def HKDF(master, key_len, salt, hashmod, num_keys=1, context=None): + """Derive one or more keys from a master secret using + the HMAC-based KDF defined in RFC5869_. + + Args: + master (byte string): + The unguessable value used by the KDF to generate the other keys. + It must be a high-entropy secret, though not necessarily uniform. + It must not be a password. + key_len (integer): + The length in bytes of every derived key. + salt (byte string): + A non-secret, reusable value that strengthens the randomness + extraction step. + Ideally, it is as long as the digest size of the chosen hash. + If empty, a string of zeroes in used. + hashmod (module): + A cryptographic hash algorithm from :mod:`Cryptodome.Hash`. + :mod:`Cryptodome.Hash.SHA512` is a good choice. + num_keys (integer): + The number of keys to derive. Every key is :data:`key_len` bytes long. + The maximum cumulative length of all keys is + 255 times the digest size. + context (byte string): + Optional identifier describing what the keys are used for. + + Return: + A byte string or a tuple of byte strings. + + .. _RFC5869: http://tools.ietf.org/html/rfc5869 + """ + + output_len = key_len * num_keys + if output_len > (255 * hashmod.digest_size): + raise ValueError("Too much secret data to derive") + if not salt: + salt = b'\x00' * hashmod.digest_size + if context is None: + context = b"" + + prk = _HKDF_extract(salt, master, hashmod) + okm = _HKDF_expand(prk, context, output_len, hashmod) + + if num_keys == 1: + return okm[:key_len] + kol = [okm[idx:idx + key_len] + for idx in iter_range(0, output_len, key_len)] + return list(kol[:num_keys]) + + +def scrypt(password, salt, key_len, N, r, p, num_keys=1): + """Derive one or more keys from a passphrase. + + Args: + password (string): + The secret pass phrase to generate the keys from. + salt (string): + A string to use for better protection from dictionary attacks. + This value does not need to be kept secret, + but it should be randomly chosen for each derivation. + It is recommended to be at least 16 bytes long. + key_len (integer): + The length in bytes of each derived key. + N (integer): + CPU/Memory cost parameter. It must be a power of 2 and less + than :math:`2^{32}`. + r (integer): + Block size parameter. + p (integer): + Parallelization parameter. + It must be no greater than :math:`(2^{32}-1)/(4r)`. + num_keys (integer): + The number of keys to derive. Every key is :data:`key_len` bytes long. + By default, only 1 key is generated. + The maximum cumulative length of all keys is :math:`(2^{32}-1)*32` + (that is, 128TB). + + A good choice of parameters *(N, r , p)* was suggested + by Colin Percival in his `presentation in 2009`__: + + - *( 2¹⁴, 8, 1 )* for interactive logins (≤100ms) + - *( 2²⁰, 8, 1 )* for file encryption (≤5s) + + Return: + A byte string or a tuple of byte strings. + + .. __: http://www.tarsnap.com/scrypt/scrypt-slides.pdf + """ + + if 2 ** (bit_size(N) - 1) != N: + raise ValueError("N must be a power of 2") + if N >= 2 ** 32: + raise ValueError("N is too big") + if p > ((2 ** 32 - 1) * 32) // (128 * r): + raise ValueError("p or r are too big") + + prf_hmac_sha256 = lambda p, s: HMAC.new(p, s, SHA256).digest() + + stage_1 = PBKDF2(password, salt, p * 128 * r, 1, prf=prf_hmac_sha256) + + scryptROMix = _raw_scrypt_lib.scryptROMix + core = _raw_salsa20_lib.Salsa20_8_core + + # Parallelize into p flows + data_out = [] + for flow in iter_range(p): + idx = flow * 128 * r + buffer_out = create_string_buffer(128 * r) + result = scryptROMix(stage_1[idx: idx + 128 * r], + buffer_out, + c_size_t(128 * r), + N, + core) + if result: + raise ValueError("Error %X while running scrypt" % result) + data_out += [get_raw_buffer(buffer_out)] + + dk = PBKDF2(password, + b"".join(data_out), + key_len * num_keys, 1, + prf=prf_hmac_sha256) + + if num_keys == 1: + return dk + + kol = [dk[idx:idx + key_len] + for idx in iter_range(0, key_len * num_keys, key_len)] + return kol + + +def _bcrypt_encode(data): + s = "./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" + + bits = [] + for c in data: + bits_c = bin(bord(c))[2:].zfill(8) + bits.append(bstr(bits_c)) + bits = b"".join(bits) + + bits6 = [bits[idx:idx+6] for idx in range(0, len(bits), 6)] + + result = [] + for g in bits6[:-1]: + idx = int(g, 2) + result.append(s[idx]) + + g = bits6[-1] + idx = int(g, 2) << (6 - len(g)) + result.append(s[idx]) + result = "".join(result) + + return tobytes(result) + + +def _bcrypt_decode(data): + s = "./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" + + bits = [] + for c in tostr(data): + idx = s.find(c) + bits6 = bin(idx)[2:].zfill(6) + bits.append(bits6) + bits = "".join(bits) + + modulo4 = len(data) % 4 + if modulo4 == 1: + raise ValueError("Incorrect length") + elif modulo4 == 2: + bits = bits[:-4] + elif modulo4 == 3: + bits = bits[:-2] + + bits8 = [bits[idx:idx+8] for idx in range(0, len(bits), 8)] + + result = [] + for g in bits8: + result.append(bchr(int(g, 2))) + result = b"".join(result) + + return result + + +def _bcrypt_hash(password, cost, salt, constant, invert): + from Cryptodome.Cipher import _EKSBlowfish + + if len(password) > 72: + raise ValueError("The password is too long. It must be 72 bytes at most.") + + if not (4 <= cost <= 31): + raise ValueError("bcrypt cost factor must be in the range 4..31") + + cipher = _EKSBlowfish.new(password, _EKSBlowfish.MODE_ECB, salt, cost, invert) + ctext = constant + for _ in range(64): + ctext = cipher.encrypt(ctext) + return ctext + + +def bcrypt(password, cost, salt=None): + """Hash a password into a key, using the OpenBSD bcrypt protocol. + + Args: + password (byte string or string): + The secret password or pass phrase. + It must be at most 72 bytes long. + It must not contain the zero byte. + Unicode strings will be encoded as UTF-8. + cost (integer): + The exponential factor that makes it slower to compute the hash. + It must be in the range 4 to 31. + A value of at least 12 is recommended. + salt (byte string): + Optional. Random byte string to thwarts dictionary and rainbow table + attacks. It must be 16 bytes long. + If not passed, a random value is generated. + + Return (byte string): + The bcrypt hash + + Raises: + ValueError: if password is longer than 72 bytes or if it contains the zero byte + + """ + + password = tobytes(password, "utf-8") + + if password.find(bchr(0)[0]) != -1: + raise ValueError("The password contains the zero byte") + + if len(password) < 72: + password += b"\x00" + + if salt is None: + salt = get_random_bytes(16) + if len(salt) != 16: + raise ValueError("bcrypt salt must be 16 bytes long") + + ctext = _bcrypt_hash(password, cost, salt, b"OrpheanBeholderScryDoubt", True) + + cost_enc = b"$" + bstr(str(cost).zfill(2)) + salt_enc = b"$" + _bcrypt_encode(salt) + hash_enc = _bcrypt_encode(ctext[:-1]) # only use 23 bytes, not 24 + return b"$2a" + cost_enc + salt_enc + hash_enc + + +def bcrypt_check(password, bcrypt_hash): + """Verify if the provided password matches the given bcrypt hash. + + Args: + password (byte string or string): + The secret password or pass phrase to test. + It must be at most 72 bytes long. + It must not contain the zero byte. + Unicode strings will be encoded as UTF-8. + bcrypt_hash (byte string, bytearray): + The reference bcrypt hash the password needs to be checked against. + + Raises: + ValueError: if the password does not match + """ + + bcrypt_hash = tobytes(bcrypt_hash) + + if len(bcrypt_hash) != 60: + raise ValueError("Incorrect length of the bcrypt hash: %d bytes instead of 60" % len(bcrypt_hash)) + + if bcrypt_hash[:4] != b'$2a$': + raise ValueError("Unsupported prefix") + + p = re.compile(br'\$2a\$([0-9][0-9])\$([A-Za-z0-9./]{22,22})([A-Za-z0-9./]{31,31})') + r = p.match(bcrypt_hash) + if not r: + raise ValueError("Incorrect bcrypt hash format") + + cost = int(r.group(1)) + if not (4 <= cost <= 31): + raise ValueError("Incorrect cost") + + salt = _bcrypt_decode(r.group(2)) + + bcrypt_hash2 = bcrypt(password, cost, salt) + + secret = get_random_bytes(16) + + mac1 = BLAKE2s.new(digest_bits=160, key=secret, data=bcrypt_hash).digest() + mac2 = BLAKE2s.new(digest_bits=160, key=secret, data=bcrypt_hash2).digest() + if mac1 != mac2: + raise ValueError("Incorrect bcrypt hash") + + +def SP800_108_Counter(master, key_len, prf, num_keys=None, label=b'', context=b''): + """Derive one or more keys from a master secret using + a pseudorandom function in Counter Mode, as specified in + `NIST SP 800-108r1 `_. + + Args: + master (byte string): + The secret value used by the KDF to derive the other keys. + It must not be a password. + The length on the secret must be consistent with the input expected by + the :data:`prf` function. + key_len (integer): + The length in bytes of each derived key. + prf (function): + A pseudorandom function that takes two byte strings as parameters: + the secret and an input. It returns another byte string. + num_keys (integer): + The number of keys to derive. Every key is :data:`key_len` bytes long. + By default, only 1 key is derived. + label (byte string): + Optional description of the purpose of the derived keys. + It must not contain zero bytes. + context (byte string): + Optional information pertaining to + the protocol that uses the keys, such as the identity of the + participants, nonces, session IDs, etc. + It must not contain zero bytes. + + Return: + - a byte string (if ``num_keys`` is not specified), or + - a tuple of byte strings (if ``num_key`` is specified). + """ + + if num_keys is None: + num_keys = 1 + + if context.find(b'\x00') != -1: + raise ValueError("Null byte found in context") + + key_len_enc = long_to_bytes(key_len * num_keys * 8, 4) + output_len = key_len * num_keys + + i = 1 + dk = b"" + while len(dk) < output_len: + info = long_to_bytes(i, 4) + label + b'\x00' + context + key_len_enc + dk += prf(master, info) + i += 1 + if i > 0xFFFFFFFF: + raise ValueError("Overflow in SP800 108 counter") + + if num_keys == 1: + return dk[:key_len] + else: + kol = [dk[idx:idx + key_len] + for idx in iter_range(0, output_len, key_len)] + return kol diff --git a/venv/Lib/site-packages/Cryptodome/Protocol/KDF.pyi b/venv/Lib/site-packages/Cryptodome/Protocol/KDF.pyi new file mode 100644 index 0000000..80691e0 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Protocol/KDF.pyi @@ -0,0 +1,44 @@ +from types import ModuleType +from typing import Optional, Callable, Tuple, Union, Dict, Any, overload +from typing_extensions import Literal + +Buffer=bytes|bytearray|memoryview + +RNG = Callable[[int], bytes] +PRF = Callable[[bytes, bytes], bytes] + +def PBKDF1(password: str, salt: bytes, dkLen: int, count: Optional[int]=1000, hashAlgo: Optional[ModuleType]=None) -> bytes: ... +def PBKDF2(password: str, salt: bytes, dkLen: Optional[int]=16, count: Optional[int]=1000, prf: Optional[RNG]=None, hmac_hash_module: Optional[ModuleType]=None) -> bytes: ... + +class _S2V(object): + def __init__(self, key: bytes, ciphermod: ModuleType, cipher_params: Optional[Dict[Any, Any]]=None) -> None: ... + + @staticmethod + def new(key: bytes, ciphermod: ModuleType) -> None: ... + def update(self, item: bytes) -> None: ... + def derive(self) -> bytes: ... + +def _HKDF_extract(salt: Buffer, ikm: Buffer, hashmod: ModuleType) -> bytes: ... +def _HKDF_expand(prk: Buffer, info: Buffer, L: int, hashmod) -> bytes : ... +def HKDF(master: bytes, key_len: int, salt: bytes, hashmod: ModuleType, num_keys: Optional[int]=1, context: Optional[bytes]=None) -> Union[bytes, Tuple[bytes, ...]]: ... + +def scrypt(password: str, salt: str, key_len: int, N: int, r: int, p: int, num_keys: Optional[int]=1) -> Union[bytes, Tuple[bytes, ...]]: ... + +def _bcrypt_decode(data: bytes) -> bytes: ... +def _bcrypt_hash(password:bytes , cost: int, salt: bytes, constant:bytes, invert:bool) -> bytes: ... +def bcrypt(password: Union[bytes, str], cost: int, salt: Optional[bytes]=None) -> bytes: ... +def bcrypt_check(password: Union[bytes, str], bcrypt_hash: Union[bytes, bytearray, str]) -> None: ... + +@overload +def SP800_108_Counter(master: Buffer, + key_len: int, + prf: PRF, + num_keys: Literal[None] = None, + label: Buffer = b'', context: Buffer = b'') -> bytes: ... + +@overload +def SP800_108_Counter(master: Buffer, + key_len: int, + prf: PRF, + num_keys: int, + label: Buffer = b'', context: Buffer = b'') -> Tuple[bytes]: ... diff --git a/venv/Lib/site-packages/Cryptodome/Protocol/SecretSharing.py b/venv/Lib/site-packages/Cryptodome/Protocol/SecretSharing.py new file mode 100644 index 0000000..1034909 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Protocol/SecretSharing.py @@ -0,0 +1,297 @@ +# +# SecretSharing.py : distribute a secret amongst a group of participants +# +# =================================================================== +# +# Copyright (c) 2014, Legrandin +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# =================================================================== + +from Cryptodome.Util.py3compat import is_native_int +from Cryptodome.Util import number +from Cryptodome.Util.number import long_to_bytes, bytes_to_long +from Cryptodome.Random import get_random_bytes as rng + + +def _mult_gf2(f1, f2): + """Multiply two polynomials in GF(2)""" + + # Ensure f2 is the smallest + if f2 > f1: + f1, f2 = f2, f1 + z = 0 + while f2: + if f2 & 1: + z ^= f1 + f1 <<= 1 + f2 >>= 1 + return z + + +def _div_gf2(a, b): + """ + Compute division of polynomials over GF(2). + Given a and b, it finds two polynomials q and r such that: + + a = b*q + r with deg(r)= d: + s = 1 << (deg(r) - d) + q ^= s + r ^= _mult_gf2(b, s) + return (q, r) + + +class _Element(object): + """Element of GF(2^128) field""" + + # The irreducible polynomial defining + # this field is 1 + x + x^2 + x^7 + x^128 + irr_poly = 1 + 2 + 4 + 128 + 2 ** 128 + + def __init__(self, encoded_value): + """Initialize the element to a certain value. + + The value passed as parameter is internally encoded as + a 128-bit integer, where each bit represents a polynomial + coefficient. The LSB is the constant coefficient. + """ + + if is_native_int(encoded_value): + self._value = encoded_value + elif len(encoded_value) == 16: + self._value = bytes_to_long(encoded_value) + else: + raise ValueError("The encoded value must be an integer or a 16 byte string") + + def __eq__(self, other): + return self._value == other._value + + def __int__(self): + """Return the field element, encoded as a 128-bit integer.""" + return self._value + + def encode(self): + """Return the field element, encoded as a 16 byte string.""" + return long_to_bytes(self._value, 16) + + def __mul__(self, factor): + + f1 = self._value + f2 = factor._value + + # Make sure that f2 is the smallest, to speed up the loop + if f2 > f1: + f1, f2 = f2, f1 + + if self.irr_poly in (f1, f2): + return _Element(0) + + mask1 = 2 ** 128 + v, z = f1, 0 + while f2: + # if f2 ^ 1: z ^= v + mask2 = int(bin(f2 & 1)[2:] * 128, base=2) + z = (mask2 & (z ^ v)) | ((mask1 - mask2 - 1) & z) + v <<= 1 + # if v & mask1: v ^= self.irr_poly + mask3 = int(bin((v >> 128) & 1)[2:] * 128, base=2) + v = (mask3 & (v ^ self.irr_poly)) | ((mask1 - mask3 - 1) & v) + f2 >>= 1 + return _Element(z) + + def __add__(self, term): + return _Element(self._value ^ term._value) + + def inverse(self): + """Return the inverse of this element in GF(2^128).""" + + # We use the Extended GCD algorithm + # http://en.wikipedia.org/wiki/Polynomial_greatest_common_divisor + + if self._value == 0: + raise ValueError("Inversion of zero") + + r0, r1 = self._value, self.irr_poly + s0, s1 = 1, 0 + while r1 > 0: + q = _div_gf2(r0, r1)[0] + r0, r1 = r1, r0 ^ _mult_gf2(q, r1) + s0, s1 = s1, s0 ^ _mult_gf2(q, s1) + return _Element(s0) + + def __pow__(self, exponent): + result = _Element(self._value) + for _ in range(exponent - 1): + result = result * self + return result + + +class Shamir(object): + """Shamir's secret sharing scheme. + + A secret is split into ``n`` shares, and it is sufficient to collect + ``k`` of them to reconstruct the secret. + """ + + @staticmethod + def split(k, n, secret, ssss=False): + """Split a secret into ``n`` shares. + + The secret can be reconstructed later using just ``k`` shares + out of the original ``n``. + Each share must be kept confidential to the person it was + assigned to. + + Each share is associated to an index (starting from 1). + + Args: + k (integer): + The number of shares needed to reconstruct the secret. + n (integer): + The number of shares to create (at least ``k``). + secret (byte string): + A byte string of 16 bytes (e.g. an AES 128 key). + ssss (bool): + If ``True``, the shares can be used with the ``ssss`` utility + (without using the "diffusion layer"). + Default: ``False``. + + Return (tuples): + ``n`` tuples, one per participant. + A tuple contains two items: + + 1. the unique index (an integer) + 2. the share (16 bytes) + """ + + # + # We create a polynomial with random coefficients in GF(2^128): + # + # p(x) = c_0 + \sum_{i=1}^{k-1} c_i * x^i + # + # c_0 is the secret. + # + + coeffs = [_Element(rng(16)) for i in range(k - 1)] + coeffs.append(_Element(secret)) + + # Each share is y_i = p(x_i) where x_i + # is the index assigned to the share. + + def make_share(user, coeffs, ssss): + idx = _Element(user) + + # Horner's method + share = _Element(0) + for coeff in coeffs: + share = idx * share + coeff + + # The ssss utility actually uses: + # + # p(x) = c_0 + \sum_{i=1}^{k-1} c_i * x^i + x^k + # + if ssss: + share += _Element(user) ** len(coeffs) + + return share.encode() + + return [(i, make_share(i, coeffs, ssss)) for i in range(1, n + 1)] + + @staticmethod + def combine(shares, ssss=False): + """Recombine a secret, if enough shares are presented. + + Args: + shares (tuples): + The *k* tuples, each containing the index (an integer) and + the share (a byte string, 16 bytes long) that were assigned to + a participant. + + .. note:: + + Pass exactly as many share as they are required, + and no more. + + ssss (bool): + If ``True``, the shares were produced by the ``ssss`` utility + (without using the "diffusion layer"). + Default: ``False``. + + Return: + The original secret, as a byte string (16 bytes long). + """ + + # + # Given k points (x,y), the interpolation polynomial of degree k-1 is: + # + # L(x) = \sum_{j=0}^{k-1} y_i * l_j(x) + # + # where: + # + # l_j(x) = \prod_{ \overset{0 \le m \le k-1}{m \ne j} } + # \frac{x - x_m}{x_j - x_m} + # + # However, in this case we are purely interested in the constant + # coefficient of L(x). + # + + k = len(shares) + + gf_shares = [] + for x in shares: + idx = _Element(x[0]) + value = _Element(x[1]) + if any(y[0] == idx for y in gf_shares): + raise ValueError("Duplicate share") + if ssss: + value += idx ** k + gf_shares.append((idx, value)) + + result = _Element(0) + for j in range(k): + x_j, y_j = gf_shares[j] + + numerator = _Element(1) + denominator = _Element(1) + + for m in range(k): + x_m = gf_shares[m][0] + if m != j: + numerator *= x_m + denominator *= x_j + x_m + result += y_j * numerator * denominator.inverse() + + return result.encode() diff --git a/venv/Lib/site-packages/Cryptodome/Protocol/SecretSharing.pyi b/venv/Lib/site-packages/Cryptodome/Protocol/SecretSharing.pyi new file mode 100644 index 0000000..5952c99 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Protocol/SecretSharing.pyi @@ -0,0 +1,22 @@ +from typing import Union, List, Tuple, Optional + +def _mult_gf2(f1: int, f2: int) -> int : ... +def _div_gf2(a: int, b: int) -> int : ... + +class _Element(object): + irr_poly: int + def __init__(self, encoded_value: Union[int, bytes]) -> None: ... + def __eq__(self, other) -> bool: ... + def __int__(self) -> int: ... + def encode(self) -> bytes: ... + def __mul__(self, factor: int) -> _Element: ... + def __add__(self, term: _Element) -> _Element: ... + def inverse(self) -> _Element: ... + def __pow__(self, exponent) -> _Element: ... + +class Shamir(object): + @staticmethod + def split(k: int, n: int, secret: bytes, ssss: Optional[bool]) -> List[Tuple[int, bytes]]: ... + @staticmethod + def combine(shares: List[Tuple[int, bytes]], ssss: Optional[bool]) -> bytes: ... + diff --git a/venv/Lib/site-packages/Cryptodome/Protocol/__init__.py b/venv/Lib/site-packages/Cryptodome/Protocol/__init__.py new file mode 100644 index 0000000..76e22bf --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Protocol/__init__.py @@ -0,0 +1,31 @@ +# =================================================================== +# +# Copyright (c) 2014, Legrandin +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# =================================================================== + +__all__ = ['KDF', 'SecretSharing', 'DH'] diff --git a/venv/Lib/site-packages/Cryptodome/Protocol/__init__.pyi b/venv/Lib/site-packages/Cryptodome/Protocol/__init__.pyi new file mode 100644 index 0000000..377ed90 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Protocol/__init__.pyi @@ -0,0 +1 @@ +__all__ = ['KDF.pyi', 'SecretSharing.pyi'] diff --git a/venv/Lib/site-packages/Cryptodome/Protocol/__pycache__/DH.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/Protocol/__pycache__/DH.cpython-312.pyc new file mode 100644 index 0000000..66bbf99 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Protocol/__pycache__/DH.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/Protocol/__pycache__/HPKE.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/Protocol/__pycache__/HPKE.cpython-312.pyc new file mode 100644 index 0000000..c12a870 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Protocol/__pycache__/HPKE.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/Protocol/__pycache__/KDF.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/Protocol/__pycache__/KDF.cpython-312.pyc new file mode 100644 index 0000000..c3dddcc Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Protocol/__pycache__/KDF.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/Protocol/__pycache__/SecretSharing.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/Protocol/__pycache__/SecretSharing.cpython-312.pyc new file mode 100644 index 0000000..69eb129 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Protocol/__pycache__/SecretSharing.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/Protocol/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/Protocol/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000..4ed0053 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Protocol/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/Protocol/_scrypt.pyd b/venv/Lib/site-packages/Cryptodome/Protocol/_scrypt.pyd new file mode 100644 index 0000000..0353374 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Protocol/_scrypt.pyd differ diff --git a/venv/Lib/site-packages/Cryptodome/PublicKey/DSA.py b/venv/Lib/site-packages/Cryptodome/PublicKey/DSA.py new file mode 100644 index 0000000..dddd304 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/PublicKey/DSA.py @@ -0,0 +1,682 @@ +# -*- coding: utf-8 -*- +# +# PublicKey/DSA.py : DSA signature primitive +# +# Written in 2008 by Dwayne C. Litzenberger +# +# =================================================================== +# The contents of this file are dedicated to the public domain. To +# the extent that dedication to the public domain is not available, +# everyone is granted a worldwide, perpetual, royalty-free, +# non-exclusive license to exercise all rights associated with the +# contents of this file for any purpose whatsoever. +# No rights are reserved. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# =================================================================== + +__all__ = ['generate', 'construct', 'DsaKey', 'import_key' ] + +import binascii +import struct +import itertools + +from Cryptodome.Util.py3compat import bchr, bord, tobytes, tostr, iter_range + +from Cryptodome import Random +from Cryptodome.IO import PKCS8, PEM +from Cryptodome.Hash import SHA256 +from Cryptodome.Util.asn1 import ( + DerObject, DerSequence, + DerInteger, DerObjectId, + DerBitString, + ) + +from Cryptodome.Math.Numbers import Integer +from Cryptodome.Math.Primality import (test_probable_prime, COMPOSITE, + PROBABLY_PRIME) + +from Cryptodome.PublicKey import (_expand_subject_public_key_info, + _create_subject_public_key_info, + _extract_subject_public_key_info) + +# ; The following ASN.1 types are relevant for DSA +# +# SubjectPublicKeyInfo ::= SEQUENCE { +# algorithm AlgorithmIdentifier, +# subjectPublicKey BIT STRING +# } +# +# id-dsa ID ::= { iso(1) member-body(2) us(840) x9-57(10040) x9cm(4) 1 } +# +# ; See RFC3279 +# Dss-Parms ::= SEQUENCE { +# p INTEGER, +# q INTEGER, +# g INTEGER +# } +# +# DSAPublicKey ::= INTEGER +# +# DSSPrivatKey_OpenSSL ::= SEQUENCE +# version INTEGER, +# p INTEGER, +# q INTEGER, +# g INTEGER, +# y INTEGER, +# x INTEGER +# } +# + +class DsaKey(object): + r"""Class defining an actual DSA key. + Do not instantiate directly. + Use :func:`generate`, :func:`construct` or :func:`import_key` instead. + + :ivar p: DSA modulus + :vartype p: integer + + :ivar q: Order of the subgroup + :vartype q: integer + + :ivar g: Generator + :vartype g: integer + + :ivar y: Public key + :vartype y: integer + + :ivar x: Private key + :vartype x: integer + + :undocumented: exportKey, publickey + """ + + _keydata = ['y', 'g', 'p', 'q', 'x'] + + def __init__(self, key_dict): + input_set = set(key_dict.keys()) + public_set = set(('y' , 'g', 'p', 'q')) + if not public_set.issubset(input_set): + raise ValueError("Some DSA components are missing = %s" % + str(public_set - input_set)) + extra_set = input_set - public_set + if extra_set and extra_set != set(('x',)): + raise ValueError("Unknown DSA components = %s" % + str(extra_set - set(('x',)))) + self._key = dict(key_dict) + + def _sign(self, m, k): + if not self.has_private(): + raise TypeError("DSA public key cannot be used for signing") + if not (1 < k < self.q): + raise ValueError("k is not between 2 and q-1") + + x, q, p, g = [self._key[comp] for comp in ['x', 'q', 'p', 'g']] + + blind_factor = Integer.random_range(min_inclusive=1, + max_exclusive=q) + inv_blind_k = (blind_factor * k).inverse(q) + blind_x = x * blind_factor + + r = pow(g, k, p) % q # r = (g**k mod p) mod q + s = (inv_blind_k * (blind_factor * m + blind_x * r)) % q + return map(int, (r, s)) + + def _verify(self, m, sig): + r, s = sig + y, q, p, g = [self._key[comp] for comp in ['y', 'q', 'p', 'g']] + if not (0 < r < q) or not (0 < s < q): + return False + w = Integer(s).inverse(q) + u1 = (w * m) % q + u2 = (w * r) % q + v = (pow(g, u1, p) * pow(y, u2, p) % p) % q + return v == r + + def has_private(self): + """Whether this is a DSA private key""" + + return 'x' in self._key + + def can_encrypt(self): # legacy + return False + + def can_sign(self): # legacy + return True + + def public_key(self): + """A matching DSA public key. + + Returns: + a new :class:`DsaKey` object + """ + + public_components = dict((k, self._key[k]) for k in ('y', 'g', 'p', 'q')) + return DsaKey(public_components) + + def __eq__(self, other): + if bool(self.has_private()) != bool(other.has_private()): + return False + + result = True + for comp in self._keydata: + result = result and (getattr(self._key, comp, None) == + getattr(other._key, comp, None)) + return result + + def __ne__(self, other): + return not self.__eq__(other) + + def __getstate__(self): + # DSA key is not pickable + from pickle import PicklingError + raise PicklingError + + def domain(self): + """The DSA domain parameters. + + Returns + tuple : (p,q,g) + """ + + return [int(self._key[comp]) for comp in ('p', 'q', 'g')] + + def __repr__(self): + attrs = [] + for k in self._keydata: + if k == 'p': + bits = Integer(self.p).size_in_bits() + attrs.append("p(%d)" % (bits,)) + elif hasattr(self, k): + attrs.append(k) + if self.has_private(): + attrs.append("private") + # PY3K: This is meant to be text, do not change to bytes (data) + return "<%s @0x%x %s>" % (self.__class__.__name__, id(self), ",".join(attrs)) + + def __getattr__(self, item): + try: + return int(self._key[item]) + except KeyError: + raise AttributeError(item) + + def export_key(self, format='PEM', pkcs8=None, passphrase=None, + protection=None, randfunc=None): + """Export this DSA key. + + Args: + format (string): + The encoding for the output: + + - *'PEM'* (default). ASCII as per `RFC1421`_/ `RFC1423`_. + - *'DER'*. Binary ASN.1 encoding. + - *'OpenSSH'*. ASCII one-liner as per `RFC4253`_. + Only suitable for public keys, not for private keys. + + passphrase (string): + *Private keys only*. The pass phrase to protect the output. + + pkcs8 (boolean): + *Private keys only*. If ``True`` (default), the key is encoded + with `PKCS#8`_. If ``False``, it is encoded in the custom + OpenSSL/OpenSSH container. + + protection (string): + *Only in combination with a pass phrase*. + The encryption scheme to use to protect the output. + + If :data:`pkcs8` takes value ``True``, this is the PKCS#8 + algorithm to use for deriving the secret and encrypting + the private DSA key. + For a complete list of algorithms, see :mod:`Cryptodome.IO.PKCS8`. + The default is *PBKDF2WithHMAC-SHA1AndDES-EDE3-CBC*. + + If :data:`pkcs8` is ``False``, the obsolete PEM encryption scheme is + used. It is based on MD5 for key derivation, and Triple DES for + encryption. Parameter :data:`protection` is then ignored. + + The combination ``format='DER'`` and ``pkcs8=False`` is not allowed + if a passphrase is present. + + randfunc (callable): + A function that returns random bytes. + By default it is :func:`Cryptodome.Random.get_random_bytes`. + + Returns: + byte string : the encoded key + + Raises: + ValueError : when the format is unknown or when you try to encrypt a private + key with *DER* format and OpenSSL/OpenSSH. + + .. warning:: + If you don't provide a pass phrase, the private key will be + exported in the clear! + + .. _RFC1421: http://www.ietf.org/rfc/rfc1421.txt + .. _RFC1423: http://www.ietf.org/rfc/rfc1423.txt + .. _RFC4253: http://www.ietf.org/rfc/rfc4253.txt + .. _`PKCS#8`: http://www.ietf.org/rfc/rfc5208.txt + """ + + if passphrase is not None: + passphrase = tobytes(passphrase) + + if randfunc is None: + randfunc = Random.get_random_bytes + + if format == 'OpenSSH': + tup1 = [self._key[x].to_bytes() for x in ('p', 'q', 'g', 'y')] + + def func(x): + if (bord(x[0]) & 0x80): + return bchr(0) + x + else: + return x + + tup2 = [func(x) for x in tup1] + keyparts = [b'ssh-dss'] + tup2 + keystring = b''.join( + [struct.pack(">I", len(kp)) + kp for kp in keyparts] + ) + return b'ssh-dss ' + binascii.b2a_base64(keystring)[:-1] + + # DER format is always used, even in case of PEM, which simply + # encodes it into BASE64. + params = DerSequence([self.p, self.q, self.g]) + if self.has_private(): + if pkcs8 is None: + pkcs8 = True + if pkcs8: + if not protection: + protection = 'PBKDF2WithHMAC-SHA1AndDES-EDE3-CBC' + private_key = DerInteger(self.x).encode() + binary_key = PKCS8.wrap( + private_key, oid, passphrase, + protection, key_params=params, + randfunc=randfunc + ) + if passphrase: + key_type = 'ENCRYPTED PRIVATE' + else: + key_type = 'PRIVATE' + passphrase = None + else: + if format != 'PEM' and passphrase: + raise ValueError("DSA private key cannot be encrypted") + ints = [0, self.p, self.q, self.g, self.y, self.x] + binary_key = DerSequence(ints).encode() + key_type = "DSA PRIVATE" + else: + if pkcs8: + raise ValueError("PKCS#8 is only meaningful for private keys") + + binary_key = _create_subject_public_key_info(oid, + DerInteger(self.y), params) + key_type = "PUBLIC" + + if format == 'DER': + return binary_key + if format == 'PEM': + pem_str = PEM.encode( + binary_key, key_type + " KEY", + passphrase, randfunc + ) + return tobytes(pem_str) + raise ValueError("Unknown key format '%s'. Cannot export the DSA key." % format) + + # Backward-compatibility + exportKey = export_key + publickey = public_key + + # Methods defined in PyCryptodome that we don't support anymore + + def sign(self, M, K): + raise NotImplementedError("Use module Cryptodome.Signature.DSS instead") + + def verify(self, M, signature): + raise NotImplementedError("Use module Cryptodome.Signature.DSS instead") + + def encrypt(self, plaintext, K): + raise NotImplementedError + + def decrypt(self, ciphertext): + raise NotImplementedError + + def blind(self, M, B): + raise NotImplementedError + + def unblind(self, M, B): + raise NotImplementedError + + def size(self): + raise NotImplementedError + + +def _generate_domain(L, randfunc): + """Generate a new set of DSA domain parameters""" + + N = { 1024:160, 2048:224, 3072:256 }.get(L) + if N is None: + raise ValueError("Invalid modulus length (%d)" % L) + + outlen = SHA256.digest_size * 8 + n = (L + outlen - 1) // outlen - 1 # ceil(L/outlen) -1 + b_ = L - 1 - (n * outlen) + + # Generate q (A.1.1.2) + q = Integer(4) + upper_bit = 1 << (N - 1) + while test_probable_prime(q, randfunc) != PROBABLY_PRIME: + seed = randfunc(64) + U = Integer.from_bytes(SHA256.new(seed).digest()) & (upper_bit - 1) + q = U | upper_bit | 1 + + assert(q.size_in_bits() == N) + + # Generate p (A.1.1.2) + offset = 1 + upper_bit = 1 << (L - 1) + while True: + V = [ SHA256.new(seed + Integer(offset + j).to_bytes()).digest() + for j in iter_range(n + 1) ] + V = [ Integer.from_bytes(v) for v in V ] + W = sum([V[i] * (1 << (i * outlen)) for i in iter_range(n)], + (V[n] & ((1 << b_) - 1)) * (1 << (n * outlen))) + + X = Integer(W + upper_bit) # 2^{L-1} < X < 2^{L} + assert(X.size_in_bits() == L) + + c = X % (q * 2) + p = X - (c - 1) # 2q divides (p-1) + if p.size_in_bits() == L and \ + test_probable_prime(p, randfunc) == PROBABLY_PRIME: + break + offset += n + 1 + + # Generate g (A.2.3, index=1) + e = (p - 1) // q + for count in itertools.count(1): + U = seed + b"ggen" + bchr(1) + Integer(count).to_bytes() + W = Integer.from_bytes(SHA256.new(U).digest()) + g = pow(W, e, p) + if g != 1: + break + + return (p, q, g, seed) + + +def generate(bits, randfunc=None, domain=None): + """Generate a new DSA key pair. + + The algorithm follows Appendix A.1/A.2 and B.1 of `FIPS 186-4`_, + respectively for domain generation and key pair generation. + + Args: + bits (integer): + Key length, or size (in bits) of the DSA modulus *p*. + It must be 1024, 2048 or 3072. + + randfunc (callable): + Random number generation function; it accepts a single integer N + and return a string of random data N bytes long. + If not specified, :func:`Cryptodome.Random.get_random_bytes` is used. + + domain (tuple): + The DSA domain parameters *p*, *q* and *g* as a list of 3 + integers. Size of *p* and *q* must comply to `FIPS 186-4`_. + If not specified, the parameters are created anew. + + Returns: + :class:`DsaKey` : a new DSA key object + + Raises: + ValueError : when **bits** is too little, too big, or not a multiple of 64. + + .. _FIPS 186-4: http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf + """ + + if randfunc is None: + randfunc = Random.get_random_bytes + + if domain: + p, q, g = map(Integer, domain) + + ## Perform consistency check on domain parameters + # P and Q must be prime + fmt_error = test_probable_prime(p) == COMPOSITE + fmt_error |= test_probable_prime(q) == COMPOSITE + # Verify Lagrange's theorem for sub-group + fmt_error |= ((p - 1) % q) != 0 + fmt_error |= g <= 1 or g >= p + fmt_error |= pow(g, q, p) != 1 + if fmt_error: + raise ValueError("Invalid DSA domain parameters") + else: + p, q, g, _ = _generate_domain(bits, randfunc) + + L = p.size_in_bits() + N = q.size_in_bits() + + if L != bits: + raise ValueError("Mismatch between size of modulus (%d)" + " and 'bits' parameter (%d)" % (L, bits)) + + if (L, N) not in [(1024, 160), (2048, 224), + (2048, 256), (3072, 256)]: + raise ValueError("Lengths of p and q (%d, %d) are not compatible" + "to FIPS 186-3" % (L, N)) + + if not 1 < g < p: + raise ValueError("Incorrent DSA generator") + + # B.1.1 + c = Integer.random(exact_bits=N + 64, randfunc=randfunc) + x = c % (q - 1) + 1 # 1 <= x <= q-1 + y = pow(g, x, p) + + key_dict = { 'y':y, 'g':g, 'p':p, 'q':q, 'x':x } + return DsaKey(key_dict) + + +def construct(tup, consistency_check=True): + """Construct a DSA key from a tuple of valid DSA components. + + Args: + tup (tuple): + A tuple of long integers, with 4 or 5 items + in the following order: + + 1. Public key (*y*). + 2. Sub-group generator (*g*). + 3. Modulus, finite field order (*p*). + 4. Sub-group order (*q*). + 5. Private key (*x*). Optional. + + consistency_check (boolean): + If ``True``, the library will verify that the provided components + fulfil the main DSA properties. + + Raises: + ValueError: when the key being imported fails the most basic DSA validity checks. + + Returns: + :class:`DsaKey` : a DSA key object + """ + + key_dict = dict(zip(('y', 'g', 'p', 'q', 'x'), map(Integer, tup))) + key = DsaKey(key_dict) + + fmt_error = False + if consistency_check: + # P and Q must be prime + fmt_error = test_probable_prime(key.p) == COMPOSITE + fmt_error |= test_probable_prime(key.q) == COMPOSITE + # Verify Lagrange's theorem for sub-group + fmt_error |= ((key.p - 1) % key.q) != 0 + fmt_error |= key.g <= 1 or key.g >= key.p + fmt_error |= pow(key.g, key.q, key.p) != 1 + # Public key + fmt_error |= key.y <= 0 or key.y >= key.p + if hasattr(key, 'x'): + fmt_error |= key.x <= 0 or key.x >= key.q + fmt_error |= pow(key.g, key.x, key.p) != key.y + + if fmt_error: + raise ValueError("Invalid DSA key components") + + return key + + +# Dss-Parms ::= SEQUENCE { +# p OCTET STRING, +# q OCTET STRING, +# g OCTET STRING +# } +# DSAPublicKey ::= INTEGER -- public key, y + +def _import_openssl_private(encoded, passphrase, params): + if params: + raise ValueError("DSA private key already comes with parameters") + der = DerSequence().decode(encoded, nr_elements=6, only_ints_expected=True) + if der[0] != 0: + raise ValueError("No version found") + tup = [der[comp] for comp in (4, 3, 1, 2, 5)] + return construct(tup) + + +def _import_subjectPublicKeyInfo(encoded, passphrase, params): + + algoid, encoded_key, emb_params = _expand_subject_public_key_info(encoded) + if algoid != oid: + raise ValueError("No DSA subjectPublicKeyInfo") + if params and emb_params: + raise ValueError("Too many DSA parameters") + + y = DerInteger().decode(encoded_key).value + p, q, g = list(DerSequence().decode(params or emb_params)) + tup = (y, g, p, q) + return construct(tup) + + +def _import_x509_cert(encoded, passphrase, params): + + sp_info = _extract_subject_public_key_info(encoded) + return _import_subjectPublicKeyInfo(sp_info, None, params) + + +def _import_pkcs8(encoded, passphrase, params): + if params: + raise ValueError("PKCS#8 already includes parameters") + k = PKCS8.unwrap(encoded, passphrase) + if k[0] != oid: + raise ValueError("No PKCS#8 encoded DSA key") + x = DerInteger().decode(k[1]).value + p, q, g = list(DerSequence().decode(k[2])) + tup = (pow(g, x, p), g, p, q, x) + return construct(tup) + + +def _import_key_der(key_data, passphrase, params): + """Import a DSA key (public or private half), encoded in DER form.""" + + decodings = (_import_openssl_private, + _import_subjectPublicKeyInfo, + _import_x509_cert, + _import_pkcs8) + + for decoding in decodings: + try: + return decoding(key_data, passphrase, params) + except ValueError: + pass + + raise ValueError("DSA key format is not supported") + + +def import_key(extern_key, passphrase=None): + """Import a DSA key. + + Args: + extern_key (string or byte string): + The DSA key to import. + + The following formats are supported for a DSA **public** key: + + - X.509 certificate (binary DER or PEM) + - X.509 ``subjectPublicKeyInfo`` (binary DER or PEM) + - OpenSSH (ASCII one-liner, see `RFC4253`_) + + The following formats are supported for a DSA **private** key: + + - `PKCS#8`_ ``PrivateKeyInfo`` or ``EncryptedPrivateKeyInfo`` + DER SEQUENCE (binary or PEM) + - OpenSSL/OpenSSH custom format (binary or PEM) + + For details about the PEM encoding, see `RFC1421`_/`RFC1423`_. + + passphrase (string): + In case of an encrypted private key, this is the pass phrase + from which the decryption key is derived. + + Encryption may be applied either at the `PKCS#8`_ or at the PEM level. + + Returns: + :class:`DsaKey` : a DSA key object + + Raises: + ValueError : when the given key cannot be parsed (possibly because + the pass phrase is wrong). + + .. _RFC1421: http://www.ietf.org/rfc/rfc1421.txt + .. _RFC1423: http://www.ietf.org/rfc/rfc1423.txt + .. _RFC4253: http://www.ietf.org/rfc/rfc4253.txt + .. _PKCS#8: http://www.ietf.org/rfc/rfc5208.txt + """ + + extern_key = tobytes(extern_key) + if passphrase is not None: + passphrase = tobytes(passphrase) + + if extern_key.startswith(b'-----'): + # This is probably a PEM encoded key + (der, marker, enc_flag) = PEM.decode(tostr(extern_key), passphrase) + if enc_flag: + passphrase = None + return _import_key_der(der, passphrase, None) + + if extern_key.startswith(b'ssh-dss '): + # This is probably a public OpenSSH key + keystring = binascii.a2b_base64(extern_key.split(b' ')[1]) + keyparts = [] + while len(keystring) > 4: + length = struct.unpack(">I", keystring[:4])[0] + keyparts.append(keystring[4:4 + length]) + keystring = keystring[4 + length:] + if keyparts[0] == b"ssh-dss": + tup = [Integer.from_bytes(keyparts[x]) for x in (4, 3, 1, 2)] + return construct(tup) + + if len(extern_key) > 0 and bord(extern_key[0]) == 0x30: + # This is probably a DER encoded key + return _import_key_der(extern_key, passphrase, None) + + raise ValueError("DSA key format is not supported") + + +# Backward compatibility +importKey = import_key + +#: `Object ID`_ for a DSA key. +#: +#: id-dsa ID ::= { iso(1) member-body(2) us(840) x9-57(10040) x9cm(4) 1 } +#: +#: .. _`Object ID`: http://www.alvestrand.no/objectid/1.2.840.10040.4.1.html +oid = "1.2.840.10040.4.1" diff --git a/venv/Lib/site-packages/Cryptodome/PublicKey/DSA.pyi b/venv/Lib/site-packages/Cryptodome/PublicKey/DSA.pyi new file mode 100644 index 0000000..354ac1f --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/PublicKey/DSA.pyi @@ -0,0 +1,31 @@ +from typing import Dict, Tuple, Callable, Union, Optional + +__all__ = ['generate', 'construct', 'DsaKey', 'import_key' ] + +RNG = Callable[[int], bytes] + +class DsaKey(object): + def __init__(self, key_dict: Dict[str, int]) -> None: ... + def has_private(self) -> bool: ... + def can_encrypt(self) -> bool: ... # legacy + def can_sign(self) -> bool: ... # legacy + def public_key(self) -> DsaKey: ... + def __eq__(self, other: object) -> bool: ... + def __ne__(self, other: object) -> bool: ... + def __getstate__(self) -> None: ... + def domain(self) -> Tuple[int, int, int]: ... + def __repr__(self) -> str: ... + def __getattr__(self, item: str) -> int: ... + def export_key(self, format: Optional[str]="PEM", pkcs8: Optional[bool]=None, passphrase: Optional[str]=None, + protection: Optional[str]=None, randfunc: Optional[RNG]=None) -> bytes: ... + # Backward-compatibility + exportKey = export_key + publickey = public_key + +def generate(bits: int, randfunc: Optional[RNG]=None, domain: Optional[Tuple[int, int, int]]=None) -> DsaKey: ... +def construct(tup: Union[Tuple[int, int, int, int], Tuple[int, int, int, int, int]], consistency_check: Optional[bool]=True) -> DsaKey: ... +def import_key(extern_key: Union[str, bytes], passphrase: Optional[str]=None) -> DsaKey: ... +# Backward compatibility +importKey = import_key + +oid: str diff --git a/venv/Lib/site-packages/Cryptodome/PublicKey/ECC.py b/venv/Lib/site-packages/Cryptodome/PublicKey/ECC.py new file mode 100644 index 0000000..bd9c8cb --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/PublicKey/ECC.py @@ -0,0 +1,1342 @@ +# =================================================================== +# +# Copyright (c) 2015, Legrandin +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# =================================================================== + +from __future__ import print_function + +import re +import struct +import binascii + +from Cryptodome.Util.py3compat import bord, tobytes, tostr, bchr, is_string + +from Cryptodome.Math.Numbers import Integer +from Cryptodome.Util.asn1 import (DerObjectId, DerOctetString, DerSequence, + DerBitString) + +from Cryptodome.PublicKey import (_expand_subject_public_key_info, + _create_subject_public_key_info, + _extract_subject_public_key_info) + +from Cryptodome.Hash import SHA512, SHAKE256 + +from Cryptodome.Random import get_random_bytes + +from ._point import EccPoint, EccXPoint, _curves +from ._point import CurveID as _CurveID + + +class UnsupportedEccFeature(ValueError): + pass + + +class EccKey(object): + r"""Class defining an ECC key. + Do not instantiate directly. + Use :func:`generate`, :func:`construct` or :func:`import_key` instead. + + :ivar curve: The **canonical** name of the curve as defined in the `ECC table`_. + :vartype curve: string + + :ivar pointQ: an ECC point representing the public component. + :vartype pointQ: :class:`EccPoint` or :class:`EccXPoint` + + :ivar d: A scalar that represents the private component + in NIST P curves. It is smaller than the + order of the generator point. + :vartype d: integer + + :ivar seed: A seed that represents the private component + in Ed22519 (32 bytes), Curve25519 (32 bytes), + Curve448 (56 bytes), Ed448 (57 bytes). + :vartype seed: bytes + """ + + def __init__(self, **kwargs): + """Create a new ECC key + + Keywords: + curve : string + The name of the curve. + d : integer + Mandatory for a private key one NIST P curves. + It must be in the range ``[1..order-1]``. + seed : bytes + Mandatory for a private key on Ed25519 (32 bytes), + Curve25519 (32 bytes), Curve448 (56 bytes) or Ed448 (57 bytes). + point : EccPoint or EccXPoint + Mandatory for a public key. If provided for a private key, + the implementation will NOT check whether it matches ``d``. + + Only one parameter among ``d``, ``seed`` or ``point`` may be used. + """ + + kwargs_ = dict(kwargs) + curve_name = kwargs_.pop("curve", None) + self._d = kwargs_.pop("d", None) + self._seed = kwargs_.pop("seed", None) + self._point = kwargs_.pop("point", None) + if curve_name is None and self._point: + curve_name = self._point.curve + if kwargs_: + raise TypeError("Unknown parameters: " + str(kwargs_)) + + if curve_name not in _curves: + raise ValueError("Unsupported curve (%s)" % curve_name) + self._curve = _curves[curve_name] + self.curve = self._curve.canonical + + count = int(self._d is not None) + int(self._seed is not None) + + if count == 0: + if self._point is None: + raise ValueError("At lest one between parameters 'point', 'd' or 'seed' must be specified") + return + + if count == 2: + raise ValueError("Parameters d and seed are mutually exclusive") + + # NIST P curves work with d, EdDSA works with seed + + # RFC 8032, 5.1.5 + if self._curve.id == _CurveID.ED25519: + if self._d is not None: + raise ValueError("Parameter d can only be used with NIST P curves") + if len(self._seed) != 32: + raise ValueError("Parameter seed must be 32 bytes long for Ed25519") + seed_hash = SHA512.new(self._seed).digest() # h + self._prefix = seed_hash[32:] + tmp = bytearray(seed_hash[:32]) + tmp[0] &= 0xF8 + tmp[31] = (tmp[31] & 0x7F) | 0x40 + self._d = Integer.from_bytes(tmp, byteorder='little') + # RFC 8032, 5.2.5 + elif self._curve.id == _CurveID.ED448: + if self._d is not None: + raise ValueError("Parameter d can only be used with NIST P curves") + if len(self._seed) != 57: + raise ValueError("Parameter seed must be 57 bytes long for Ed448") + seed_hash = SHAKE256.new(self._seed).read(114) # h + self._prefix = seed_hash[57:] + tmp = bytearray(seed_hash[:57]) + tmp[0] &= 0xFC + tmp[55] |= 0x80 + tmp[56] = 0 + self._d = Integer.from_bytes(tmp, byteorder='little') + # RFC 7748, 5 + elif self._curve.id == _CurveID.CURVE25519: + if self._d is not None: + raise ValueError("Parameter d can only be used with NIST P curves") + if len(self._seed) != 32: + raise ValueError("Parameter seed must be 32 bytes long for Curve25519") + tmp = bytearray(self._seed) + tmp[0] &= 0xF8 + tmp[31] = (tmp[31] & 0x7F) | 0x40 + self._d = Integer.from_bytes(tmp, byteorder='little') + elif self._curve.id == _CurveID.CURVE448: + if self._d is not None: + raise ValueError("Parameter d can only be used with NIST P curves") + if len(self._seed) != 56: + raise ValueError("Parameter seed must be 56 bytes long for Curve448") + tmp = bytearray(self._seed) + tmp[0] &= 0xFC + tmp[55] |= 0x80 + self._d = Integer.from_bytes(tmp, byteorder='little') + + else: + if self._seed is not None: + raise ValueError("Parameter 'seed' cannot be used with NIST P-curves") + self._d = Integer(self._d) + if not 1 <= self._d < self._curve.order: + raise ValueError("Parameter d must be an integer smaller than the curve order") + + def __eq__(self, other): + if not isinstance(other, EccKey): + return False + + if other.has_private() != self.has_private(): + return False + + return other.pointQ == self.pointQ + + def __repr__(self): + if self.has_private(): + if self._curve.is_edwards: + extra = ", seed=%s" % tostr(binascii.hexlify(self._seed)) + else: + extra = ", d=%d" % int(self._d) + else: + extra = "" + if self._curve.id in (_CurveID.CURVE25519, + _CurveID.CURVE448): + x = self.pointQ.x + result = "EccKey(curve='%s', point_x=%d%s)" % (self._curve.canonical, x, extra) + else: + x, y = self.pointQ.xy + result = "EccKey(curve='%s', point_x=%d, point_y=%d%s)" % (self._curve.canonical, x, y, extra) + return result + + def has_private(self): + """``True`` if this key can be used for making signatures or decrypting data.""" + + return self._d is not None + + # ECDSA + def _sign(self, z, k): + assert 0 < k < self._curve.order + + order = self._curve.order + blind = Integer.random_range(min_inclusive=1, + max_exclusive=order) + + blind_d = self._d * blind + inv_blind_k = (blind * k).inverse(order) + + r = (self._curve.G * k).x % order + s = inv_blind_k * (blind * z + blind_d * r) % order + return (r, s) + + # ECDSA + def _verify(self, z, rs): + order = self._curve.order + sinv = rs[1].inverse(order) + point1 = self._curve.G * ((sinv * z) % order) + point2 = self.pointQ * ((sinv * rs[0]) % order) + return (point1 + point2).x == rs[0] + + @property + def d(self): + if not self.has_private(): + raise ValueError("This is not a private ECC key") + return self._d + + @property + def seed(self): + if not self.has_private(): + raise ValueError("This is not a private ECC key") + return self._seed + + @property + def pointQ(self): + if self._point is None: + self._point = self._curve.G * self._d + return self._point + + def public_key(self): + """A matching ECC public key. + + Returns: + a new :class:`EccKey` object + """ + + return EccKey(curve=self._curve.canonical, point=self.pointQ) + + def _export_SEC1(self, compress): + if not self._curve.is_weierstrass: + raise ValueError("SEC1 format is only supported for NIST P curves") + + # See 2.2 in RFC5480 and 2.3.3 in SEC1 + # + # The first byte is: + # - 0x02: compressed, only X-coordinate, Y-coordinate is even + # - 0x03: compressed, only X-coordinate, Y-coordinate is odd + # - 0x04: uncompressed, X-coordinate is followed by Y-coordinate + # + # PAI is in theory encoded as 0x00. + + modulus_bytes = self.pointQ.size_in_bytes() + + if compress: + if self.pointQ.y.is_odd(): + first_byte = b'\x03' + else: + first_byte = b'\x02' + public_key = (first_byte + + self.pointQ.x.to_bytes(modulus_bytes)) + else: + public_key = (b'\x04' + + self.pointQ.x.to_bytes(modulus_bytes) + + self.pointQ.y.to_bytes(modulus_bytes)) + return public_key + + def _export_eddsa_public(self): + x, y = self.pointQ.xy + if self._curve.id == _CurveID.ED25519: + result = bytearray(y.to_bytes(32, byteorder='little')) + result[31] = ((x & 1) << 7) | result[31] + elif self._curve.id == _CurveID.ED448: + result = bytearray(y.to_bytes(57, byteorder='little')) + result[56] = (x & 1) << 7 + else: + raise ValueError("Not an EdDSA key to export") + return bytes(result) + + def _export_montgomery_public(self): + if not self._curve.is_montgomery: + raise ValueError("Not a Montgomery key to export") + x = self.pointQ.x + field_size = self.pointQ.size_in_bytes() + result = bytearray(x.to_bytes(field_size, byteorder='little')) + return bytes(result) + + def _export_subjectPublicKeyInfo(self, compress): + if self._curve.is_edwards: + oid = self._curve.oid + public_key = self._export_eddsa_public() + params = None + elif self._curve.is_montgomery: + oid = self._curve.oid + public_key = self._export_montgomery_public() + params = None + else: + oid = "1.2.840.10045.2.1" # unrestricted + public_key = self._export_SEC1(compress) + params = DerObjectId(self._curve.oid) + + return _create_subject_public_key_info(oid, + public_key, + params) + + def _export_rfc5915_private_der(self, include_ec_params=True): + + assert self.has_private() + + # ECPrivateKey ::= SEQUENCE { + # version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1), + # privateKey OCTET STRING, + # parameters [0] ECParameters {{ NamedCurve }} OPTIONAL, + # publicKey [1] BIT STRING OPTIONAL + # } + + # Public key - uncompressed form + modulus_bytes = self.pointQ.size_in_bytes() + public_key = (b'\x04' + + self.pointQ.x.to_bytes(modulus_bytes) + + self.pointQ.y.to_bytes(modulus_bytes)) + + seq = [1, + DerOctetString(self.d.to_bytes(modulus_bytes)), + DerObjectId(self._curve.oid, explicit=0), + DerBitString(public_key, explicit=1)] + + if not include_ec_params: + del seq[2] + + return DerSequence(seq).encode() + + def _export_pkcs8(self, **kwargs): + from Cryptodome.IO import PKCS8 + + if kwargs.get('passphrase', None) is not None and 'protection' not in kwargs: + raise ValueError("At least the 'protection' parameter must be present") + + if self._seed is not None: + oid = self._curve.oid + private_key = DerOctetString(self._seed).encode() + params = None + else: + oid = "1.2.840.10045.2.1" # unrestricted + private_key = self._export_rfc5915_private_der(include_ec_params=False) + params = DerObjectId(self._curve.oid) + + result = PKCS8.wrap(private_key, + oid, + key_params=params, + **kwargs) + return result + + def _export_public_pem(self, compress): + from Cryptodome.IO import PEM + + encoded_der = self._export_subjectPublicKeyInfo(compress) + return PEM.encode(encoded_der, "PUBLIC KEY") + + def _export_private_pem(self, passphrase, **kwargs): + from Cryptodome.IO import PEM + + encoded_der = self._export_rfc5915_private_der() + return PEM.encode(encoded_der, "EC PRIVATE KEY", passphrase, **kwargs) + + def _export_private_clear_pkcs8_in_clear_pem(self): + from Cryptodome.IO import PEM + + encoded_der = self._export_pkcs8() + return PEM.encode(encoded_der, "PRIVATE KEY") + + def _export_private_encrypted_pkcs8_in_clear_pem(self, passphrase, **kwargs): + from Cryptodome.IO import PEM + + assert passphrase + if 'protection' not in kwargs: + raise ValueError("At least the 'protection' parameter should be present") + encoded_der = self._export_pkcs8(passphrase=passphrase, **kwargs) + return PEM.encode(encoded_der, "ENCRYPTED PRIVATE KEY") + + def _export_openssh(self, compress): + if self.has_private(): + raise ValueError("Cannot export OpenSSH private keys") + + desc = self._curve.openssh + + if desc is None: + raise ValueError("Cannot export %s keys as OpenSSH" % self.curve) + elif desc == "ssh-ed25519": + public_key = self._export_eddsa_public() + comps = (tobytes(desc), tobytes(public_key)) + else: + modulus_bytes = self.pointQ.size_in_bytes() + + if compress: + first_byte = 2 + self.pointQ.y.is_odd() + public_key = (bchr(first_byte) + + self.pointQ.x.to_bytes(modulus_bytes)) + else: + public_key = (b'\x04' + + self.pointQ.x.to_bytes(modulus_bytes) + + self.pointQ.y.to_bytes(modulus_bytes)) + + middle = desc.split("-")[2] + comps = (tobytes(desc), tobytes(middle), public_key) + + blob = b"".join([struct.pack(">I", len(x)) + x for x in comps]) + return desc + " " + tostr(binascii.b2a_base64(blob)) + + def export_key(self, **kwargs): + """Export this ECC key. + + Args: + format (string): + The output format: + + - ``'DER'``. The key will be encoded in ASN.1 DER format (binary). + For a public key, the ASN.1 ``subjectPublicKeyInfo`` structure + defined in `RFC5480`_ will be used. + For a private key, the ASN.1 ``ECPrivateKey`` structure defined + in `RFC5915`_ is used instead (possibly within a PKCS#8 envelope, + see the ``use_pkcs8`` flag below). + - ``'PEM'``. The key will be encoded in a PEM_ envelope (ASCII). + - ``'OpenSSH'``. The key will be encoded in the OpenSSH_ format + (ASCII, public keys only). + - ``'SEC1'``. The public key (i.e., the EC point) will be encoded + into ``bytes`` according to Section 2.3.3 of `SEC1`_ + (which is a subset of the older X9.62 ITU standard). + Only for NIST P-curves. + - ``'raw'``. The public key will be encoded as ``bytes``, + without any metadata. + + * For NIST P-curves: equivalent to ``'SEC1'``. + * For Ed25519 and Ed448: ``bytes`` in the format + defined in `RFC8032`_. + * For Curve25519 and Curve448: ``bytes`` in the format + defined in `RFC7748`_. + + passphrase (bytes or string): + (*Private keys only*) The passphrase to protect the + private key. + + use_pkcs8 (boolean): + (*Private keys only*) + If ``True`` (default and recommended), the `PKCS#8`_ representation + will be used. + It must be ``True`` for Ed25519, Ed448, Curve25519, and Curve448. + + If ``False`` and a passphrase is present, the obsolete PEM + encryption will be used. + + protection (string): + When a private key is exported with password-protection + and PKCS#8 (both ``DER`` and ``PEM`` formats), this parameter MUST be + present, + For all possible protection schemes, + refer to :ref:`the encryption parameters of PKCS#8`. + It is recommended to use ``'PBKDF2WithHMAC-SHA512AndAES128-CBC'``. + + compress (boolean): + If ``True``, the method returns a more compact representation + of the public key, with the X-coordinate only. + + If ``False`` (default), the method returns the full public key. + + This parameter is ignored for Ed25519/Ed448/Curve25519/Curve448, + as compression is mandatory. + + prot_params (dict): + When a private key is exported with password-protection + and PKCS#8 (both ``DER`` and ``PEM`` formats), this dictionary + contains the parameters to use to derive the encryption key + from the passphrase. + For all possible values, + refer to :ref:`the encryption parameters of PKCS#8`. + The recommendation is to use ``{'iteration_count':21000}`` for PBKDF2, + and ``{'iteration_count':131072}`` for scrypt. + + .. warning:: + If you don't provide a passphrase, the private key will be + exported in the clear! + + .. note:: + When exporting a private key with password-protection and `PKCS#8`_ + (both ``DER`` and ``PEM`` formats), any extra parameters + to ``export_key()`` will be passed to :mod:`Cryptodome.IO.PKCS8`. + + .. _PEM: http://www.ietf.org/rfc/rfc1421.txt + .. _`PEM encryption`: http://www.ietf.org/rfc/rfc1423.txt + .. _OpenSSH: http://www.openssh.com/txt/rfc5656.txt + .. _RFC5480: https://tools.ietf.org/html/rfc5480 + .. _SEC1: https://www.secg.org/sec1-v2.pdf + .. _RFC7748: https://tools.ietf.org/html/rfc7748 + + Returns: + A multi-line string (for ``'PEM'`` and ``'OpenSSH'``) or + ``bytes`` (for ``'DER'``, ``'SEC1'``, and ``'raw'``) with the encoded key. + """ + + args = kwargs.copy() + ext_format = args.pop("format") + if ext_format not in ("PEM", "DER", "OpenSSH", "SEC1", "raw"): + raise ValueError("Unknown format '%s'" % ext_format) + + compress = args.pop("compress", False) + + if self.has_private(): + passphrase = args.pop("passphrase", None) + if is_string(passphrase): + passphrase = tobytes(passphrase) + if not passphrase: + raise ValueError("Empty passphrase") + + use_pkcs8 = args.pop("use_pkcs8", True) + if use_pkcs8 is False: + if self._curve.is_edwards: + raise ValueError("'pkcs8' must be True for EdDSA curves") + if self._curve.is_montgomery: + raise ValueError("'pkcs8' must be True for Curve25519") + if 'protection' in args: + raise ValueError("'protection' is only supported for PKCS#8") + + if ext_format == "PEM": + if use_pkcs8: + if passphrase: + return self._export_private_encrypted_pkcs8_in_clear_pem(passphrase, **args) + else: + return self._export_private_clear_pkcs8_in_clear_pem() + else: + return self._export_private_pem(passphrase, **args) + elif ext_format == "DER": + # DER + if passphrase and not use_pkcs8: + raise ValueError("Private keys can only be encrpyted with DER using PKCS#8") + if use_pkcs8: + return self._export_pkcs8(passphrase=passphrase, **args) + else: + return self._export_rfc5915_private_der() + else: + raise ValueError("Private keys cannot be exported " + "in the '%s' format" % ext_format) + else: # Public key + if args: + raise ValueError("Unexpected parameters: '%s'" % args) + if ext_format == "PEM": + return self._export_public_pem(compress) + elif ext_format == "DER": + return self._export_subjectPublicKeyInfo(compress) + elif ext_format == "SEC1": + return self._export_SEC1(compress) + elif ext_format == "raw": + if self._curve.is_edwards: + return self._export_eddsa_public() + elif self._curve.is_montgomery: + return self._export_montgomery_public() + else: + return self._export_SEC1(compress) + else: + return self._export_openssh(compress) + + +def generate(**kwargs): + """Generate a new private key on the given curve. + + Args: + + curve (string): + Mandatory. It must be a curve name defined in the `ECC table`_. + + randfunc (callable): + Optional. The RNG to read randomness from. + If ``None``, :func:`Cryptodome.Random.get_random_bytes` is used. + """ + + curve_name = kwargs.pop("curve") + curve = _curves[curve_name] + randfunc = kwargs.pop("randfunc", get_random_bytes) + if kwargs: + raise TypeError("Unknown parameters: " + str(kwargs)) + + if _curves[curve_name].id == _CurveID.ED25519: + seed = randfunc(32) + new_key = EccKey(curve=curve_name, seed=seed) + elif _curves[curve_name].id == _CurveID.ED448: + seed = randfunc(57) + new_key = EccKey(curve=curve_name, seed=seed) + elif _curves[curve_name].id == _CurveID.CURVE25519: + seed = randfunc(32) + new_key = EccKey(curve=curve_name, seed=seed) + _curves[curve_name].validate(new_key.pointQ) + elif _curves[curve_name].id == _CurveID.CURVE448: + seed = randfunc(56) + new_key = EccKey(curve=curve_name, seed=seed) + _curves[curve_name].validate(new_key.pointQ) + else: + d = Integer.random_range(min_inclusive=1, + max_exclusive=curve.order, + randfunc=randfunc) + new_key = EccKey(curve=curve_name, d=d) + + return new_key + + +def construct(**kwargs): + """Build a new ECC key (private or public) starting + from some base components. + + In most cases, you will already have an existing key + which you can read in with :func:`import_key` instead + of this function. + + Args: + curve (string): + Mandatory. The name of the elliptic curve, as defined in the `ECC table`_. + + d (integer): + Mandatory for a private key and a NIST P-curve (e.g., P-256). + It must be an integer in the range ``[1..order-1]``. + + seed (bytes): + Mandatory for a private key and curves Ed25519 (32 bytes), + Curve25519 (32 bytes), Curve448 (56 bytes) and Ed448 (57 bytes). + + point_x (integer): + The X coordinate (affine) of the ECC point. + Mandatory for a public key. + + point_y (integer): + The Y coordinate (affine) of the ECC point. + Mandatory for a public key, + except for Curve25519 and Curve448. + + Returns: + :class:`EccKey` : a new ECC key object + """ + + curve_name = kwargs["curve"] + curve = _curves[curve_name] + point_x = kwargs.pop("point_x", None) + point_y = kwargs.pop("point_y", None) + + if "point" in kwargs: + raise TypeError("Unknown keyword: point") + + if curve.id == _CurveID.CURVE25519: + + if point_x is not None: + kwargs["point"] = EccXPoint(point_x, curve_name) + new_key = EccKey(**kwargs) + curve.validate(new_key.pointQ) + + elif curve.id == _CurveID.CURVE448: + + if point_x is not None: + kwargs["point"] = EccXPoint(point_x, curve_name) + new_key = EccKey(**kwargs) + curve.validate(new_key.pointQ) + + else: + + if None not in (point_x, point_y): + kwargs["point"] = EccPoint(point_x, point_y, curve_name) + new_key = EccKey(**kwargs) + + # Validate that the private key matches the public one + # because EccKey will not do that automatically + if new_key.has_private() and 'point' in kwargs: + pub_key = curve.G * new_key.d + if pub_key.xy != (point_x, point_y): + raise ValueError("Private and public ECC keys do not match") + + return new_key + + +def _import_public_der(ec_point, curve_oid=None, curve_name=None): + """Convert an encoded EC point into an EccKey object + + ec_point: byte string with the EC point (SEC1-encoded) + curve_oid: string with the name the curve + curve_name: string with the OID of the curve + + Either curve_id or curve_name must be specified + + """ + + for _curve_name, curve in _curves.items(): + if curve_oid and curve.oid == curve_oid: + break + if curve_name == _curve_name: + break + else: + if curve_oid: + raise UnsupportedEccFeature("Unsupported ECC curve (OID: %s)" % curve_oid) + else: + raise UnsupportedEccFeature("Unsupported ECC curve (%s)" % curve_name) + + # See 2.2 in RFC5480 and 2.3.3 in SEC1 + # The first byte is: + # - 0x02: compressed, only X-coordinate, Y-coordinate is even + # - 0x03: compressed, only X-coordinate, Y-coordinate is odd + # - 0x04: uncompressed, X-coordinate is followed by Y-coordinate + # + # PAI is in theory encoded as 0x00. + + modulus_bytes = curve.p.size_in_bytes() + point_type = bord(ec_point[0]) + + # Uncompressed point + if point_type == 0x04: + if len(ec_point) != (1 + 2 * modulus_bytes): + raise ValueError("Incorrect EC point length") + x = Integer.from_bytes(ec_point[1:modulus_bytes+1]) + y = Integer.from_bytes(ec_point[modulus_bytes+1:]) + # Compressed point + elif point_type in (0x02, 0x03): + if len(ec_point) != (1 + modulus_bytes): + raise ValueError("Incorrect EC point length") + x = Integer.from_bytes(ec_point[1:]) + # Right now, we only support Short Weierstrass curves + y = (x**3 - x*3 + curve.b).sqrt(curve.p) + if point_type == 0x02 and y.is_odd(): + y = curve.p - y + if point_type == 0x03 and y.is_even(): + y = curve.p - y + else: + raise ValueError("Incorrect EC point encoding") + + return construct(curve=_curve_name, point_x=x, point_y=y) + + +def _import_subjectPublicKeyInfo(encoded, *kwargs): + """Convert a subjectPublicKeyInfo into an EccKey object""" + + # See RFC5480 + + # Parse the generic subjectPublicKeyInfo structure + oid, ec_point, params = _expand_subject_public_key_info(encoded) + + nist_p_oids = ( + "1.2.840.10045.2.1", # id-ecPublicKey (unrestricted) + "1.3.132.1.12", # id-ecDH + "1.3.132.1.13" # id-ecMQV + ) + eddsa_oids = { + "1.3.101.112": ("Ed25519", _import_ed25519_public_key), # id-Ed25519 + "1.3.101.113": ("Ed448", _import_ed448_public_key) # id-Ed448 + } + xdh_oids = { + "1.3.101.110": ("Curve25519", _import_curve25519_public_key), # id-X25519 + "1.3.101.111": ("Curve448", _import_curve448_public_key), # id-X448 + } + + if oid in nist_p_oids: + # See RFC5480 + + # Parameters are mandatory and encoded as ECParameters + # ECParameters ::= CHOICE { + # namedCurve OBJECT IDENTIFIER + # -- implicitCurve NULL + # -- specifiedCurve SpecifiedECDomain + # } + # implicitCurve and specifiedCurve are not supported (as per RFC) + if not params: + raise ValueError("Missing ECC parameters for ECC OID %s" % oid) + try: + curve_oid = DerObjectId().decode(params).value + except ValueError: + raise ValueError("Error decoding namedCurve") + + # ECPoint ::= OCTET STRING + return _import_public_der(ec_point, curve_oid=curve_oid) + + elif oid in eddsa_oids: + # See RFC8410 + curve_name, import_eddsa_public_key = eddsa_oids[oid] + + # Parameters must be absent + if params: + raise ValueError("Unexpected ECC parameters for ECC OID %s" % oid) + + x, y = import_eddsa_public_key(ec_point) + return construct(point_x=x, point_y=y, curve=curve_name) + + elif oid in xdh_oids: + curve_name, import_xdh_public_key = xdh_oids[oid] + + # Parameters must be absent + if params: + raise ValueError("Unexpected ECC parameters for ECC OID %s" % oid) + + x = import_xdh_public_key(ec_point) + return construct(point_x=x, curve=curve_name) + + else: + raise UnsupportedEccFeature("Unsupported ECC OID: %s" % oid) + + +def _import_rfc5915_der(encoded, passphrase, curve_oid=None): + + # See RFC5915 https://tools.ietf.org/html/rfc5915 + # + # ECPrivateKey ::= SEQUENCE { + # version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1), + # privateKey OCTET STRING, + # parameters [0] ECParameters {{ NamedCurve }} OPTIONAL, + # publicKey [1] BIT STRING OPTIONAL + # } + + ec_private_key = DerSequence().decode(encoded, nr_elements=(2, 3, 4)) + if ec_private_key[0] != 1: + raise ValueError("Incorrect ECC private key version") + + scalar_bytes = DerOctetString().decode(ec_private_key[1]).payload + + next_element = 2 + + # Try to decode 'parameters' + if next_element < len(ec_private_key): + try: + parameters = DerObjectId(explicit=0).decode(ec_private_key[next_element]).value + if curve_oid is not None and parameters != curve_oid: + raise ValueError("Curve mismatch") + curve_oid = parameters + next_element += 1 + except ValueError: + pass + + if curve_oid is None: + raise ValueError("No curve found") + + for curve_name, curve in _curves.items(): + if curve.oid == curve_oid: + break + else: + raise UnsupportedEccFeature("Unsupported ECC curve (OID: %s)" % curve_oid) + + modulus_bytes = curve.p.size_in_bytes() + if len(scalar_bytes) != modulus_bytes: + raise ValueError("Private key is too small") + + # Try to decode 'publicKey' + point_x = point_y = None + if next_element < len(ec_private_key): + try: + public_key_enc = DerBitString(explicit=1).decode(ec_private_key[next_element]).value + public_key = _import_public_der(public_key_enc, curve_oid=curve_oid) + point_x = public_key.pointQ.x + point_y = public_key.pointQ.y + next_element += 1 + except ValueError: + pass + + d = Integer.from_bytes(scalar_bytes) + return construct(curve=curve_name, d=d, point_x=point_x, point_y=point_y) + + +def _import_pkcs8(encoded, passphrase): + from Cryptodome.IO import PKCS8 + + algo_oid, private_key, params = PKCS8.unwrap(encoded, passphrase) + + nist_p_oids = ( + "1.2.840.10045.2.1", # id-ecPublicKey (unrestricted) + "1.3.132.1.12", # id-ecDH + "1.3.132.1.13" # id-ecMQV + ) + eddsa_oids = { + "1.3.101.112": "Ed25519", # id-Ed25519 + "1.3.101.113": "Ed448", # id-Ed448 + } + xdh_oids = { + "1.3.101.110": "Curve25519", # id-X25519 + "1.3.101.111": "Curve448", # id-X448 + } + + if algo_oid in nist_p_oids: + curve_oid = DerObjectId().decode(params).value + return _import_rfc5915_der(private_key, passphrase, curve_oid) + elif algo_oid in eddsa_oids: + if params is not None: + raise ValueError("EdDSA ECC private key must not have parameters") + curve_oid = None + seed = DerOctetString().decode(private_key).payload + return construct(curve=eddsa_oids[algo_oid], seed=seed) + elif algo_oid in xdh_oids: + curve_name = xdh_oids[algo_oid] + if params is not None: + raise ValueError("%s ECC private key must not have parameters" % + curve_name) + curve_oid = None + seed = DerOctetString().decode(private_key).payload + return construct(curve=xdh_oids[algo_oid], seed=seed) + else: + raise UnsupportedEccFeature("Unsupported ECC purpose (OID: %s)" % algo_oid) + + +def _import_x509_cert(encoded, *kwargs): + + sp_info = _extract_subject_public_key_info(encoded) + return _import_subjectPublicKeyInfo(sp_info) + + +def _import_der(encoded, passphrase): + + try: + return _import_subjectPublicKeyInfo(encoded, passphrase) + except UnsupportedEccFeature as err: + raise err + except (ValueError, TypeError, IndexError): + pass + + try: + return _import_x509_cert(encoded, passphrase) + except UnsupportedEccFeature as err: + raise err + except (ValueError, TypeError, IndexError): + pass + + try: + return _import_rfc5915_der(encoded, passphrase) + except UnsupportedEccFeature as err: + raise err + except (ValueError, TypeError, IndexError): + pass + + try: + return _import_pkcs8(encoded, passphrase) + except UnsupportedEccFeature as err: + raise err + except (ValueError, TypeError, IndexError): + pass + + raise ValueError("Not an ECC DER key") + + +def _import_openssh_public(encoded): + parts = encoded.split(b' ') + if len(parts) not in (2, 3): + raise ValueError("Not an openssh public key") + + try: + keystring = binascii.a2b_base64(parts[1]) + + keyparts = [] + while len(keystring) > 4: + lk = struct.unpack(">I", keystring[:4])[0] + keyparts.append(keystring[4:4 + lk]) + keystring = keystring[4 + lk:] + + if parts[0] != keyparts[0]: + raise ValueError("Mismatch in openssh public key") + + # NIST P curves + if parts[0].startswith(b"ecdsa-sha2-"): + + for curve_name, curve in _curves.items(): + if curve.openssh is None: + continue + if not curve.openssh.startswith("ecdsa-sha2"): + continue + middle = tobytes(curve.openssh.split("-")[2]) + if keyparts[1] == middle: + break + else: + raise ValueError("Unsupported ECC curve: " + middle) + + ecc_key = _import_public_der(keyparts[2], curve_oid=curve.oid) + + # EdDSA + elif parts[0] == b"ssh-ed25519": + x, y = _import_ed25519_public_key(keyparts[1]) + ecc_key = construct(curve="Ed25519", point_x=x, point_y=y) + else: + raise ValueError("Unsupported SSH key type: " + parts[0]) + + except (IndexError, TypeError, binascii.Error): + raise ValueError("Error parsing SSH key type: " + parts[0]) + + return ecc_key + + +def _import_openssh_private_ecc(data, password): + + from ._openssh import (import_openssh_private_generic, + read_bytes, read_string, check_padding) + + key_type, decrypted = import_openssh_private_generic(data, password) + + eddsa_keys = { + "ssh-ed25519": ("Ed25519", _import_ed25519_public_key, 32), + } + + # https://datatracker.ietf.org/doc/html/draft-miller-ssh-agent-04 + if key_type.startswith("ecdsa-sha2"): + + ecdsa_curve_name, decrypted = read_string(decrypted) + if ecdsa_curve_name not in _curves: + raise UnsupportedEccFeature("Unsupported ECC curve %s" % ecdsa_curve_name) + curve = _curves[ecdsa_curve_name] + modulus_bytes = (curve.modulus_bits + 7) // 8 + + public_key, decrypted = read_bytes(decrypted) + + if bord(public_key[0]) != 4: + raise ValueError("Only uncompressed OpenSSH EC keys are supported") + if len(public_key) != 2 * modulus_bytes + 1: + raise ValueError("Incorrect public key length") + + point_x = Integer.from_bytes(public_key[1:1+modulus_bytes]) + point_y = Integer.from_bytes(public_key[1+modulus_bytes:]) + + private_key, decrypted = read_bytes(decrypted) + d = Integer.from_bytes(private_key) + + params = {'d': d, 'curve': ecdsa_curve_name} + + elif key_type in eddsa_keys: + + curve_name, import_eddsa_public_key, seed_len = eddsa_keys[key_type] + + public_key, decrypted = read_bytes(decrypted) + point_x, point_y = import_eddsa_public_key(public_key) + + private_public_key, decrypted = read_bytes(decrypted) + seed = private_public_key[:seed_len] + + params = {'seed': seed, 'curve': curve_name} + else: + raise ValueError("Unsupport SSH agent key type:" + key_type) + + _, padded = read_string(decrypted) # Comment + check_padding(padded) + + return construct(point_x=point_x, point_y=point_y, **params) + + +def _import_ed25519_public_key(encoded): + """Import an Ed25519 ECC public key, encoded as raw bytes as described + in RFC8032_. + + Args: + encoded (bytes): + The Ed25519 public key to import. It must be 32 bytes long. + + Returns: + x and y (integer) + + Raises: + ValueError: when the given key cannot be parsed. + + .. _RFC8032: https://datatracker.ietf.org/doc/html/rfc8032 + """ + + if len(encoded) != 32: + raise ValueError("Incorrect length. Only Ed25519 public keys are supported.") + + p = Integer(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed) # 2**255 - 19 + d = 37095705934669439343138083508754565189542113879843219016388785533085940283555 + + y = bytearray(encoded) + x_lsb = y[31] >> 7 + y[31] &= 0x7F + point_y = Integer.from_bytes(y, byteorder='little') + if point_y >= p: + raise ValueError("Invalid Ed25519 key (y)") + if point_y == 1: + return 0, 1 + + u = (point_y**2 - 1) % p + v = ((point_y**2 % p) * d + 1) % p + try: + v_inv = v.inverse(p) + x2 = (u * v_inv) % p + point_x = Integer._tonelli_shanks(x2, p) + if (point_x & 1) != x_lsb: + point_x = p - point_x + except ValueError: + raise ValueError("Invalid Ed25519 public key") + return point_x, point_y + + +def _import_curve25519_public_key(encoded): + """Import a Curve25519 ECC public key, + encoded as raw bytes as described in RFC7748_. + + Args: + encoded (bytes): + The Curve25519 public key to import. It must be 32 bytes long. + + Returns: + x (integer) + + Raises: + ValueError: when the given key cannot be parsed. + + .. _RFC7748: https://datatracker.ietf.org/doc/html/rfc7748 + """ + + if len(encoded) != 32: + raise ValueError("Incorrect Curve25519 key length") + + x = bytearray(encoded) + # RFC 7741, Section 5 + x[31] &= 0x7F + point_x = Integer.from_bytes(x, byteorder='little') + + return point_x + + +def _import_curve448_public_key(encoded): + """Import a Curve448 ECC public key, + encoded as raw bytes as described in RFC7748_. + + Args: + encoded (bytes): + The Curve448 public key to import. It must be 56 bytes long. + + Returns: + x (integer) + + Raises: + ValueError: when the given key cannot be parsed. + + .. _RFC7748: https://datatracker.ietf.org/doc/html/rfc7748 + """ + + if len(encoded) != 56: + raise ValueError("Incorrect Curve448 key length") + + point_x = Integer.from_bytes(encoded, byteorder='little') + + return point_x + + +def _import_ed448_public_key(encoded): + """Import an Ed448 ECC public key, encoded as raw bytes as described + in RFC8032_. + + Args: + encoded (bytes): + The Ed448 public key to import. It must be 57 bytes long. + + Returns: + x and y (integer) + + Raises: + ValueError: when the given key cannot be parsed. + + .. _RFC8032: https://datatracker.ietf.org/doc/html/rfc8032 + """ + + if len(encoded) != 57: + raise ValueError("Incorrect length. Only Ed448 public keys are supported.") + + p = _curves['curve448'].p + d = p - 39081 + + y = encoded[:56] + x_lsb = bord(encoded[56]) >> 7 + point_y = Integer.from_bytes(y, byteorder='little') + if point_y >= p: + raise ValueError("Invalid Ed448 key (y)") + if point_y == 1: + return 0, 1 + + u = (point_y**2 - 1) % p + v = ((point_y**2 % p) * d - 1) % p + try: + v_inv = v.inverse(p) + x2 = (u * v_inv) % p + point_x = Integer._tonelli_shanks(x2, p) + if (point_x & 1) != x_lsb: + point_x = p - point_x + except ValueError: + raise ValueError("Invalid Ed448 public key") + return point_x, point_y + + +def import_key(encoded, passphrase=None, curve_name=None): + """Import an ECC key (public or private). + + Args: + encoded (bytes or multi-line string): + The ECC key to import. + The function will try to automatically detect the right format. + + Supported formats for an ECC **public** key: + + * X.509 certificate: binary (DER) or ASCII (PEM). + * X.509 ``subjectPublicKeyInfo``: binary (DER) or ASCII (PEM). + * SEC1_ (or X9.62), as ``bytes``. NIST P curves only. + You must also provide the ``curve_name`` (with a value from the `ECC table`_) + * OpenSSH line, defined in RFC5656_ and RFC8709_ (ASCII). + This is normally the content of files like ``~/.ssh/id_ecdsa.pub``. + + Supported formats for an ECC **private** key: + + * A binary ``ECPrivateKey`` structure, as defined in `RFC5915`_ (DER). + NIST P curves only. + * A `PKCS#8`_ structure (or the more recent Asymmetric Key + Package, RFC5958_): binary (DER) or ASCII (PEM). + * `OpenSSH 6.5`_ and newer versions (ASCII). + + Private keys can be in the clear or password-protected. + + For details about the PEM encoding, see `RFC1421`_/`RFC1423`_. + + passphrase (byte string): + The passphrase to use for decrypting a private key. + Encryption may be applied protected at the PEM level (not recommended) + or at the PKCS#8 level (recommended). + This parameter is ignored if the key in input is not encrypted. + + curve_name (string): + For a SEC1 encoding only. This is the name of the curve, + as defined in the `ECC table`_. + + .. note:: + + To import EdDSA private and public keys, when encoded as raw ``bytes``, use: + + * :func:`Cryptodome.Signature.eddsa.import_public_key`, or + * :func:`Cryptodome.Signature.eddsa.import_private_key`. + + .. note:: + + To import X25519/X448 private and public keys, when encoded as raw ``bytes``, use: + + * :func:`Cryptodome.Protocol.DH.import_x25519_public_key` + * :func:`Cryptodome.Protocol.DH.import_x25519_private_key` + * :func:`Cryptodome.Protocol.DH.import_x448_public_key` + * :func:`Cryptodome.Protocol.DH.import_x448_private_key` + + Returns: + :class:`EccKey` : a new ECC key object + + Raises: + ValueError: when the given key cannot be parsed (possibly because + the pass phrase is wrong). + + .. _RFC1421: https://datatracker.ietf.org/doc/html/rfc1421 + .. _RFC1423: https://datatracker.ietf.org/doc/html/rfc1423 + .. _RFC5915: https://datatracker.ietf.org/doc/html/rfc5915 + .. _RFC5656: https://datatracker.ietf.org/doc/html/rfc5656 + .. _RFC8709: https://datatracker.ietf.org/doc/html/rfc8709 + .. _RFC5958: https://datatracker.ietf.org/doc/html/rfc5958 + .. _`PKCS#8`: https://datatracker.ietf.org/doc/html/rfc5208 + .. _`OpenSSH 6.5`: https://flak.tedunangst.com/post/new-openssh-key-format-and-bcrypt-pbkdf + .. _SEC1: https://www.secg.org/sec1-v2.pdf + """ + + from Cryptodome.IO import PEM + + encoded = tobytes(encoded) + if passphrase is not None: + passphrase = tobytes(passphrase) + + # PEM + if encoded.startswith(b'-----BEGIN OPENSSH PRIVATE KEY'): + text_encoded = tostr(encoded) + openssh_encoded, marker, enc_flag = PEM.decode(text_encoded, passphrase) + result = _import_openssh_private_ecc(openssh_encoded, passphrase) + return result + + elif encoded.startswith(b'-----'): + + text_encoded = tostr(encoded) + + # Remove any EC PARAMETERS section + # Ignore its content because the curve type must be already given in the key + ecparams_start = "-----BEGIN EC PARAMETERS-----" + ecparams_end = "-----END EC PARAMETERS-----" + text_encoded = re.sub(ecparams_start + ".*?" + ecparams_end, "", + text_encoded, + flags=re.DOTALL) + + der_encoded, marker, enc_flag = PEM.decode(text_encoded, passphrase) + if enc_flag: + passphrase = None + try: + result = _import_der(der_encoded, passphrase) + except UnsupportedEccFeature as uef: + raise uef + except ValueError: + raise ValueError("Invalid DER encoding inside the PEM file") + return result + + # OpenSSH + if encoded.startswith((b'ecdsa-sha2-', b'ssh-ed25519')): + return _import_openssh_public(encoded) + + # DER + if len(encoded) > 0 and bord(encoded[0]) == 0x30: + return _import_der(encoded, passphrase) + + # SEC1 + if len(encoded) > 0 and bord(encoded[0]) in (0x02, 0x03, 0x04): + if curve_name is None: + raise ValueError("No curve name was provided") + return _import_public_der(encoded, curve_name=curve_name) + + raise ValueError("ECC key format is not supported") + + +if __name__ == "__main__": + + import time + + d = 0xc51e4753afdec1e6b6c6a5b992f43f8dd0c7a8933072708b6522468b2ffb06fd + + point = _curves['p256'].G.copy() + count = 3000 + + start = time.time() + for x in range(count): + pointX = point * d + print("(P-256 G)", (time.time() - start) / count * 1000, "ms") + + start = time.time() + for x in range(count): + pointX = pointX * d + print("(P-256 arbitrary point)", (time.time() - start) / count * 1000, "ms") diff --git a/venv/Lib/site-packages/Cryptodome/PublicKey/ECC.pyi b/venv/Lib/site-packages/Cryptodome/PublicKey/ECC.pyi new file mode 100644 index 0000000..3d64727 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/PublicKey/ECC.pyi @@ -0,0 +1,80 @@ +from __future__ import annotations + +from typing import Union, Callable, Optional, Tuple, Dict, NamedTuple, Any, overload, Literal +from typing_extensions import TypedDict, Unpack, NotRequired + +from Cryptodome.Math.Numbers import Integer +from Cryptodome.IO._PBES import ProtParams + +from ._point import EccPoint as EccPoint +from ._point import EccXPoint as EccXPoint + +RNG = Callable[[int], bytes] + + +class UnsupportedEccFeature(ValueError): + ... + +class ExportParams(TypedDict): + passphrase: NotRequired[Union[bytes, str]] + use_pkcs8: NotRequired[bool] + protection: NotRequired[str] + compress: NotRequired[bool] + prot_params: NotRequired[ProtParams] + + +class EccKey(object): + curve: str + def __init__(self, *, curve: str = ..., d: int = ..., point: EccPoint = ...) -> None: ... + def __eq__(self, other: object) -> bool: ... + def __repr__(self) -> str: ... + def has_private(self) -> bool: ... + @property + def d(self) -> int: ... + @property + def pointQ(self) -> EccPoint: ... + def public_key(self) -> EccKey: ... + + @overload + def export_key(self, + *, + format: Literal['PEM', 'OpenSSH'], + **kwargs: Unpack[ExportParams]) -> str: ... + + @overload + def export_key(self, + *, + format: Literal['DER', 'SEC1', 'raw'], + **kwargs: Unpack[ExportParams]) -> bytes: ... + + +_Curve = NamedTuple("_Curve", [('p', Integer), + ('order', Integer), + ('b', Integer), + ('Gx', Integer), + ('Gy', Integer), + ('G', EccPoint), + ('modulus_bits', int), + ('oid', str), + ('context', Any), + ('desc', str), + ('openssh', Union[str, None]), + ]) + +_curves: Dict[str, _Curve] + +def _import_rfc5915_der(encoded: bytes, + passphrase: Optional[str] = None, + curve_oid: Optional[str] = None) -> EccKey: ... + +def generate(**kwargs: Union[str, RNG]) -> EccKey: ... +def construct(**kwargs: Union[str, int]) -> EccKey: ... + + +def import_key(encoded: Union[bytes, str], + passphrase: Optional[str] = None, + curve_name: Optional[str] = None) -> EccKey: ... + + +def _import_ed25519_public_key(encoded: bytes) -> EccKey: ... +def _import_ed448_public_key(encoded: bytes) -> EccKey: ... diff --git a/venv/Lib/site-packages/Cryptodome/PublicKey/ElGamal.py b/venv/Lib/site-packages/Cryptodome/PublicKey/ElGamal.py new file mode 100644 index 0000000..95c219e --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/PublicKey/ElGamal.py @@ -0,0 +1,286 @@ +# +# ElGamal.py : ElGamal encryption/decryption and signatures +# +# Part of the Python Cryptography Toolkit +# +# Originally written by: A.M. Kuchling +# +# =================================================================== +# The contents of this file are dedicated to the public domain. To +# the extent that dedication to the public domain is not available, +# everyone is granted a worldwide, perpetual, royalty-free, +# non-exclusive license to exercise all rights associated with the +# contents of this file for any purpose whatsoever. +# No rights are reserved. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# =================================================================== + +__all__ = ['generate', 'construct', 'ElGamalKey'] + +from Cryptodome import Random +from Cryptodome.Math.Primality import ( generate_probable_safe_prime, + test_probable_prime, COMPOSITE ) +from Cryptodome.Math.Numbers import Integer + +# Generate an ElGamal key with N bits +def generate(bits, randfunc): + """Randomly generate a fresh, new ElGamal key. + + The key will be safe for use for both encryption and signature + (although it should be used for **only one** purpose). + + Args: + bits (int): + Key length, or size (in bits) of the modulus *p*. + The recommended value is 2048. + randfunc (callable): + Random number generation function; it should accept + a single integer *N* and return a string of random + *N* random bytes. + + Return: + an :class:`ElGamalKey` object + """ + + obj=ElGamalKey() + + # Generate a safe prime p + # See Algorithm 4.86 in Handbook of Applied Cryptography + obj.p = generate_probable_safe_prime(exact_bits=bits, randfunc=randfunc) + q = (obj.p - 1) >> 1 + + # Generate generator g + while 1: + # Choose a square residue; it will generate a cyclic group of order q. + obj.g = pow(Integer.random_range(min_inclusive=2, + max_exclusive=obj.p, + randfunc=randfunc), 2, obj.p) + + # We must avoid g=2 because of Bleichenbacher's attack described + # in "Generating ElGamal signatures without knowning the secret key", + # 1996 + if obj.g in (1, 2): + continue + + # Discard g if it divides p-1 because of the attack described + # in Note 11.67 (iii) in HAC + if (obj.p - 1) % obj.g == 0: + continue + + # g^{-1} must not divide p-1 because of Khadir's attack + # described in "Conditions of the generator for forging ElGamal + # signature", 2011 + ginv = obj.g.inverse(obj.p) + if (obj.p - 1) % ginv == 0: + continue + + # Found + break + + # Generate private key x + obj.x = Integer.random_range(min_inclusive=2, + max_exclusive=obj.p-1, + randfunc=randfunc) + # Generate public key y + obj.y = pow(obj.g, obj.x, obj.p) + return obj + +def construct(tup): + r"""Construct an ElGamal key from a tuple of valid ElGamal components. + + The modulus *p* must be a prime. + The following conditions must apply: + + .. math:: + + \begin{align} + &1 < g < p-1 \\ + &g^{p-1} = 1 \text{ mod } 1 \\ + &1 < x < p-1 \\ + &g^x = y \text{ mod } p + \end{align} + + Args: + tup (tuple): + A tuple with either 3 or 4 integers, + in the following order: + + 1. Modulus (*p*). + 2. Generator (*g*). + 3. Public key (*y*). + 4. Private key (*x*). Optional. + + Raises: + ValueError: when the key being imported fails the most basic ElGamal validity checks. + + Returns: + an :class:`ElGamalKey` object + """ + + obj=ElGamalKey() + if len(tup) not in [3,4]: + raise ValueError('argument for construct() wrong length') + for i in range(len(tup)): + field = obj._keydata[i] + setattr(obj, field, Integer(tup[i])) + + fmt_error = test_probable_prime(obj.p) == COMPOSITE + fmt_error |= obj.g<=1 or obj.g>=obj.p + fmt_error |= pow(obj.g, obj.p-1, obj.p)!=1 + fmt_error |= obj.y<1 or obj.y>=obj.p + if len(tup)==4: + fmt_error |= obj.x<=1 or obj.x>=obj.p + fmt_error |= pow(obj.g, obj.x, obj.p)!=obj.y + + if fmt_error: + raise ValueError("Invalid ElGamal key components") + + return obj + +class ElGamalKey(object): + r"""Class defining an ElGamal key. + Do not instantiate directly. + Use :func:`generate` or :func:`construct` instead. + + :ivar p: Modulus + :vartype d: integer + + :ivar g: Generator + :vartype e: integer + + :ivar y: Public key component + :vartype y: integer + + :ivar x: Private key component + :vartype x: integer + """ + + #: Dictionary of ElGamal parameters. + #: + #: A public key will only have the following entries: + #: + #: - **y**, the public key. + #: - **g**, the generator. + #: - **p**, the modulus. + #: + #: A private key will also have: + #: + #: - **x**, the private key. + _keydata=['p', 'g', 'y', 'x'] + + def __init__(self, randfunc=None): + if randfunc is None: + randfunc = Random.new().read + self._randfunc = randfunc + + def _encrypt(self, M, K): + a=pow(self.g, K, self.p) + b=( pow(self.y, K, self.p)*M ) % self.p + return [int(a), int(b)] + + def _decrypt(self, M): + if (not hasattr(self, 'x')): + raise TypeError('Private key not available in this object') + r = Integer.random_range(min_inclusive=2, + max_exclusive=self.p-1, + randfunc=self._randfunc) + a_blind = (pow(self.g, r, self.p) * M[0]) % self.p + ax=pow(a_blind, self.x, self.p) + plaintext_blind = (ax.inverse(self.p) * M[1] ) % self.p + plaintext = (plaintext_blind * pow(self.y, r, self.p)) % self.p + return int(plaintext) + + def _sign(self, M, K): + if (not hasattr(self, 'x')): + raise TypeError('Private key not available in this object') + p1=self.p-1 + K = Integer(K) + if (K.gcd(p1)!=1): + raise ValueError('Bad K value: GCD(K,p-1)!=1') + a=pow(self.g, K, self.p) + t=(Integer(M)-self.x*a) % p1 + while t<0: t=t+p1 + b=(t*K.inverse(p1)) % p1 + return [int(a), int(b)] + + def _verify(self, M, sig): + sig = [Integer(x) for x in sig] + if sig[0]<1 or sig[0]>self.p-1: + return 0 + v1=pow(self.y, sig[0], self.p) + v1=(v1*pow(sig[0], sig[1], self.p)) % self.p + v2=pow(self.g, M, self.p) + if v1==v2: + return 1 + return 0 + + def has_private(self): + """Whether this is an ElGamal private key""" + + if hasattr(self, 'x'): + return 1 + else: + return 0 + + def can_encrypt(self): + return True + + def can_sign(self): + return True + + def publickey(self): + """A matching ElGamal public key. + + Returns: + a new :class:`ElGamalKey` object + """ + return construct((self.p, self.g, self.y)) + + def __eq__(self, other): + if bool(self.has_private()) != bool(other.has_private()): + return False + + result = True + for comp in self._keydata: + result = result and (getattr(self.key, comp, None) == + getattr(other.key, comp, None)) + return result + + def __ne__(self, other): + return not self.__eq__(other) + + def __getstate__(self): + # ElGamal key is not pickable + from pickle import PicklingError + raise PicklingError + + # Methods defined in PyCryptodome that we don't support anymore + + def sign(self, M, K): + raise NotImplementedError + + def verify(self, M, signature): + raise NotImplementedError + + def encrypt(self, plaintext, K): + raise NotImplementedError + + def decrypt(self, ciphertext): + raise NotImplementedError + + def blind(self, M, B): + raise NotImplementedError + + def unblind(self, M, B): + raise NotImplementedError + + def size(self): + raise NotImplementedError diff --git a/venv/Lib/site-packages/Cryptodome/PublicKey/ElGamal.pyi b/venv/Lib/site-packages/Cryptodome/PublicKey/ElGamal.pyi new file mode 100644 index 0000000..9048531 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/PublicKey/ElGamal.pyi @@ -0,0 +1,18 @@ +from typing import Callable, Union, Tuple, Optional + +__all__ = ['generate', 'construct', 'ElGamalKey'] + +RNG = Callable[[int], bytes] + +def generate(bits: int, randfunc: RNG) -> ElGamalKey: ... +def construct(tup: Union[Tuple[int, int, int], Tuple[int, int, int, int]]) -> ElGamalKey: ... + +class ElGamalKey(object): + def __init__(self, randfunc: Optional[RNG]=None) -> None: ... + def has_private(self) -> bool: ... + def can_encrypt(self) -> bool: ... + def can_sign(self) -> bool: ... + def publickey(self) -> ElGamalKey: ... + def __eq__(self, other: object) -> bool: ... + def __ne__(self, other: object) -> bool: ... + def __getstate__(self) -> None: ... diff --git a/venv/Lib/site-packages/Cryptodome/PublicKey/RSA.py b/venv/Lib/site-packages/Cryptodome/PublicKey/RSA.py new file mode 100644 index 0000000..476785e --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/PublicKey/RSA.py @@ -0,0 +1,871 @@ +# -*- coding: utf-8 -*- +# =================================================================== +# +# Copyright (c) 2016, Legrandin +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# =================================================================== + +__all__ = ['generate', 'construct', 'import_key', + 'RsaKey', 'oid'] + +import binascii +import struct + +from Cryptodome import Random +from Cryptodome.Util.py3compat import tobytes, bord, tostr +from Cryptodome.Util.asn1 import DerSequence, DerNull +from Cryptodome.Util.number import bytes_to_long + +from Cryptodome.Math.Numbers import Integer +from Cryptodome.Math.Primality import (test_probable_prime, + generate_probable_prime, COMPOSITE) + +from Cryptodome.PublicKey import (_expand_subject_public_key_info, + _create_subject_public_key_info, + _extract_subject_public_key_info) + + +class RsaKey(object): + r"""Class defining an RSA key, private or public. + Do not instantiate directly. + Use :func:`generate`, :func:`construct` or :func:`import_key` instead. + + :ivar n: RSA modulus + :vartype n: integer + + :ivar e: RSA public exponent + :vartype e: integer + + :ivar d: RSA private exponent + :vartype d: integer + + :ivar p: First factor of the RSA modulus + :vartype p: integer + + :ivar q: Second factor of the RSA modulus + :vartype q: integer + + :ivar invp: Chinese remainder component (:math:`p^{-1} \text{mod } q`) + :vartype invp: integer + + :ivar invq: Chinese remainder component (:math:`q^{-1} \text{mod } p`) + :vartype invq: integer + + :ivar u: Same as ``invp`` + :vartype u: integer + """ + + def __init__(self, **kwargs): + """Build an RSA key. + + :Keywords: + n : integer + The modulus. + e : integer + The public exponent. + d : integer + The private exponent. Only required for private keys. + p : integer + The first factor of the modulus. Only required for private keys. + q : integer + The second factor of the modulus. Only required for private keys. + u : integer + The CRT coefficient (inverse of p modulo q). Only required for + private keys. + """ + + input_set = set(kwargs.keys()) + public_set = set(('n', 'e')) + private_set = public_set | set(('p', 'q', 'd', 'u')) + if input_set not in (private_set, public_set): + raise ValueError("Some RSA components are missing") + for component, value in kwargs.items(): + setattr(self, "_" + component, value) + if input_set == private_set: + self._dp = self._d % (self._p - 1) # = (e⁻¹) mod (p-1) + self._dq = self._d % (self._q - 1) # = (e⁻¹) mod (q-1) + self._invq = None # will be computed on demand + + @property + def n(self): + return int(self._n) + + @property + def e(self): + return int(self._e) + + @property + def d(self): + if not self.has_private(): + raise AttributeError("No private exponent available for public keys") + return int(self._d) + + @property + def p(self): + if not self.has_private(): + raise AttributeError("No CRT component 'p' available for public keys") + return int(self._p) + + @property + def q(self): + if not self.has_private(): + raise AttributeError("No CRT component 'q' available for public keys") + return int(self._q) + + @property + def dp(self): + if not self.has_private(): + raise AttributeError("No CRT component 'dp' available for public keys") + return int(self._dp) + + @property + def dq(self): + if not self.has_private(): + raise AttributeError("No CRT component 'dq' available for public keys") + return int(self._dq) + + @property + def invq(self): + if not self.has_private(): + raise AttributeError("No CRT component 'invq' available for public keys") + if self._invq is None: + self._invq = self._q.inverse(self._p) + return int(self._invq) + + @property + def invp(self): + return self.u + + @property + def u(self): + if not self.has_private(): + raise AttributeError("No CRT component 'u' available for public keys") + return int(self._u) + + def size_in_bits(self): + """Size of the RSA modulus in bits""" + return self._n.size_in_bits() + + def size_in_bytes(self): + """The minimal amount of bytes that can hold the RSA modulus""" + return (self._n.size_in_bits() - 1) // 8 + 1 + + def _encrypt(self, plaintext): + if not 0 <= plaintext < self._n: + raise ValueError("Plaintext too large") + return int(pow(Integer(plaintext), self._e, self._n)) + + def _decrypt_to_bytes(self, ciphertext): + if not 0 <= ciphertext < self._n: + raise ValueError("Ciphertext too large") + if not self.has_private(): + raise TypeError("This is not a private key") + + # Blinded RSA decryption (to prevent timing attacks): + # Step 1: Generate random secret blinding factor r, + # such that 0 < r < n-1 + r = Integer.random_range(min_inclusive=1, max_exclusive=self._n) + # Step 2: Compute c' = c * r**e mod n + cp = Integer(ciphertext) * pow(r, self._e, self._n) % self._n + # Step 3: Compute m' = c'**d mod n (normal RSA decryption) + m1 = pow(cp, self._dp, self._p) + m2 = pow(cp, self._dq, self._q) + h = ((m2 - m1) * self._u) % self._q + mp = h * self._p + m1 + # Step 4: Compute m = m' * (r**(-1)) mod n + # then encode into a big endian byte string + result = Integer._mult_modulo_bytes( + r.inverse(self._n), + mp, + self._n) + return result + + def _decrypt(self, ciphertext): + """Legacy private method""" + + return bytes_to_long(self._decrypt_to_bytes(ciphertext)) + + def has_private(self): + """Whether this is an RSA private key""" + + return hasattr(self, "_d") + + def can_encrypt(self): # legacy + return True + + def can_sign(self): # legacy + return True + + def public_key(self): + """A matching RSA public key. + + Returns: + a new :class:`RsaKey` object + """ + return RsaKey(n=self._n, e=self._e) + + def __eq__(self, other): + if self.has_private() != other.has_private(): + return False + if self.n != other.n or self.e != other.e: + return False + if not self.has_private(): + return True + return (self.d == other.d) + + def __ne__(self, other): + return not (self == other) + + def __getstate__(self): + # RSA key is not pickable + from pickle import PicklingError + raise PicklingError + + def __repr__(self): + if self.has_private(): + extra = ", d=%d, p=%d, q=%d, u=%d" % (int(self._d), int(self._p), + int(self._q), int(self._u)) + else: + extra = "" + return "RsaKey(n=%d, e=%d%s)" % (int(self._n), int(self._e), extra) + + def __str__(self): + if self.has_private(): + key_type = "Private" + else: + key_type = "Public" + return "%s RSA key at 0x%X" % (key_type, id(self)) + + def export_key(self, format='PEM', passphrase=None, pkcs=1, + protection=None, randfunc=None, prot_params=None): + """Export this RSA key. + + Keyword Args: + format (string): + The desired output format: + + - ``'PEM'``. (default) Text output, according to `RFC1421`_/`RFC1423`_. + - ``'DER'``. Binary output. + - ``'OpenSSH'``. Text output, according to the OpenSSH specification. + Only suitable for public keys (not private keys). + + Note that PEM contains a DER structure. + + passphrase (bytes or string): + (*Private keys only*) The passphrase to protect the + private key. + + pkcs (integer): + (*Private keys only*) The standard to use for + serializing the key: PKCS#1 or PKCS#8. + + With ``pkcs=1`` (*default*), the private key is encoded with a + simple `PKCS#1`_ structure (``RSAPrivateKey``). The key cannot be + securely encrypted. + + With ``pkcs=8``, the private key is encoded with a `PKCS#8`_ structure + (``PrivateKeyInfo``). PKCS#8 offers the best ways to securely + encrypt the key. + + .. note:: + This parameter is ignored for a public key. + For DER and PEM, the output is always an + ASN.1 DER ``SubjectPublicKeyInfo`` structure. + + protection (string): + (*For private keys only*) + The encryption scheme to use for protecting the private key + using the passphrase. + + You can only specify a value if ``pkcs=8``. + For all possible protection schemes, + refer to :ref:`the encryption parameters of PKCS#8`. + The recommended value is + ``'PBKDF2WithHMAC-SHA512AndAES256-CBC'``. + + If ``None`` (default), the behavior depends on :attr:`format`: + + - if ``format='PEM'``, the obsolete PEM encryption scheme is used. + It is based on MD5 for key derivation, and 3DES for encryption. + + - if ``format='DER'``, the ``'PBKDF2WithHMAC-SHA1AndDES-EDE3-CBC'`` + scheme is used. + + prot_params (dict): + (*For private keys only*) + + The parameters to use to derive the encryption key + from the passphrase. ``'protection'`` must be also specified. + For all possible values, + refer to :ref:`the encryption parameters of PKCS#8`. + The recommendation is to use ``{'iteration_count':21000}`` for PBKDF2, + and ``{'iteration_count':131072}`` for scrypt. + + randfunc (callable): + A function that provides random bytes. Only used for PEM encoding. + The default is :func:`Cryptodome.Random.get_random_bytes`. + + Returns: + bytes: the encoded key + + Raises: + ValueError:when the format is unknown or when you try to encrypt a private + key with *DER* format and PKCS#1. + + .. warning:: + If you don't provide a pass phrase, the private key will be + exported in the clear! + + .. _RFC1421: http://www.ietf.org/rfc/rfc1421.txt + .. _RFC1423: http://www.ietf.org/rfc/rfc1423.txt + .. _`PKCS#1`: http://www.ietf.org/rfc/rfc3447.txt + .. _`PKCS#8`: http://www.ietf.org/rfc/rfc5208.txt + """ + + if passphrase is not None: + passphrase = tobytes(passphrase) + + if randfunc is None: + randfunc = Random.get_random_bytes + + if format == 'OpenSSH': + e_bytes, n_bytes = [x.to_bytes() for x in (self._e, self._n)] + if bord(e_bytes[0]) & 0x80: + e_bytes = b'\x00' + e_bytes + if bord(n_bytes[0]) & 0x80: + n_bytes = b'\x00' + n_bytes + keyparts = [b'ssh-rsa', e_bytes, n_bytes] + keystring = b''.join([struct.pack(">I", len(kp)) + kp for kp in keyparts]) + return b'ssh-rsa ' + binascii.b2a_base64(keystring)[:-1] + + # DER format is always used, even in case of PEM, which simply + # encodes it into BASE64. + if self.has_private(): + binary_key = DerSequence([0, + self.n, + self.e, + self.d, + self.p, + self.q, + self.d % (self.p-1), + self.d % (self.q-1), + Integer(self.q).inverse(self.p) + ]).encode() + if pkcs == 1: + key_type = 'RSA PRIVATE KEY' + if format == 'DER' and passphrase: + raise ValueError("PKCS#1 private key cannot be encrypted") + else: # PKCS#8 + from Cryptodome.IO import PKCS8 + + if format == 'PEM' and protection is None: + key_type = 'PRIVATE KEY' + binary_key = PKCS8.wrap(binary_key, oid, None, + key_params=DerNull()) + else: + key_type = 'ENCRYPTED PRIVATE KEY' + if not protection: + if prot_params: + raise ValueError("'protection' parameter must be set") + protection = 'PBKDF2WithHMAC-SHA1AndDES-EDE3-CBC' + binary_key = PKCS8.wrap(binary_key, oid, + passphrase, protection, + prot_params=prot_params, + key_params=DerNull()) + passphrase = None + else: + key_type = "PUBLIC KEY" + binary_key = _create_subject_public_key_info(oid, + DerSequence([self.n, + self.e]), + DerNull() + ) + + if format == 'DER': + return binary_key + if format == 'PEM': + from Cryptodome.IO import PEM + + pem_str = PEM.encode(binary_key, key_type, passphrase, randfunc) + return tobytes(pem_str) + + raise ValueError("Unknown key format '%s'. Cannot export the RSA key." % format) + + # Backward compatibility + def exportKey(self, *args, **kwargs): + """:meta private:""" + return self.export_key(*args, **kwargs) + + def publickey(self): + """:meta private:""" + return self.public_key() + + # Methods defined in PyCryptodome that we don't support anymore + def sign(self, M, K): + """:meta private:""" + raise NotImplementedError("Use module Cryptodome.Signature.pkcs1_15 instead") + + def verify(self, M, signature): + """:meta private:""" + raise NotImplementedError("Use module Cryptodome.Signature.pkcs1_15 instead") + + def encrypt(self, plaintext, K): + """:meta private:""" + raise NotImplementedError("Use module Cryptodome.Cipher.PKCS1_OAEP instead") + + def decrypt(self, ciphertext): + """:meta private:""" + raise NotImplementedError("Use module Cryptodome.Cipher.PKCS1_OAEP instead") + + def blind(self, M, B): + """:meta private:""" + raise NotImplementedError + + def unblind(self, M, B): + """:meta private:""" + raise NotImplementedError + + def size(self): + """:meta private:""" + raise NotImplementedError + + +def generate(bits, randfunc=None, e=65537): + """Create a new RSA key pair. + + The algorithm closely follows NIST `FIPS 186-4`_ in its + sections B.3.1 and B.3.3. The modulus is the product of + two non-strong probable primes. + Each prime passes a suitable number of Miller-Rabin tests + with random bases and a single Lucas test. + + Args: + bits (integer): + Key length, or size (in bits) of the RSA modulus. + It must be at least 1024, but **2048 is recommended.** + The FIPS standard only defines 1024, 2048 and 3072. + Keyword Args: + randfunc (callable): + Function that returns random bytes. + The default is :func:`Cryptodome.Random.get_random_bytes`. + e (integer): + Public RSA exponent. It must be an odd positive integer. + It is typically a small number with very few ones in its + binary representation. + The FIPS standard requires the public exponent to be + at least 65537 (the default). + + Returns: an RSA key object (:class:`RsaKey`, with private key). + + .. _FIPS 186-4: http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf + """ + + if bits < 1024: + raise ValueError("RSA modulus length must be >= 1024") + if e % 2 == 0 or e < 3: + raise ValueError("RSA public exponent must be a positive, odd integer larger than 2.") + + if randfunc is None: + randfunc = Random.get_random_bytes + + d = n = Integer(1) + e = Integer(e) + + while n.size_in_bits() != bits and d < (1 << (bits // 2)): + # Generate the prime factors of n: p and q. + # By construciton, their product is always + # 2^{bits-1} < p*q < 2^bits. + size_q = bits // 2 + size_p = bits - size_q + + min_p = min_q = (Integer(1) << (2 * size_q - 1)).sqrt() + if size_q != size_p: + min_p = (Integer(1) << (2 * size_p - 1)).sqrt() + + def filter_p(candidate): + return candidate > min_p and (candidate - 1).gcd(e) == 1 + + p = generate_probable_prime(exact_bits=size_p, + randfunc=randfunc, + prime_filter=filter_p) + + min_distance = Integer(1) << (bits // 2 - 100) + + def filter_q(candidate): + return (candidate > min_q and + (candidate - 1).gcd(e) == 1 and + abs(candidate - p) > min_distance) + + q = generate_probable_prime(exact_bits=size_q, + randfunc=randfunc, + prime_filter=filter_q) + + n = p * q + lcm = (p - 1).lcm(q - 1) + d = e.inverse(lcm) + + if p > q: + p, q = q, p + + u = p.inverse(q) + + return RsaKey(n=n, e=e, d=d, p=p, q=q, u=u) + + +def construct(rsa_components, consistency_check=True): + r"""Construct an RSA key from a tuple of valid RSA components. + + The modulus **n** must be the product of two primes. + The public exponent **e** must be odd and larger than 1. + + In case of a private key, the following equations must apply: + + .. math:: + + \begin{align} + p*q &= n \\ + e*d &\equiv 1 ( \text{mod lcm} [(p-1)(q-1)]) \\ + p*u &\equiv 1 ( \text{mod } q) + \end{align} + + Args: + rsa_components (tuple): + A tuple of integers, with at least 2 and no + more than 6 items. The items come in the following order: + + 1. RSA modulus *n*. + 2. Public exponent *e*. + 3. Private exponent *d*. + Only required if the key is private. + 4. First factor of *n* (*p*). + Optional, but the other factor *q* must also be present. + 5. Second factor of *n* (*q*). Optional. + 6. CRT coefficient *q*, that is :math:`p^{-1} \text{mod }q`. Optional. + + Keyword Args: + consistency_check (boolean): + If ``True``, the library will verify that the provided components + fulfil the main RSA properties. + + Raises: + ValueError: when the key being imported fails the most basic RSA validity checks. + + Returns: An RSA key object (:class:`RsaKey`). + """ + + class InputComps(object): + pass + + input_comps = InputComps() + for (comp, value) in zip(('n', 'e', 'd', 'p', 'q', 'u'), rsa_components): + setattr(input_comps, comp, Integer(value)) + + n = input_comps.n + e = input_comps.e + if not hasattr(input_comps, 'd'): + key = RsaKey(n=n, e=e) + else: + d = input_comps.d + if hasattr(input_comps, 'q'): + p = input_comps.p + q = input_comps.q + else: + # Compute factors p and q from the private exponent d. + # We assume that n has no more than two factors. + # See 8.2.2(i) in Handbook of Applied Cryptography. + ktot = d * e - 1 + # The quantity d*e-1 is a multiple of phi(n), even, + # and can be represented as t*2^s. + t = ktot + while t % 2 == 0: + t //= 2 + # Cycle through all multiplicative inverses in Zn. + # The algorithm is non-deterministic, but there is a 50% chance + # any candidate a leads to successful factoring. + # See "Digitalized Signatures and Public Key Functions as Intractable + # as Factorization", M. Rabin, 1979 + spotted = False + a = Integer(2) + while not spotted and a < 100: + k = Integer(t) + # Cycle through all values a^{t*2^i}=a^k + while k < ktot: + cand = pow(a, k, n) + # Check if a^k is a non-trivial root of unity (mod n) + if cand != 1 and cand != (n - 1) and pow(cand, 2, n) == 1: + # We have found a number such that (cand-1)(cand+1)=0 (mod n). + # Either of the terms divides n. + p = Integer(n).gcd(cand + 1) + spotted = True + break + k *= 2 + # This value was not any good... let's try another! + a += 2 + if not spotted: + raise ValueError("Unable to compute factors p and q from exponent d.") + # Found ! + assert ((n % p) == 0) + q = n // p + + if hasattr(input_comps, 'u'): + u = input_comps.u + else: + u = p.inverse(q) + + # Build key object + key = RsaKey(n=n, e=e, d=d, p=p, q=q, u=u) + + # Verify consistency of the key + if consistency_check: + + # Modulus and public exponent must be coprime + if e <= 1 or e >= n: + raise ValueError("Invalid RSA public exponent") + if Integer(n).gcd(e) != 1: + raise ValueError("RSA public exponent is not coprime to modulus") + + # For RSA, modulus must be odd + if not n & 1: + raise ValueError("RSA modulus is not odd") + + if key.has_private(): + # Modulus and private exponent must be coprime + if d <= 1 or d >= n: + raise ValueError("Invalid RSA private exponent") + if Integer(n).gcd(d) != 1: + raise ValueError("RSA private exponent is not coprime to modulus") + # Modulus must be product of 2 primes + if p * q != n: + raise ValueError("RSA factors do not match modulus") + if test_probable_prime(p) == COMPOSITE: + raise ValueError("RSA factor p is composite") + if test_probable_prime(q) == COMPOSITE: + raise ValueError("RSA factor q is composite") + # See Carmichael theorem + phi = (p - 1) * (q - 1) + lcm = phi // (p - 1).gcd(q - 1) + if (e * d % int(lcm)) != 1: + raise ValueError("Invalid RSA condition") + if hasattr(key, 'u'): + # CRT coefficient + if u <= 1 or u >= q: + raise ValueError("Invalid RSA component u") + if (p * u % q) != 1: + raise ValueError("Invalid RSA component u with p") + + return key + + +def _import_pkcs1_private(encoded, *kwargs): + # RSAPrivateKey ::= SEQUENCE { + # version Version, + # modulus INTEGER, -- n + # publicExponent INTEGER, -- e + # privateExponent INTEGER, -- d + # prime1 INTEGER, -- p + # prime2 INTEGER, -- q + # exponent1 INTEGER, -- d mod (p-1) + # exponent2 INTEGER, -- d mod (q-1) + # coefficient INTEGER -- (inverse of q) mod p + # } + # + # Version ::= INTEGER + der = DerSequence().decode(encoded, nr_elements=9, only_ints_expected=True) + if der[0] != 0: + raise ValueError("No PKCS#1 encoding of an RSA private key") + return construct(der[1:6] + [Integer(der[4]).inverse(der[5])]) + + +def _import_pkcs1_public(encoded, *kwargs): + # RSAPublicKey ::= SEQUENCE { + # modulus INTEGER, -- n + # publicExponent INTEGER -- e + # } + der = DerSequence().decode(encoded, nr_elements=2, only_ints_expected=True) + return construct(der) + + +def _import_subjectPublicKeyInfo(encoded, *kwargs): + + oids = (oid, "1.2.840.113549.1.1.10") + + algoid, encoded_key, params = _expand_subject_public_key_info(encoded) + if algoid not in oids or params is not None: + raise ValueError("No RSA subjectPublicKeyInfo") + return _import_pkcs1_public(encoded_key) + + +def _import_x509_cert(encoded, *kwargs): + + sp_info = _extract_subject_public_key_info(encoded) + return _import_subjectPublicKeyInfo(sp_info) + + +def _import_pkcs8(encoded, passphrase): + from Cryptodome.IO import PKCS8 + + oids = (oid, "1.2.840.113549.1.1.10") + + k = PKCS8.unwrap(encoded, passphrase) + if k[0] not in oids: + raise ValueError("No PKCS#8 encoded RSA key") + return _import_keyDER(k[1], passphrase) + + +def _import_keyDER(extern_key, passphrase): + """Import an RSA key (public or private half), encoded in DER form.""" + + decodings = (_import_pkcs1_private, + _import_pkcs1_public, + _import_subjectPublicKeyInfo, + _import_x509_cert, + _import_pkcs8) + + for decoding in decodings: + try: + return decoding(extern_key, passphrase) + except ValueError: + pass + + raise ValueError("RSA key format is not supported") + + +def _import_openssh_private_rsa(data, password): + + from ._openssh import (import_openssh_private_generic, + read_bytes, read_string, check_padding) + + ssh_name, decrypted = import_openssh_private_generic(data, password) + + if ssh_name != "ssh-rsa": + raise ValueError("This SSH key is not RSA") + + n, decrypted = read_bytes(decrypted) + e, decrypted = read_bytes(decrypted) + d, decrypted = read_bytes(decrypted) + iqmp, decrypted = read_bytes(decrypted) + p, decrypted = read_bytes(decrypted) + q, decrypted = read_bytes(decrypted) + + _, padded = read_string(decrypted) # Comment + check_padding(padded) + + build = [Integer.from_bytes(x) for x in (n, e, d, q, p, iqmp)] + return construct(build) + + +def import_key(extern_key, passphrase=None): + """Import an RSA key (public or private). + + Args: + extern_key (string or byte string): + The RSA key to import. + + The following formats are supported for an RSA **public key**: + + - X.509 certificate (binary or PEM format) + - X.509 ``subjectPublicKeyInfo`` DER SEQUENCE (binary or PEM + encoding) + - `PKCS#1`_ ``RSAPublicKey`` DER SEQUENCE (binary or PEM encoding) + - An OpenSSH line (e.g. the content of ``~/.ssh/id_ecdsa``, ASCII) + + The following formats are supported for an RSA **private key**: + + - PKCS#1 ``RSAPrivateKey`` DER SEQUENCE (binary or PEM encoding) + - `PKCS#8`_ ``PrivateKeyInfo`` or ``EncryptedPrivateKeyInfo`` + DER SEQUENCE (binary or PEM encoding) + - OpenSSH (text format, introduced in `OpenSSH 6.5`_) + + For details about the PEM encoding, see `RFC1421`_/`RFC1423`_. + + passphrase (string or byte string): + For private keys only, the pass phrase that encrypts the key. + + Returns: An RSA key object (:class:`RsaKey`). + + Raises: + ValueError/IndexError/TypeError: + When the given key cannot be parsed (possibly because the pass + phrase is wrong). + + .. _RFC1421: http://www.ietf.org/rfc/rfc1421.txt + .. _RFC1423: http://www.ietf.org/rfc/rfc1423.txt + .. _`PKCS#1`: http://www.ietf.org/rfc/rfc3447.txt + .. _`PKCS#8`: http://www.ietf.org/rfc/rfc5208.txt + .. _`OpenSSH 6.5`: https://flak.tedunangst.com/post/new-openssh-key-format-and-bcrypt-pbkdf + """ + + from Cryptodome.IO import PEM + + extern_key = tobytes(extern_key) + if passphrase is not None: + passphrase = tobytes(passphrase) + + if extern_key.startswith(b'-----BEGIN OPENSSH PRIVATE KEY'): + text_encoded = tostr(extern_key) + openssh_encoded, marker, enc_flag = PEM.decode(text_encoded, passphrase) + result = _import_openssh_private_rsa(openssh_encoded, passphrase) + return result + + if extern_key.startswith(b'-----'): + # This is probably a PEM encoded key. + (der, marker, enc_flag) = PEM.decode(tostr(extern_key), passphrase) + if enc_flag: + passphrase = None + return _import_keyDER(der, passphrase) + + if extern_key.startswith(b'ssh-rsa '): + # This is probably an OpenSSH key + keystring = binascii.a2b_base64(extern_key.split(b' ')[1]) + keyparts = [] + while len(keystring) > 4: + length = struct.unpack(">I", keystring[:4])[0] + keyparts.append(keystring[4:4 + length]) + keystring = keystring[4 + length:] + e = Integer.from_bytes(keyparts[1]) + n = Integer.from_bytes(keyparts[2]) + return construct([n, e]) + + if len(extern_key) > 0 and bord(extern_key[0]) == 0x30: + # This is probably a DER encoded key + return _import_keyDER(extern_key, passphrase) + + raise ValueError("RSA key format is not supported") + + +# Backward compatibility +importKey = import_key + +#: `Object ID`_ for the RSA encryption algorithm. This OID often indicates +#: a generic RSA key, even when such key will be actually used for digital +#: signatures. +#: +#: .. note: +#: An RSA key meant for PSS padding has a dedicated Object ID ``1.2.840.113549.1.1.10`` +#: +#: .. _`Object ID`: http://www.alvestrand.no/objectid/1.2.840.113549.1.1.1.html +oid = "1.2.840.113549.1.1.1" diff --git a/venv/Lib/site-packages/Cryptodome/PublicKey/RSA.pyi b/venv/Lib/site-packages/Cryptodome/PublicKey/RSA.pyi new file mode 100644 index 0000000..85f6c4a --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/PublicKey/RSA.pyi @@ -0,0 +1,78 @@ +from typing import Callable, Union, Tuple, Optional, overload, Literal + +from Cryptodome.Math.Numbers import Integer +from Cryptodome.IO._PBES import ProtParams + +__all__ = ['generate', 'construct', 'import_key', + 'RsaKey', 'oid'] + +RNG = Callable[[int], bytes] + +class RsaKey(object): + def __init__(self, **kwargs: int) -> None: ... + + @property + def n(self) -> int: ... + @property + def e(self) -> int: ... + @property + def d(self) -> int: ... + @property + def p(self) -> int: ... + @property + def q(self) -> int: ... + @property + def u(self) -> int: ... + @property + def invp(self) -> int: ... + @property + def invq(self) -> int: ... + + def size_in_bits(self) -> int: ... + def size_in_bytes(self) -> int: ... + def has_private(self) -> bool: ... + def can_encrypt(self) -> bool: ... # legacy + def can_sign(self) -> bool:... # legacy + def public_key(self) -> RsaKey: ... + def __eq__(self, other: object) -> bool: ... + def __ne__(self, other: object) -> bool: ... + def __getstate__(self) -> None: ... + def __repr__(self) -> str: ... + def __str__(self) -> str: ... + + @overload + def export_key(self, + format: Optional[str]="PEM", + passphrase: Optional[str]=None, + pkcs: Optional[int]=1, + protection: Optional[str]=None, + randfunc: Optional[RNG]=None + ) -> bytes: ... + @overload + def export_key(self, *, + format: Optional[str]="PEM", + passphrase: str, + pkcs: Literal[8], + protection: str, + randfunc: Optional[RNG]=None, + prot_params: ProtParams, + ) -> bytes: ... + + # Backward compatibility + exportKey = export_key + publickey = public_key + +Int = Union[int, Integer] + +def generate(bits: int, randfunc: Optional[RNG]=None, e: Optional[int]=65537) -> RsaKey: ... +def construct(rsa_components: Union[Tuple[Int, Int], # n, e + Tuple[Int, Int, Int], # n, e, d + Tuple[Int, Int, Int, Int, Int], # n, e, d, p, q + Tuple[Int, Int, Int, Int, Int, Int]], # n, e, d, p, q, crt_q + consistency_check: Optional[bool]=True) -> RsaKey: ... +def import_key(extern_key: Union[str, bytes], passphrase: Optional[str]=None) -> RsaKey: ... + +# Backward compatibility +importKey = import_key + +oid: str diff --git a/venv/Lib/site-packages/Cryptodome/PublicKey/__init__.py b/venv/Lib/site-packages/Cryptodome/PublicKey/__init__.py new file mode 100644 index 0000000..99b67a4 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/PublicKey/__init__.py @@ -0,0 +1,94 @@ +# -*- coding: utf-8 -*- +# +# =================================================================== +# The contents of this file are dedicated to the public domain. To +# the extent that dedication to the public domain is not available, +# everyone is granted a worldwide, perpetual, royalty-free, +# non-exclusive license to exercise all rights associated with the +# contents of this file for any purpose whatsoever. +# No rights are reserved. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# =================================================================== + +from Cryptodome.Util.asn1 import (DerSequence, DerInteger, DerBitString, + DerObjectId, DerNull) + + +def _expand_subject_public_key_info(encoded): + """Parse a SubjectPublicKeyInfo structure. + + It returns a triple with: + * OID (string) + * encoded public key (bytes) + * Algorithm parameters (bytes or None) + """ + + # + # SubjectPublicKeyInfo ::= SEQUENCE { + # algorithm AlgorithmIdentifier, + # subjectPublicKey BIT STRING + # } + # + # AlgorithmIdentifier ::= SEQUENCE { + # algorithm OBJECT IDENTIFIER, + # parameters ANY DEFINED BY algorithm OPTIONAL + # } + # + + spki = DerSequence().decode(encoded, nr_elements=2) + algo = DerSequence().decode(spki[0], nr_elements=(1,2)) + algo_oid = DerObjectId().decode(algo[0]) + spk = DerBitString().decode(spki[1]).value + + if len(algo) == 1: + algo_params = None + else: + try: + DerNull().decode(algo[1]) + algo_params = None + except: + algo_params = algo[1] + + return algo_oid.value, spk, algo_params + + +def _create_subject_public_key_info(algo_oid, public_key, params): + + if params is None: + algorithm = DerSequence([DerObjectId(algo_oid)]) + else: + algorithm = DerSequence([DerObjectId(algo_oid), params]) + + spki = DerSequence([algorithm, + DerBitString(public_key) + ]) + return spki.encode() + + +def _extract_subject_public_key_info(x509_certificate): + """Extract subjectPublicKeyInfo from a DER X.509 certificate.""" + + certificate = DerSequence().decode(x509_certificate, nr_elements=3) + tbs_certificate = DerSequence().decode(certificate[0], + nr_elements=range(6, 11)) + + index = 5 + try: + tbs_certificate[0] + 1 + # Version not present + version = 1 + except TypeError: + version = DerInteger(explicit=0).decode(tbs_certificate[0]).value + if version not in (2, 3): + raise ValueError("Incorrect X.509 certificate version") + index = 6 + + return tbs_certificate[index] diff --git a/venv/Lib/site-packages/Cryptodome/PublicKey/__init__.pyi b/venv/Lib/site-packages/Cryptodome/PublicKey/__init__.pyi new file mode 100644 index 0000000..e69de29 diff --git a/venv/Lib/site-packages/Cryptodome/PublicKey/__pycache__/DSA.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/PublicKey/__pycache__/DSA.cpython-312.pyc new file mode 100644 index 0000000..f190b27 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/PublicKey/__pycache__/DSA.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/PublicKey/__pycache__/ECC.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/PublicKey/__pycache__/ECC.cpython-312.pyc new file mode 100644 index 0000000..9fb3508 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/PublicKey/__pycache__/ECC.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/PublicKey/__pycache__/ElGamal.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/PublicKey/__pycache__/ElGamal.cpython-312.pyc new file mode 100644 index 0000000..3fefca0 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/PublicKey/__pycache__/ElGamal.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/PublicKey/__pycache__/RSA.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/PublicKey/__pycache__/RSA.cpython-312.pyc new file mode 100644 index 0000000..3ec48e7 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/PublicKey/__pycache__/RSA.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/PublicKey/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/PublicKey/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000..72b6d83 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/PublicKey/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/PublicKey/__pycache__/_curve.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/PublicKey/__pycache__/_curve.cpython-312.pyc new file mode 100644 index 0000000..5a0fc33 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/PublicKey/__pycache__/_curve.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/PublicKey/__pycache__/_edwards.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/PublicKey/__pycache__/_edwards.cpython-312.pyc new file mode 100644 index 0000000..4223546 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/PublicKey/__pycache__/_edwards.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/PublicKey/__pycache__/_montgomery.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/PublicKey/__pycache__/_montgomery.cpython-312.pyc new file mode 100644 index 0000000..5c4d3b2 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/PublicKey/__pycache__/_montgomery.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/PublicKey/__pycache__/_nist_ecc.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/PublicKey/__pycache__/_nist_ecc.cpython-312.pyc new file mode 100644 index 0000000..a637435 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/PublicKey/__pycache__/_nist_ecc.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/PublicKey/__pycache__/_openssh.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/PublicKey/__pycache__/_openssh.cpython-312.pyc new file mode 100644 index 0000000..7304451 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/PublicKey/__pycache__/_openssh.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/PublicKey/__pycache__/_point.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/PublicKey/__pycache__/_point.cpython-312.pyc new file mode 100644 index 0000000..f053c68 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/PublicKey/__pycache__/_point.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/PublicKey/_curve.py b/venv/Lib/site-packages/Cryptodome/PublicKey/_curve.py new file mode 100644 index 0000000..0027f61 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/PublicKey/_curve.py @@ -0,0 +1,37 @@ +# This file is licensed under the BSD 2-Clause License. +# See https://opensource.org/licenses/BSD-2-Clause for details. + +# This is the element of a database of curve parameters. Items are indexed by their +# human-friendly name, such as "P-256". The element has the following fields: +# +# - p the prime number that defines the finite field for all modulo operations +# - b the constant in the Short Weierstrass curve equation (can be None) +# - order the number of elements in the group with the generator below +# - Gx the affine coordinate X of the generator point +# - Gy the affine coordinate Y of the generator point +# - G the generator, as an EccPoint object +# - modulus_bits the minimum number of bits for encoding the modulus p +# - oid an ASCII string with the registered ASN.1 Object ID +# - context a raw pointer to memory holding a context for all curve operations (can be None) +# - canonical the canonical name of the curve +# - openssh the ASCII string used in OpenSSH id files for public keys on this curve +# - rawlib the reference to the dynamic libary with the low-level functions +# - validate a function that raises an exception if the the input point is invalid + +class _Curve(object): + + def __init__(self, p, b, order, Gx, Gy, G, modulus_bits, oid, context, + canonical, openssh, rawlib, validate=None): + self.p = p + self.b = b + self.order = order + self.Gx = Gx + self.Gy = Gy + self.G = G + self.modulus_bits = modulus_bits + self.oid = oid + self.context = context + self.canonical = canonical + self.openssh = openssh + self.rawlib = rawlib + self.validate = validate diff --git a/venv/Lib/site-packages/Cryptodome/PublicKey/_curve25519.pyd b/venv/Lib/site-packages/Cryptodome/PublicKey/_curve25519.pyd new file mode 100644 index 0000000..c40148a Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/PublicKey/_curve25519.pyd differ diff --git a/venv/Lib/site-packages/Cryptodome/PublicKey/_curve448.pyd b/venv/Lib/site-packages/Cryptodome/PublicKey/_curve448.pyd new file mode 100644 index 0000000..040d188 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/PublicKey/_curve448.pyd differ diff --git a/venv/Lib/site-packages/Cryptodome/PublicKey/_ec_ws.pyd b/venv/Lib/site-packages/Cryptodome/PublicKey/_ec_ws.pyd new file mode 100644 index 0000000..a47bb55 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/PublicKey/_ec_ws.pyd differ diff --git a/venv/Lib/site-packages/Cryptodome/PublicKey/_ed25519.pyd b/venv/Lib/site-packages/Cryptodome/PublicKey/_ed25519.pyd new file mode 100644 index 0000000..380de9a Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/PublicKey/_ed25519.pyd differ diff --git a/venv/Lib/site-packages/Cryptodome/PublicKey/_ed448.pyd b/venv/Lib/site-packages/Cryptodome/PublicKey/_ed448.pyd new file mode 100644 index 0000000..42a9b95 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/PublicKey/_ed448.pyd differ diff --git a/venv/Lib/site-packages/Cryptodome/PublicKey/_edwards.py b/venv/Lib/site-packages/Cryptodome/PublicKey/_edwards.py new file mode 100644 index 0000000..55de7b7 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/PublicKey/_edwards.py @@ -0,0 +1,116 @@ +# This file is licensed under the BSD 2-Clause License. +# See https://opensource.org/licenses/BSD-2-Clause for details. + +from ._curve import _Curve +from Cryptodome.Math.Numbers import Integer +from Cryptodome.Util._raw_api import (load_pycryptodome_raw_lib, VoidPointer, + SmartPointer) + + +def ed25519_curve(): + p = 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed # 2**255 - 19 + order = 0x1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3ed + Gx = 0x216936d3cd6e53fec0a4e231fdd6dc5c692cc7609525a7b2c9562d608f25d51a + Gy = 0x6666666666666666666666666666666666666666666666666666666666666658 + + _ed25519_lib = load_pycryptodome_raw_lib("Cryptodome.PublicKey._ed25519", """ +typedef void Point; +int ed25519_new_point(Point **out, + const uint8_t x[32], + const uint8_t y[32], + size_t modsize, + const void *context); +int ed25519_clone(Point **P, const Point *Q); +void ed25519_free_point(Point *p); +int ed25519_cmp(const Point *p1, const Point *p2); +int ed25519_neg(Point *p); +int ed25519_get_xy(uint8_t *xb, uint8_t *yb, size_t modsize, Point *p); +int ed25519_double(Point *p); +int ed25519_add(Point *P1, const Point *P2); +int ed25519_scalar(Point *P, const uint8_t *scalar, size_t scalar_len, uint64_t seed); +""") + + class EcLib(object): + new_point = _ed25519_lib.ed25519_new_point + clone = _ed25519_lib.ed25519_clone + free_point = _ed25519_lib.ed25519_free_point + cmp = _ed25519_lib.ed25519_cmp + neg = _ed25519_lib.ed25519_neg + get_xy = _ed25519_lib.ed25519_get_xy + double = _ed25519_lib.ed25519_double + add = _ed25519_lib.ed25519_add + scalar = _ed25519_lib.ed25519_scalar + + ed25519 = _Curve(Integer(p), + None, + Integer(order), + Integer(Gx), + Integer(Gy), + None, + 255, + "1.3.101.112", # RFC8410 + None, + "Ed25519", + "ssh-ed25519", + EcLib) + return ed25519 + + +def ed448_curve(): + p = 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffffff # 2**448 - 2**224 - 1 + order = 0x3fffffffffffffffffffffffffffffffffffffffffffffffffffffff7cca23e9c44edb49aed63690216cc2728dc58f552378c292ab5844f3 + Gx = 0x4f1970c66bed0ded221d15a622bf36da9e146570470f1767ea6de324a3d3a46412ae1af72ab66511433b80e18b00938e2626a82bc70cc05e + Gy = 0x693f46716eb6bc248876203756c9c7624bea73736ca3984087789c1e05a0c2d73ad3ff1ce67c39c4fdbd132c4ed7c8ad9808795bf230fa14 + + _ed448_lib = load_pycryptodome_raw_lib("Cryptodome.PublicKey._ed448", """ +typedef void EcContext; +typedef void PointEd448; +int ed448_new_context(EcContext **pec_ctx); +void ed448_context(EcContext *ec_ctx); +void ed448_free_context(EcContext *ec_ctx); +int ed448_new_point(PointEd448 **out, + const uint8_t x[56], + const uint8_t y[56], + size_t len, + const EcContext *context); +int ed448_clone(PointEd448 **P, const PointEd448 *Q); +void ed448_free_point(PointEd448 *p); +int ed448_cmp(const PointEd448 *p1, const PointEd448 *p2); +int ed448_neg(PointEd448 *p); +int ed448_get_xy(uint8_t *xb, uint8_t *yb, size_t len, const PointEd448 *p); +int ed448_double(PointEd448 *p); +int ed448_add(PointEd448 *P1, const PointEd448 *P2); +int ed448_scalar(PointEd448 *P, const uint8_t *scalar, size_t scalar_len, uint64_t seed); +""") + + class EcLib(object): + new_point = _ed448_lib.ed448_new_point + clone = _ed448_lib.ed448_clone + free_point = _ed448_lib.ed448_free_point + cmp = _ed448_lib.ed448_cmp + neg = _ed448_lib.ed448_neg + get_xy = _ed448_lib.ed448_get_xy + double = _ed448_lib.ed448_double + add = _ed448_lib.ed448_add + scalar = _ed448_lib.ed448_scalar + + ed448_context = VoidPointer() + result = _ed448_lib.ed448_new_context(ed448_context.address_of()) + if result: + raise ImportError("Error %d initializing Ed448 context" % result) + + context = SmartPointer(ed448_context.get(), _ed448_lib.ed448_free_context) + + ed448 = _Curve(Integer(p), + None, + Integer(order), + Integer(Gx), + Integer(Gy), + None, + 448, + "1.3.101.113", # RFC8410 + context, + "Ed448", + None, + EcLib) + return ed448 diff --git a/venv/Lib/site-packages/Cryptodome/PublicKey/_montgomery.py b/venv/Lib/site-packages/Cryptodome/PublicKey/_montgomery.py new file mode 100644 index 0000000..5e5fd51 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/PublicKey/_montgomery.py @@ -0,0 +1,152 @@ +# This file is licensed under the BSD 2-Clause License. +# See https://opensource.org/licenses/BSD-2-Clause for details. + +from ._curve import _Curve +from Cryptodome.Math.Numbers import Integer +from Cryptodome.Util._raw_api import (load_pycryptodome_raw_lib, VoidPointer, + SmartPointer) + + +def curve25519_curve(): + p = 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed # 2**255 - 19 + order = 0x1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3ed + + _curve25519_lib = load_pycryptodome_raw_lib("Cryptodome.PublicKey._curve25519", """ +typedef void Point; + +int curve25519_new_point(Point **out, + const uint8_t x[32], + size_t modsize, + const void* context); +int curve25519_clone(Point **P, const Point *Q); +void curve25519_free_point(Point *p); +int curve25519_get_x(uint8_t *xb, size_t modsize, Point *p); +int curve25519_scalar(Point *P, const uint8_t *scalar, size_t scalar_len, uint64_t seed); +int curve25519_cmp(const Point *ecp1, const Point *ecp2); +""") + + class EcLib(object): + new_point = _curve25519_lib.curve25519_new_point + clone = _curve25519_lib.curve25519_clone + free_point = _curve25519_lib.curve25519_free_point + get_x = _curve25519_lib.curve25519_get_x + scalar = _curve25519_lib.curve25519_scalar + cmp = _curve25519_lib.curve25519_cmp + + def _validate_x25519_point(point): + + p2 = p * 2 + x1 = 325606250916557431795983626356110631294008115727848805560023387167927233504 + x2 = 39382357235489614581723060781553021112529911719440698176882885853963445705823 + + # http://cr.yp.to/ecdh.html#validate + deny_list = ( + 0, + 1, + x1, + x2, + p - 1, + p, + p + 1, + p + x1, + p + x2, + p2 - 1, + p2, + p2 + 1, + ) + + try: + valid = point.x not in deny_list + except ValueError: + valid = False + + if not valid: + raise ValueError("Invalid Curve25519 public key") + + curve25519 = _Curve(Integer(p), + None, + Integer(order), + Integer(9), + None, + None, + 255, + "1.3.101.110", # RFC8410 + None, + "Curve25519", + None, + EcLib, + _validate_x25519_point, + ) + + return curve25519 + + +def curve448_curve(): + p = 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffffff # 2**448 - 2**224 - 1 + order = 0x3fffffffffffffffffffffffffffffffffffffffffffffffffffffff7cca23e9c44edb49aed63690216cc2728dc58f552378c292ab5844f3 + + _curve448_lib = load_pycryptodome_raw_lib("Cryptodome.PublicKey._curve448", """ +typedef void Curve448Context; +typedef void Curve448Point; + +int curve448_new_context(Curve448Context **pec_ctx); +void curve448_free_context(Curve448Context *ec_ctx); +int curve448_new_point(Curve448Point **out, + const uint8_t *x, + size_t len, + const Curve448Context *ec_ctx); +void curve448_free_point(Curve448Point *p); +int curve448_clone(Curve448Point **P, const Curve448Point *Q); +int curve448_get_x(uint8_t *xb, size_t modsize, const Curve448Point *p); +int curve448_scalar(Curve448Point *P, const uint8_t *scalar, size_t scalar_len, uint64_t seed); +int curve448_cmp(const Curve448Point *ecp1, const Curve448Point *ecp2); +""") + + class EcLib(object): + new_context = _curve448_lib.curve448_new_context + free_context = _curve448_lib.curve448_free_context + new_point = _curve448_lib.curve448_new_point + clone = _curve448_lib.curve448_clone + free_point = _curve448_lib.curve448_free_point + get_x = _curve448_lib.curve448_get_x + scalar = _curve448_lib.curve448_scalar + cmp = _curve448_lib.curve448_cmp + + curve448_context = VoidPointer() + result = EcLib.new_context(curve448_context.address_of()) + if result: + raise ImportError("Error %d initializing Curve448 context" % result) + + def _validate_x448_point(point): + deny_list = ( + 0, + 1, + p - 1, + p, + p + 1, + ) + + try: + valid = point.x not in deny_list + except ValueError: + valid = False + + if not valid: + raise ValueError("Invalid Curve448 public key") + + curve448 = _Curve(Integer(p), + None, + Integer(order), + Integer(5), + None, + None, + 448, + "1.3.101.111", # RFC8410 + SmartPointer(curve448_context.get(), EcLib.free_context), + "Curve448", + None, + EcLib, + _validate_x448_point, + ) + + return curve448 diff --git a/venv/Lib/site-packages/Cryptodome/PublicKey/_nist_ecc.py b/venv/Lib/site-packages/Cryptodome/PublicKey/_nist_ecc.py new file mode 100644 index 0000000..3065c65 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/PublicKey/_nist_ecc.py @@ -0,0 +1,246 @@ +# This file is licensed under the BSD 2-Clause License. +# See https://opensource.org/licenses/BSD-2-Clause for details. + +from ._curve import _Curve +from Cryptodome.Math.Numbers import Integer +from Cryptodome.Util._raw_api import (load_pycryptodome_raw_lib, VoidPointer, + SmartPointer, c_size_t, c_uint8_ptr, + c_ulonglong) +from Cryptodome.Util.number import long_to_bytes +from Cryptodome.Random.random import getrandbits + + +_ec_lib = load_pycryptodome_raw_lib("Cryptodome.PublicKey._ec_ws", """ +typedef void EcContext; +typedef void EcPoint; +int ec_ws_new_context(EcContext **pec_ctx, + const uint8_t *modulus, + const uint8_t *b, + const uint8_t *order, + size_t len, + uint64_t seed); +void ec_ws_free_context(EcContext *ec_ctx); +int ec_ws_new_point(EcPoint **pecp, + const uint8_t *x, + const uint8_t *y, + size_t len, + const EcContext *ec_ctx); +void ec_ws_free_point(EcPoint *ecp); +int ec_ws_get_xy(uint8_t *x, + uint8_t *y, + size_t len, + const EcPoint *ecp); +int ec_ws_double(EcPoint *p); +int ec_ws_add(EcPoint *ecpa, EcPoint *ecpb); +int ec_ws_scalar(EcPoint *ecp, + const uint8_t *k, + size_t len, + uint64_t seed); +int ec_ws_clone(EcPoint **pecp2, const EcPoint *ecp); +int ec_ws_cmp(const EcPoint *ecp1, const EcPoint *ecp2); +int ec_ws_neg(EcPoint *p); +""") + + +class EcLib(object): + new_context = _ec_lib.ec_ws_new_context + free_context = _ec_lib.ec_ws_free_context + new_point = _ec_lib.ec_ws_new_point + free_point = _ec_lib.ec_ws_free_point + get_xy = _ec_lib.ec_ws_get_xy + double = _ec_lib.ec_ws_double + add = _ec_lib.ec_ws_add + scalar = _ec_lib.ec_ws_scalar + clone = _ec_lib.ec_ws_clone + cmp = _ec_lib.ec_ws_cmp + neg = _ec_lib.ec_ws_neg + + +def p192_curve(): + p = 0xfffffffffffffffffffffffffffffffeffffffffffffffff + b = 0x64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1 + order = 0xffffffffffffffffffffffff99def836146bc9b1b4d22831 + Gx = 0x188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012 + Gy = 0x07192b95ffc8da78631011ed6b24cdd573f977a11e794811 + + p192_modulus = long_to_bytes(p, 24) + p192_b = long_to_bytes(b, 24) + p192_order = long_to_bytes(order, 24) + + ec_p192_context = VoidPointer() + result = _ec_lib.ec_ws_new_context(ec_p192_context.address_of(), + c_uint8_ptr(p192_modulus), + c_uint8_ptr(p192_b), + c_uint8_ptr(p192_order), + c_size_t(len(p192_modulus)), + c_ulonglong(getrandbits(64)) + ) + if result: + raise ImportError("Error %d initializing P-192 context" % result) + + context = SmartPointer(ec_p192_context.get(), _ec_lib.ec_ws_free_context) + p192 = _Curve(Integer(p), + Integer(b), + Integer(order), + Integer(Gx), + Integer(Gy), + None, + 192, + "1.2.840.10045.3.1.1", # ANSI X9.62 / SEC2 + context, + "NIST P-192", + "ecdsa-sha2-nistp192", + EcLib) + return p192 + + +def p224_curve(): + p = 0xffffffffffffffffffffffffffffffff000000000000000000000001 + b = 0xb4050a850c04b3abf54132565044b0b7d7bfd8ba270b39432355ffb4 + order = 0xffffffffffffffffffffffffffff16a2e0b8f03e13dd29455c5c2a3d + Gx = 0xb70e0cbd6bb4bf7f321390b94a03c1d356c21122343280d6115c1d21 + Gy = 0xbd376388b5f723fb4c22dfe6cd4375a05a07476444d5819985007e34 + + p224_modulus = long_to_bytes(p, 28) + p224_b = long_to_bytes(b, 28) + p224_order = long_to_bytes(order, 28) + + ec_p224_context = VoidPointer() + result = _ec_lib.ec_ws_new_context(ec_p224_context.address_of(), + c_uint8_ptr(p224_modulus), + c_uint8_ptr(p224_b), + c_uint8_ptr(p224_order), + c_size_t(len(p224_modulus)), + c_ulonglong(getrandbits(64)) + ) + if result: + raise ImportError("Error %d initializing P-224 context" % result) + + context = SmartPointer(ec_p224_context.get(), _ec_lib.ec_ws_free_context) + p224 = _Curve(Integer(p), + Integer(b), + Integer(order), + Integer(Gx), + Integer(Gy), + None, + 224, + "1.3.132.0.33", # SEC 2 + context, + "NIST P-224", + "ecdsa-sha2-nistp224", + EcLib) + return p224 + + +def p256_curve(): + p = 0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff + b = 0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b + order = 0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551 + Gx = 0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296 + Gy = 0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5 + + p256_modulus = long_to_bytes(p, 32) + p256_b = long_to_bytes(b, 32) + p256_order = long_to_bytes(order, 32) + + ec_p256_context = VoidPointer() + result = _ec_lib.ec_ws_new_context(ec_p256_context.address_of(), + c_uint8_ptr(p256_modulus), + c_uint8_ptr(p256_b), + c_uint8_ptr(p256_order), + c_size_t(len(p256_modulus)), + c_ulonglong(getrandbits(64)) + ) + if result: + raise ImportError("Error %d initializing P-256 context" % result) + + context = SmartPointer(ec_p256_context.get(), _ec_lib.ec_ws_free_context) + p256 = _Curve(Integer(p), + Integer(b), + Integer(order), + Integer(Gx), + Integer(Gy), + None, + 256, + "1.2.840.10045.3.1.7", # ANSI X9.62 / SEC2 + context, + "NIST P-256", + "ecdsa-sha2-nistp256", + EcLib) + return p256 + + +def p384_curve(): + p = 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000ffffffff + b = 0xb3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875ac656398d8a2ed19d2a85c8edd3ec2aef + order = 0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52973 + Gx = 0xaa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760aB7 + Gy = 0x3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5F + + p384_modulus = long_to_bytes(p, 48) + p384_b = long_to_bytes(b, 48) + p384_order = long_to_bytes(order, 48) + + ec_p384_context = VoidPointer() + result = _ec_lib.ec_ws_new_context(ec_p384_context.address_of(), + c_uint8_ptr(p384_modulus), + c_uint8_ptr(p384_b), + c_uint8_ptr(p384_order), + c_size_t(len(p384_modulus)), + c_ulonglong(getrandbits(64)) + ) + if result: + raise ImportError("Error %d initializing P-384 context" % result) + + context = SmartPointer(ec_p384_context.get(), _ec_lib.ec_ws_free_context) + p384 = _Curve(Integer(p), + Integer(b), + Integer(order), + Integer(Gx), + Integer(Gy), + None, + 384, + "1.3.132.0.34", # SEC 2 + context, + "NIST P-384", + "ecdsa-sha2-nistp384", + EcLib) + return p384 + + +def p521_curve(): + p = 0x000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff + b = 0x00000051953eb9618e1c9a1f929a21a0b68540eea2da725b99b315f3b8b489918ef109e156193951ec7e937b1652c0bd3bb1bf073573df883d2c34f1ef451fd46b503f00 + order = 0x000001fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e91386409 + Gx = 0x000000c6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f828af606b4d3dbaa14b5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf97e7e31c2e5bd66 + Gy = 0x0000011839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e662c97ee72995ef42640c550b9013fad0761353c7086a272c24088be94769fd16650 + + p521_modulus = long_to_bytes(p, 66) + p521_b = long_to_bytes(b, 66) + p521_order = long_to_bytes(order, 66) + + ec_p521_context = VoidPointer() + result = _ec_lib.ec_ws_new_context(ec_p521_context.address_of(), + c_uint8_ptr(p521_modulus), + c_uint8_ptr(p521_b), + c_uint8_ptr(p521_order), + c_size_t(len(p521_modulus)), + c_ulonglong(getrandbits(64)) + ) + if result: + raise ImportError("Error %d initializing P-521 context" % result) + + context = SmartPointer(ec_p521_context.get(), _ec_lib.ec_ws_free_context) + p521 = _Curve(Integer(p), + Integer(b), + Integer(order), + Integer(Gx), + Integer(Gy), + None, + 521, + "1.3.132.0.35", # SEC 2 + context, + "NIST P-521", + "ecdsa-sha2-nistp521", + EcLib) + return p521 diff --git a/venv/Lib/site-packages/Cryptodome/PublicKey/_openssh.py b/venv/Lib/site-packages/Cryptodome/PublicKey/_openssh.py new file mode 100644 index 0000000..53b16df --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/PublicKey/_openssh.py @@ -0,0 +1,135 @@ +# =================================================================== +# +# Copyright (c) 2019, Helder Eijs +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# =================================================================== + +import struct + +from Cryptodome.Cipher import AES +from Cryptodome.Hash import SHA512 +from Cryptodome.Protocol.KDF import _bcrypt_hash +from Cryptodome.Util.strxor import strxor +from Cryptodome.Util.py3compat import tostr, bchr, bord + + +def read_int4(data): + if len(data) < 4: + raise ValueError("Insufficient data") + value = struct.unpack(">I", data[:4])[0] + return value, data[4:] + + +def read_bytes(data): + size, data = read_int4(data) + if len(data) < size: + raise ValueError("Insufficient data (V)") + return data[:size], data[size:] + + +def read_string(data): + s, d = read_bytes(data) + return tostr(s), d + + +def check_padding(pad): + for v, x in enumerate(pad): + if bord(x) != ((v + 1) & 0xFF): + raise ValueError("Incorrect padding") + + +def import_openssh_private_generic(data, password): + # https://cvsweb.openbsd.org/cgi-bin/cvsweb/src/usr.bin/ssh/PROTOCOL.key?annotate=HEAD + # https://github.com/openssh/openssh-portable/blob/master/sshkey.c + # https://coolaj86.com/articles/the-openssh-private-key-format/ + # https://coolaj86.com/articles/the-ssh-public-key-format/ + + if not data.startswith(b'openssh-key-v1\x00'): + raise ValueError("Incorrect magic value") + data = data[15:] + + ciphername, data = read_string(data) + kdfname, data = read_string(data) + kdfoptions, data = read_bytes(data) + number_of_keys, data = read_int4(data) + + if number_of_keys != 1: + raise ValueError("We only handle 1 key at a time") + + _, data = read_string(data) # Public key + encrypted, data = read_bytes(data) + if data: + raise ValueError("Too much data") + + if len(encrypted) % 8 != 0: + raise ValueError("Incorrect payload length") + + # Decrypt if necessary + if ciphername == 'none': + decrypted = encrypted + else: + if (ciphername, kdfname) != ('aes256-ctr', 'bcrypt'): + raise ValueError("Unsupported encryption scheme %s/%s" % (ciphername, kdfname)) + + salt, kdfoptions = read_bytes(kdfoptions) + iterations, kdfoptions = read_int4(kdfoptions) + + if len(salt) != 16: + raise ValueError("Incorrect salt length") + if kdfoptions: + raise ValueError("Too much data in kdfoptions") + + pwd_sha512 = SHA512.new(password).digest() + # We need 32+16 = 48 bytes, therefore 2 bcrypt outputs are sufficient + stripes = [] + constant = b"OxychromaticBlowfishSwatDynamite" + for count in range(1, 3): + salt_sha512 = SHA512.new(salt + struct.pack(">I", count)).digest() + out_le = _bcrypt_hash(pwd_sha512, 6, salt_sha512, constant, False) + out = struct.pack("IIIIIIII", out_le)) + acc = bytearray(out) + for _ in range(1, iterations): + out_le = _bcrypt_hash(pwd_sha512, 6, SHA512.new(out).digest(), constant, False) + out = struct.pack("IIIIIIII", out_le)) + strxor(acc, out, output=acc) + stripes.append(acc[:24]) + + result = b"".join([bchr(a)+bchr(b) for (a, b) in zip(*stripes)]) + + cipher = AES.new(result[:32], + AES.MODE_CTR, + nonce=b"", + initial_value=result[32:32+16]) + decrypted = cipher.decrypt(encrypted) + + checkint1, decrypted = read_int4(decrypted) + checkint2, decrypted = read_int4(decrypted) + if checkint1 != checkint2: + raise ValueError("Incorrect checksum") + ssh_name, decrypted = read_string(decrypted) + + return ssh_name, decrypted diff --git a/venv/Lib/site-packages/Cryptodome/PublicKey/_openssh.pyi b/venv/Lib/site-packages/Cryptodome/PublicKey/_openssh.pyi new file mode 100644 index 0000000..15f3677 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/PublicKey/_openssh.pyi @@ -0,0 +1,7 @@ +from typing import Tuple + +def read_int4(data: bytes) -> Tuple[int, bytes]: ... +def read_bytes(data: bytes) -> Tuple[bytes, bytes]: ... +def read_string(data: bytes) -> Tuple[str, bytes]: ... +def check_padding(pad: bytes) -> None: ... +def import_openssh_private_generic(data: bytes, password: bytes) -> Tuple[str, bytes]: ... diff --git a/venv/Lib/site-packages/Cryptodome/PublicKey/_point.py b/venv/Lib/site-packages/Cryptodome/PublicKey/_point.py new file mode 100644 index 0000000..2afce9b --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/PublicKey/_point.py @@ -0,0 +1,493 @@ +# This file is licensed under the BSD 2-Clause License. +# See https://opensource.org/licenses/BSD-2-Clause for details. + +import threading + +from Cryptodome.Util.number import bytes_to_long, long_to_bytes +from Cryptodome.Util._raw_api import (VoidPointer, null_pointer, + SmartPointer, c_size_t, c_uint8_ptr, + c_ulonglong) +from Cryptodome.Math.Numbers import Integer +from Cryptodome.Random.random import getrandbits + + +class CurveID(object): + P192 = 1 + P224 = 2 + P256 = 3 + P384 = 4 + P521 = 5 + ED25519 = 6 + ED448 = 7 + CURVE25519 = 8 + CURVE448 = 9 + + +class _Curves(object): + + curves = {} + curves_lock = threading.RLock() + + p192_names = ["p192", "NIST P-192", "P-192", "prime192v1", "secp192r1", + "nistp192"] + p224_names = ["p224", "NIST P-224", "P-224", "prime224v1", "secp224r1", + "nistp224"] + p256_names = ["p256", "NIST P-256", "P-256", "prime256v1", "secp256r1", + "nistp256"] + p384_names = ["p384", "NIST P-384", "P-384", "prime384v1", "secp384r1", + "nistp384"] + p521_names = ["p521", "NIST P-521", "P-521", "prime521v1", "secp521r1", + "nistp521"] + ed25519_names = ["ed25519", "Ed25519"] + ed448_names = ["ed448", "Ed448"] + curve25519_names = ["curve25519", "Curve25519", "X25519"] + curve448_names = ["curve448", "Curve448", "X448"] + + all_names = p192_names + p224_names + p256_names + p384_names + p521_names + \ + ed25519_names + ed448_names + curve25519_names + curve448_names + + def __contains__(self, item): + return item in self.all_names + + def __dir__(self): + return self.all_names + + def load(self, name): + if name in self.p192_names: + from . import _nist_ecc + p192 = _nist_ecc.p192_curve() + p192.id = CurveID.P192 + self.curves.update(dict.fromkeys(self.p192_names, p192)) + elif name in self.p224_names: + from . import _nist_ecc + p224 = _nist_ecc.p224_curve() + p224.id = CurveID.P224 + self.curves.update(dict.fromkeys(self.p224_names, p224)) + elif name in self.p256_names: + from . import _nist_ecc + p256 = _nist_ecc.p256_curve() + p256.id = CurveID.P256 + self.curves.update(dict.fromkeys(self.p256_names, p256)) + elif name in self.p384_names: + from . import _nist_ecc + p384 = _nist_ecc.p384_curve() + p384.id = CurveID.P384 + self.curves.update(dict.fromkeys(self.p384_names, p384)) + elif name in self.p521_names: + from . import _nist_ecc + p521 = _nist_ecc.p521_curve() + p521.id = CurveID.P521 + self.curves.update(dict.fromkeys(self.p521_names, p521)) + elif name in self.ed25519_names: + from . import _edwards + ed25519 = _edwards.ed25519_curve() + ed25519.id = CurveID.ED25519 + self.curves.update(dict.fromkeys(self.ed25519_names, ed25519)) + elif name in self.ed448_names: + from . import _edwards + ed448 = _edwards.ed448_curve() + ed448.id = CurveID.ED448 + self.curves.update(dict.fromkeys(self.ed448_names, ed448)) + elif name in self.curve25519_names: + from . import _montgomery + curve25519 = _montgomery.curve25519_curve() + curve25519.id = CurveID.CURVE25519 + self.curves.update(dict.fromkeys(self.curve25519_names, curve25519)) + elif name in self.curve448_names: + from . import _montgomery + curve448 = _montgomery.curve448_curve() + curve448.id = CurveID.CURVE448 + self.curves.update(dict.fromkeys(self.curve448_names, curve448)) + else: + raise ValueError("Unsupported curve '%s'" % name) + return self.curves[name] + + def __getitem__(self, name): + with self.curves_lock: + curve = self.curves.get(name) + if curve is None: + curve = self.load(name) + if name in self.curve25519_names or name in self.curve448_names: + curve.G = EccXPoint(curve.Gx, name) + else: + curve.G = EccPoint(curve.Gx, curve.Gy, name) + curve.is_edwards = curve.id in (CurveID.ED25519, CurveID.ED448) + curve.is_montgomery = curve.id in (CurveID.CURVE25519, + CurveID.CURVE448) + curve.is_weierstrass = not (curve.is_edwards or + curve.is_montgomery) + return curve + + def items(self): + # Load all curves + for name in self.all_names: + _ = self[name] + return self.curves.items() + + +_curves = _Curves() + + +class EccPoint(object): + """A class to model a point on an Elliptic Curve. + + The class supports operators for: + + * Adding two points: ``R = S + T`` + * In-place addition: ``S += T`` + * Negating a point: ``R = -T`` + * Comparing two points: ``if S == T: ...`` or ``if S != T: ...`` + * Multiplying a point by a scalar: ``R = S*k`` + * In-place multiplication by a scalar: ``T *= k`` + + :ivar curve: The **canonical** name of the curve as defined in the `ECC table`_. + :vartype curve: string + + :ivar x: The affine X-coordinate of the ECC point + :vartype x: integer + + :ivar y: The affine Y-coordinate of the ECC point + :vartype y: integer + + :ivar xy: The tuple with affine X- and Y- coordinates + """ + + def __init__(self, x, y, curve="p256"): + + try: + self._curve = _curves[curve] + except KeyError: + raise ValueError("Unknown curve name %s" % str(curve)) + self.curve = self._curve.canonical + + if self._curve.id == CurveID.CURVE25519: + raise ValueError("EccPoint cannot be created for Curve25519") + + modulus_bytes = self.size_in_bytes() + + xb = long_to_bytes(x, modulus_bytes) + yb = long_to_bytes(y, modulus_bytes) + if len(xb) != modulus_bytes or len(yb) != modulus_bytes: + raise ValueError("Incorrect coordinate length") + + new_point = self._curve.rawlib.new_point + free_func = self._curve.rawlib.free_point + + self._point = VoidPointer() + try: + context = self._curve.context.get() + except AttributeError: + context = null_pointer + result = new_point(self._point.address_of(), + c_uint8_ptr(xb), + c_uint8_ptr(yb), + c_size_t(modulus_bytes), + context) + + if result: + if result == 15: + raise ValueError("The EC point does not belong to the curve") + raise ValueError("Error %d while instantiating an EC point" % result) + + # Ensure that object disposal of this Python object will (eventually) + # free the memory allocated by the raw library for the EC point + self._point = SmartPointer(self._point.get(), free_func) + + def set(self, point): + clone = self._curve.rawlib.clone + free_func = self._curve.rawlib.free_point + + self._point = VoidPointer() + result = clone(self._point.address_of(), + point._point.get()) + + if result: + raise ValueError("Error %d while cloning an EC point" % result) + + self._point = SmartPointer(self._point.get(), free_func) + return self + + def __eq__(self, point): + if not isinstance(point, EccPoint): + return False + + cmp_func = self._curve.rawlib.cmp + return 0 == cmp_func(self._point.get(), point._point.get()) + + # Only needed for Python 2 + def __ne__(self, point): + return not self == point + + def __neg__(self): + neg_func = self._curve.rawlib.neg + np = self.copy() + result = neg_func(np._point.get()) + if result: + raise ValueError("Error %d while inverting an EC point" % result) + return np + + def copy(self): + """Return a copy of this point.""" + x, y = self.xy + np = EccPoint(x, y, self.curve) + return np + + def is_point_at_infinity(self): + """``True`` if this is the *point-at-infinity*.""" + + if self._curve.is_edwards: + return self.x == 0 + else: + return self.xy == (0, 0) + + def point_at_infinity(self): + """Return the *point-at-infinity* for the curve.""" + + if self._curve.is_edwards: + return EccPoint(0, 1, self.curve) + else: + return EccPoint(0, 0, self.curve) + + @property + def x(self): + return self.xy[0] + + @property + def y(self): + return self.xy[1] + + @property + def xy(self): + modulus_bytes = self.size_in_bytes() + xb = bytearray(modulus_bytes) + yb = bytearray(modulus_bytes) + get_xy = self._curve.rawlib.get_xy + result = get_xy(c_uint8_ptr(xb), + c_uint8_ptr(yb), + c_size_t(modulus_bytes), + self._point.get()) + if result: + raise ValueError("Error %d while encoding an EC point" % result) + + return (Integer(bytes_to_long(xb)), Integer(bytes_to_long(yb))) + + def size_in_bytes(self): + """Size of each coordinate, in bytes.""" + return (self.size_in_bits() + 7) // 8 + + def size_in_bits(self): + """Size of each coordinate, in bits.""" + return self._curve.modulus_bits + + def double(self): + """Double this point (in-place operation). + + Returns: + This same object (to enable chaining). + """ + + double_func = self._curve.rawlib.double + result = double_func(self._point.get()) + if result: + raise ValueError("Error %d while doubling an EC point" % result) + return self + + def __iadd__(self, point): + """Add a second point to this one""" + + add_func = self._curve.rawlib.add + result = add_func(self._point.get(), point._point.get()) + if result: + if result == 16: + raise ValueError("EC points are not on the same curve") + raise ValueError("Error %d while adding two EC points" % result) + return self + + def __add__(self, point): + """Return a new point, the addition of this one and another""" + + np = self.copy() + np += point + return np + + def __imul__(self, scalar): + """Multiply this point by a scalar""" + + scalar_func = self._curve.rawlib.scalar + if scalar < 0: + raise ValueError("Scalar multiplication is only defined for non-negative integers") + sb = long_to_bytes(scalar) + result = scalar_func(self._point.get(), + c_uint8_ptr(sb), + c_size_t(len(sb)), + c_ulonglong(getrandbits(64))) + if result: + raise ValueError("Error %d during scalar multiplication" % result) + return self + + def __mul__(self, scalar): + """Return a new point, the scalar product of this one""" + + np = self.copy() + np *= scalar + return np + + def __rmul__(self, left_hand): + return self.__mul__(left_hand) + + +class EccXPoint(object): + """A class to model a point on an Elliptic Curve, + where only the X-coordinate is exposed. + + The class supports operators for: + + * Multiplying a point by a scalar: ``R = S*k`` + * In-place multiplication by a scalar: ``T *= k`` + + :ivar curve: The **canonical** name of the curve as defined in the `ECC table`_. + :vartype curve: string + + :ivar x: The affine X-coordinate of the ECC point + :vartype x: integer + """ + + def __init__(self, x, curve): + # Once encoded, x must not exceed the length of the modulus, + # but its value may match or exceed the modulus itself + # (i.e., non-canonical value) + + try: + self._curve = _curves[curve] + except KeyError: + raise ValueError("Unknown curve name %s" % str(curve)) + self.curve = self._curve.canonical + + if self._curve.id not in (CurveID.CURVE25519, CurveID.CURVE448): + raise ValueError("EccXPoint can only be created for Curve25519/Curve448") + + new_point = self._curve.rawlib.new_point + free_func = self._curve.rawlib.free_point + + self._point = VoidPointer() + try: + context = self._curve.context.get() + except AttributeError: + context = null_pointer + + modulus_bytes = self.size_in_bytes() + + if x is None: + xb = null_pointer + else: + xb = c_uint8_ptr(long_to_bytes(x, modulus_bytes)) + if len(xb) != modulus_bytes: + raise ValueError("Incorrect coordinate length") + + self._point = VoidPointer() + result = new_point(self._point.address_of(), + xb, + c_size_t(modulus_bytes), + context) + + if result == 15: + raise ValueError("The EC point does not belong to the curve") + if result: + raise ValueError("Error %d while instantiating an EC point" % result) + + # Ensure that object disposal of this Python object will (eventually) + # free the memory allocated by the raw library for the EC point + self._point = SmartPointer(self._point.get(), free_func) + + def set(self, point): + clone = self._curve.rawlib.clone + free_func = self._curve.rawlib.free_point + + self._point = VoidPointer() + result = clone(self._point.address_of(), + point._point.get()) + if result: + raise ValueError("Error %d while cloning an EC point" % result) + + self._point = SmartPointer(self._point.get(), free_func) + return self + + def __eq__(self, point): + if not isinstance(point, EccXPoint): + return False + + cmp_func = self._curve.rawlib.cmp + p1 = self._point.get() + p2 = point._point.get() + res = cmp_func(p1, p2) + return 0 == res + + def copy(self): + """Return a copy of this point.""" + + try: + x = self.x + except ValueError: + return self.point_at_infinity() + return EccXPoint(x, self.curve) + + def is_point_at_infinity(self): + """``True`` if this is the *point-at-infinity*.""" + + try: + _ = self.x + except ValueError: + return True + return False + + def point_at_infinity(self): + """Return the *point-at-infinity* for the curve.""" + + return EccXPoint(None, self.curve) + + @property + def x(self): + modulus_bytes = self.size_in_bytes() + xb = bytearray(modulus_bytes) + get_x = self._curve.rawlib.get_x + result = get_x(c_uint8_ptr(xb), + c_size_t(modulus_bytes), + self._point.get()) + if result == 19: # ERR_ECC_PAI + raise ValueError("No X coordinate for the point at infinity") + if result: + raise ValueError("Error %d while getting X of an EC point" % result) + return Integer(bytes_to_long(xb)) + + def size_in_bytes(self): + """Size of each coordinate, in bytes.""" + return (self.size_in_bits() + 7) // 8 + + def size_in_bits(self): + """Size of each coordinate, in bits.""" + return self._curve.modulus_bits + + def __imul__(self, scalar): + """Multiply this point by a scalar""" + + scalar_func = self._curve.rawlib.scalar + if scalar < 0: + raise ValueError("Scalar multiplication is only defined for non-negative integers") + sb = long_to_bytes(scalar) + result = scalar_func(self._point.get(), + c_uint8_ptr(sb), + c_size_t(len(sb)), + c_ulonglong(getrandbits(64))) + if result: + raise ValueError("Error %d during scalar multiplication" % result) + return self + + def __mul__(self, scalar): + """Return a new point, the scalar product of this one""" + + np = self.copy() + np *= scalar + return np + + def __rmul__(self, left_hand): + return self.__mul__(left_hand) diff --git a/venv/Lib/site-packages/Cryptodome/PublicKey/_point.pyi b/venv/Lib/site-packages/Cryptodome/PublicKey/_point.pyi new file mode 100644 index 0000000..2518e2e --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/PublicKey/_point.pyi @@ -0,0 +1,49 @@ +from typing import Union, Optional, Tuple + +from Cryptodome.Math.Numbers import Integer + +class EccPoint(object): + curve: str + def __init__(self, + x: Union[int, Integer], + y: Union[int, Integer], + curve: Optional[str] = ...) -> None: ... + + def set(self, point: EccPoint) -> EccPoint: ... + def __eq__(self, point: object) -> bool: ... + def __neg__(self) -> EccPoint: ... + def copy(self) -> EccPoint: ... + def is_point_at_infinity(self) -> bool: ... + def point_at_infinity(self) -> EccPoint: ... + @property + def x(self) -> int: ... + @property + def y(self) -> int: ... + @property + def xy(self) -> Tuple[int, int]: ... + def size_in_bytes(self) -> int: ... + def size_in_bits(self) -> int: ... + def double(self) -> EccPoint: ... + def __iadd__(self, point: EccPoint) -> EccPoint: ... + def __add__(self, point: EccPoint) -> EccPoint: ... + def __imul__(self, scalar: int) -> EccPoint: ... + def __mul__(self, scalar: int) -> EccPoint: ... + + +class EccXPoint(object): + curve: str + def __init__(self, + x: Union[int, Integer], + curve: Optional[str] = ...) -> None: ... + def set(self, point: EccXPoint) -> EccXPoint: ... + def __eq__(self, point: object) -> bool: ... + def copy(self) -> EccXPoint: ... + def is_point_at_infinity(self) -> bool: ... + def point_at_infinity(self) -> EccXPoint: ... + @property + def x(self) -> int: ... + def size_in_bytes(self) -> int: ... + def size_in_bits(self) -> int: ... + def __imul__(self, scalar: int) -> EccXPoint: ... + def __mul__(self, scalar: int) -> EccXPoint: ... + def __rmul__(self, left_hand: int) -> EccXPoint: ... diff --git a/venv/Lib/site-packages/Cryptodome/Random/__init__.py b/venv/Lib/site-packages/Cryptodome/Random/__init__.py new file mode 100644 index 0000000..fd18d86 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Random/__init__.py @@ -0,0 +1,57 @@ +# -*- coding: utf-8 -*- +# +# Random/__init__.py : PyCryptodome random number generation +# +# =================================================================== +# The contents of this file are dedicated to the public domain. To +# the extent that dedication to the public domain is not available, +# everyone is granted a worldwide, perpetual, royalty-free, +# non-exclusive license to exercise all rights associated with the +# contents of this file for any purpose whatsoever. +# No rights are reserved. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# =================================================================== + +__all__ = ['new', 'get_random_bytes'] + +from os import urandom + +class _UrandomRNG(object): + + def read(self, n): + """Return a random byte string of the desired size.""" + return urandom(n) + + def flush(self): + """Method provided for backward compatibility only.""" + pass + + def reinit(self): + """Method provided for backward compatibility only.""" + pass + + def close(self): + """Method provided for backward compatibility only.""" + pass + + +def new(*args, **kwargs): + """Return a file-like object that outputs cryptographically random bytes.""" + return _UrandomRNG() + + +def atfork(): + pass + + +#: Function that returns a random byte string of the desired size. +get_random_bytes = urandom + diff --git a/venv/Lib/site-packages/Cryptodome/Random/__init__.pyi b/venv/Lib/site-packages/Cryptodome/Random/__init__.pyi new file mode 100644 index 0000000..ddc5b9b --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Random/__init__.pyi @@ -0,0 +1,19 @@ +from typing import Any + +__all__ = ['new', 'get_random_bytes'] + +from os import urandom + +class _UrandomRNG(object): + + def read(self, n: int) -> bytes:... + def flush(self) -> None: ... + def reinit(self) -> None: ... + def close(self) -> None: ... + +def new(*args: Any, **kwargs: Any) -> _UrandomRNG: ... + +def atfork() -> None: ... + +get_random_bytes = urandom + diff --git a/venv/Lib/site-packages/Cryptodome/Random/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/Random/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000..87a1a08 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Random/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/Random/__pycache__/random.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/Random/__pycache__/random.cpython-312.pyc new file mode 100644 index 0000000..46b43ec Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Random/__pycache__/random.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/Random/random.py b/venv/Lib/site-packages/Cryptodome/Random/random.py new file mode 100644 index 0000000..da30795 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Random/random.py @@ -0,0 +1,138 @@ +# -*- coding: utf-8 -*- +# +# Random/random.py : Strong alternative for the standard 'random' module +# +# Written in 2008 by Dwayne C. Litzenberger +# +# =================================================================== +# The contents of this file are dedicated to the public domain. To +# the extent that dedication to the public domain is not available, +# everyone is granted a worldwide, perpetual, royalty-free, +# non-exclusive license to exercise all rights associated with the +# contents of this file for any purpose whatsoever. +# No rights are reserved. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# =================================================================== + +__all__ = ['StrongRandom', 'getrandbits', 'randrange', 'randint', 'choice', 'shuffle', 'sample'] + +from Cryptodome import Random + +from Cryptodome.Util.py3compat import is_native_int + +class StrongRandom(object): + def __init__(self, rng=None, randfunc=None): + if randfunc is None and rng is None: + self._randfunc = None + elif randfunc is not None and rng is None: + self._randfunc = randfunc + elif randfunc is None and rng is not None: + self._randfunc = rng.read + else: + raise ValueError("Cannot specify both 'rng' and 'randfunc'") + + def getrandbits(self, k): + """Return an integer with k random bits.""" + + if self._randfunc is None: + self._randfunc = Random.new().read + mask = (1 << k) - 1 + return mask & bytes_to_long(self._randfunc(ceil_div(k, 8))) + + def randrange(self, *args): + """randrange([start,] stop[, step]): + Return a randomly-selected element from range(start, stop, step).""" + if len(args) == 3: + (start, stop, step) = args + elif len(args) == 2: + (start, stop) = args + step = 1 + elif len(args) == 1: + (stop,) = args + start = 0 + step = 1 + else: + raise TypeError("randrange expected at most 3 arguments, got %d" % (len(args),)) + if (not is_native_int(start) or not is_native_int(stop) or not + is_native_int(step)): + raise TypeError("randrange requires integer arguments") + if step == 0: + raise ValueError("randrange step argument must not be zero") + + num_choices = ceil_div(stop - start, step) + if num_choices < 0: + num_choices = 0 + if num_choices < 1: + raise ValueError("empty range for randrange(%r, %r, %r)" % (start, stop, step)) + + # Pick a random number in the range of possible numbers + r = num_choices + while r >= num_choices: + r = self.getrandbits(size(num_choices)) + + return start + (step * r) + + def randint(self, a, b): + """Return a random integer N such that a <= N <= b.""" + if not is_native_int(a) or not is_native_int(b): + raise TypeError("randint requires integer arguments") + N = self.randrange(a, b+1) + assert a <= N <= b + return N + + def choice(self, seq): + """Return a random element from a (non-empty) sequence. + + If the seqence is empty, raises IndexError. + """ + if len(seq) == 0: + raise IndexError("empty sequence") + return seq[self.randrange(len(seq))] + + def shuffle(self, x): + """Shuffle the sequence in place.""" + # Fisher-Yates shuffle. O(n) + # See http://en.wikipedia.org/wiki/Fisher-Yates_shuffle + # Working backwards from the end of the array, we choose a random item + # from the remaining items until all items have been chosen. + for i in range(len(x)-1, 0, -1): # iterate from len(x)-1 downto 1 + j = self.randrange(0, i+1) # choose random j such that 0 <= j <= i + x[i], x[j] = x[j], x[i] # exchange x[i] and x[j] + + def sample(self, population, k): + """Return a k-length list of unique elements chosen from the population sequence.""" + + num_choices = len(population) + if k > num_choices: + raise ValueError("sample larger than population") + + retval = [] + selected = {} # we emulate a set using a dict here + for i in range(k): + r = None + while r is None or r in selected: + r = self.randrange(num_choices) + retval.append(population[r]) + selected[r] = 1 + return retval + +_r = StrongRandom() +getrandbits = _r.getrandbits +randrange = _r.randrange +randint = _r.randint +choice = _r.choice +shuffle = _r.shuffle +sample = _r.sample + +# These are at the bottom to avoid problems with recursive imports +from Cryptodome.Util.number import ceil_div, bytes_to_long, long_to_bytes, size + +# vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/venv/Lib/site-packages/Cryptodome/Random/random.pyi b/venv/Lib/site-packages/Cryptodome/Random/random.pyi new file mode 100644 index 0000000..9b7cf7e --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Random/random.pyi @@ -0,0 +1,22 @@ +from typing import Callable, Tuple, Union, Sequence, Any, Optional, TypeVar + +__all__ = ['StrongRandom', 'getrandbits', 'randrange', 'randint', 'choice', 'shuffle', 'sample'] + +T = TypeVar('T') + +class StrongRandom(object): + def __init__(self, rng: Optional[Any]=None, randfunc: Optional[Callable]=None) -> None: ... # TODO What is rng? + def getrandbits(self, k: int) -> int: ... + def randrange(self, start: int, stop: int = ..., step: int = ...) -> int: ... + def randint(self, a: int, b: int) -> int: ... + def choice(self, seq: Sequence[T]) -> T: ... + def shuffle(self, x: Sequence) -> None: ... + def sample(self, population: Sequence, k: int) -> list: ... + +_r = StrongRandom() +getrandbits = _r.getrandbits +randrange = _r.randrange +randint = _r.randint +choice = _r.choice +shuffle = _r.shuffle +sample = _r.sample diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/__init__.py b/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/__init__.py new file mode 100644 index 0000000..40f865d --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/__init__.py @@ -0,0 +1,64 @@ +# -*- coding: utf-8 -*- +# +# SelfTest/Cipher/__init__.py: Self-test for cipher modules +# +# Written in 2008 by Dwayne C. Litzenberger +# +# =================================================================== +# The contents of this file are dedicated to the public domain. To +# the extent that dedication to the public domain is not available, +# everyone is granted a worldwide, perpetual, royalty-free, +# non-exclusive license to exercise all rights associated with the +# contents of this file for any purpose whatsoever. +# No rights are reserved. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# =================================================================== + +"""Self-test for cipher modules""" + +import sys + + +def get_tests(config={}): + tests = [] + from Cryptodome.SelfTest.Cipher import test_AES; tests += test_AES.get_tests(config=config) + from Cryptodome.SelfTest.Cipher import test_ARC2; tests += test_ARC2.get_tests(config=config) + from Cryptodome.SelfTest.Cipher import test_ARC4; tests += test_ARC4.get_tests(config=config) + from Cryptodome.SelfTest.Cipher import test_Blowfish; tests += test_Blowfish.get_tests(config=config) + from Cryptodome.SelfTest.Cipher import test_CAST; tests += test_CAST.get_tests(config=config) + from Cryptodome.SelfTest.Cipher import test_DES3; tests += test_DES3.get_tests(config=config) + from Cryptodome.SelfTest.Cipher import test_DES; tests += test_DES.get_tests(config=config) + from Cryptodome.SelfTest.Cipher import test_Salsa20; tests += test_Salsa20.get_tests(config=config) + from Cryptodome.SelfTest.Cipher import test_ChaCha20; tests += test_ChaCha20.get_tests(config=config) + from Cryptodome.SelfTest.Cipher import test_ChaCha20_Poly1305; tests += test_ChaCha20_Poly1305.get_tests(config=config) + from Cryptodome.SelfTest.Cipher import test_pkcs1_15; tests += test_pkcs1_15.get_tests(config=config) + from Cryptodome.SelfTest.Cipher import test_pkcs1_oaep; tests += test_pkcs1_oaep.get_tests(config=config) + from Cryptodome.SelfTest.Cipher import test_OCB; tests += test_OCB.get_tests(config=config) + from Cryptodome.SelfTest.Cipher import test_CBC; tests += test_CBC.get_tests(config=config) + from Cryptodome.SelfTest.Cipher import test_CFB; tests += test_CFB.get_tests(config=config) + from Cryptodome.SelfTest.Cipher import test_OpenPGP; tests += test_OpenPGP.get_tests(config=config) + from Cryptodome.SelfTest.Cipher import test_OFB; tests += test_OFB.get_tests(config=config) + from Cryptodome.SelfTest.Cipher import test_CTR; tests += test_CTR.get_tests(config=config) + from Cryptodome.SelfTest.Cipher import test_CCM; tests += test_CCM.get_tests(config=config) + from Cryptodome.SelfTest.Cipher import test_EAX; tests += test_EAX.get_tests(config=config) + from Cryptodome.SelfTest.Cipher import test_GCM; tests += test_GCM.get_tests(config=config) + from Cryptodome.SelfTest.Cipher import test_SIV; tests += test_SIV.get_tests(config=config) + + if sys.version_info >= (3, 9): + from Cryptodome.SelfTest.Cipher import test_KW + tests += test_KW.get_tests(config=config) + + return tests + +if __name__ == '__main__': + import unittest + suite = lambda: unittest.TestSuite(get_tests()) + unittest.main(defaultTest='suite') diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000..7cd33e0 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/__pycache__/common.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/__pycache__/common.cpython-312.pyc new file mode 100644 index 0000000..580c8cd Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/__pycache__/common.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/__pycache__/test_AES.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/__pycache__/test_AES.cpython-312.pyc new file mode 100644 index 0000000..d171b6f Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/__pycache__/test_AES.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/__pycache__/test_ARC2.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/__pycache__/test_ARC2.cpython-312.pyc new file mode 100644 index 0000000..885e559 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/__pycache__/test_ARC2.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/__pycache__/test_ARC4.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/__pycache__/test_ARC4.cpython-312.pyc new file mode 100644 index 0000000..222aaa8 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/__pycache__/test_ARC4.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/__pycache__/test_Blowfish.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/__pycache__/test_Blowfish.cpython-312.pyc new file mode 100644 index 0000000..bb09118 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/__pycache__/test_Blowfish.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/__pycache__/test_CAST.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/__pycache__/test_CAST.cpython-312.pyc new file mode 100644 index 0000000..b2c4dae Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/__pycache__/test_CAST.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/__pycache__/test_CBC.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/__pycache__/test_CBC.cpython-312.pyc new file mode 100644 index 0000000..3bb799f Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/__pycache__/test_CBC.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/__pycache__/test_CCM.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/__pycache__/test_CCM.cpython-312.pyc new file mode 100644 index 0000000..969a27f Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/__pycache__/test_CCM.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/__pycache__/test_CFB.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/__pycache__/test_CFB.cpython-312.pyc new file mode 100644 index 0000000..2883938 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/__pycache__/test_CFB.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/__pycache__/test_CTR.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/__pycache__/test_CTR.cpython-312.pyc new file mode 100644 index 0000000..adaa2b5 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/__pycache__/test_CTR.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/__pycache__/test_ChaCha20.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/__pycache__/test_ChaCha20.cpython-312.pyc new file mode 100644 index 0000000..9b00a43 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/__pycache__/test_ChaCha20.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/__pycache__/test_ChaCha20_Poly1305.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/__pycache__/test_ChaCha20_Poly1305.cpython-312.pyc new file mode 100644 index 0000000..7685985 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/__pycache__/test_ChaCha20_Poly1305.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/__pycache__/test_DES.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/__pycache__/test_DES.cpython-312.pyc new file mode 100644 index 0000000..3b2e109 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/__pycache__/test_DES.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/__pycache__/test_DES3.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/__pycache__/test_DES3.cpython-312.pyc new file mode 100644 index 0000000..400b745 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/__pycache__/test_DES3.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/__pycache__/test_EAX.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/__pycache__/test_EAX.cpython-312.pyc new file mode 100644 index 0000000..4832bf8 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/__pycache__/test_EAX.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/__pycache__/test_GCM.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/__pycache__/test_GCM.cpython-312.pyc new file mode 100644 index 0000000..53d562b Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/__pycache__/test_GCM.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/__pycache__/test_KW.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/__pycache__/test_KW.cpython-312.pyc new file mode 100644 index 0000000..ad9bf34 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/__pycache__/test_KW.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/__pycache__/test_OCB.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/__pycache__/test_OCB.cpython-312.pyc new file mode 100644 index 0000000..a6a10d7 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/__pycache__/test_OCB.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/__pycache__/test_OFB.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/__pycache__/test_OFB.cpython-312.pyc new file mode 100644 index 0000000..26c24ff Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/__pycache__/test_OFB.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/__pycache__/test_OpenPGP.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/__pycache__/test_OpenPGP.cpython-312.pyc new file mode 100644 index 0000000..fa64dfd Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/__pycache__/test_OpenPGP.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/__pycache__/test_SIV.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/__pycache__/test_SIV.cpython-312.pyc new file mode 100644 index 0000000..fbf78b0 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/__pycache__/test_SIV.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/__pycache__/test_Salsa20.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/__pycache__/test_Salsa20.cpython-312.pyc new file mode 100644 index 0000000..21a297a Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/__pycache__/test_Salsa20.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/__pycache__/test_pkcs1_15.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/__pycache__/test_pkcs1_15.cpython-312.pyc new file mode 100644 index 0000000..6b2e5eb Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/__pycache__/test_pkcs1_15.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/__pycache__/test_pkcs1_oaep.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/__pycache__/test_pkcs1_oaep.cpython-312.pyc new file mode 100644 index 0000000..c2054c8 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/__pycache__/test_pkcs1_oaep.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/common.py b/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/common.py new file mode 100644 index 0000000..a13d4fb --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/common.py @@ -0,0 +1,510 @@ +# -*- coding: utf-8 -*- +# +# SelfTest/Hash/common.py: Common code for Cryptodome.SelfTest.Hash +# +# Written in 2008 by Dwayne C. Litzenberger +# +# =================================================================== +# The contents of this file are dedicated to the public domain. To +# the extent that dedication to the public domain is not available, +# everyone is granted a worldwide, perpetual, royalty-free, +# non-exclusive license to exercise all rights associated with the +# contents of this file for any purpose whatsoever. +# No rights are reserved. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# =================================================================== + +"""Self-testing for PyCryptodome hash modules""" + +import unittest +from binascii import a2b_hex, b2a_hex, hexlify + +from Cryptodome.Util.py3compat import b +from Cryptodome.Util.strxor import strxor_c + +class _NoDefault: pass # sentinel object +def _extract(d, k, default=_NoDefault): + """Get an item from a dictionary, and remove it from the dictionary.""" + try: + retval = d[k] + except KeyError: + if default is _NoDefault: + raise + return default + del d[k] + return retval + +# Generic cipher test case +class CipherSelfTest(unittest.TestCase): + + def __init__(self, module, params): + unittest.TestCase.__init__(self) + self.module = module + + # Extract the parameters + params = params.copy() + self.description = _extract(params, 'description') + self.key = b(_extract(params, 'key')) + self.plaintext = b(_extract(params, 'plaintext')) + self.ciphertext = b(_extract(params, 'ciphertext')) + self.module_name = _extract(params, 'module_name', None) + self.assoc_data = _extract(params, 'assoc_data', None) + self.mac = _extract(params, 'mac', None) + if self.assoc_data: + self.mac = b(self.mac) + + mode = _extract(params, 'mode', None) + self.mode_name = str(mode) + + if mode is not None: + # Block cipher + self.mode = getattr(self.module, "MODE_" + mode) + + self.iv = _extract(params, 'iv', None) + if self.iv is None: + self.iv = _extract(params, 'nonce', None) + if self.iv is not None: + self.iv = b(self.iv) + + else: + # Stream cipher + self.mode = None + self.iv = _extract(params, 'iv', None) + if self.iv is not None: + self.iv = b(self.iv) + + self.extra_params = params + + def shortDescription(self): + return self.description + + def _new(self): + params = self.extra_params.copy() + key = a2b_hex(self.key) + + old_style = [] + if self.mode is not None: + old_style = [ self.mode ] + if self.iv is not None: + old_style += [ a2b_hex(self.iv) ] + + return self.module.new(key, *old_style, **params) + + def isMode(self, name): + if not hasattr(self.module, "MODE_"+name): + return False + return self.mode == getattr(self.module, "MODE_"+name) + + def runTest(self): + plaintext = a2b_hex(self.plaintext) + ciphertext = a2b_hex(self.ciphertext) + assoc_data = [] + if self.assoc_data: + assoc_data = [ a2b_hex(b(x)) for x in self.assoc_data] + + ct = None + pt = None + + # + # Repeat the same encryption or decryption twice and verify + # that the result is always the same + # + for i in range(2): + cipher = self._new() + decipher = self._new() + + # Only AEAD modes + for comp in assoc_data: + cipher.update(comp) + decipher.update(comp) + + ctX = b2a_hex(cipher.encrypt(plaintext)) + ptX = b2a_hex(decipher.decrypt(ciphertext)) + + if ct: + self.assertEqual(ct, ctX) + self.assertEqual(pt, ptX) + ct, pt = ctX, ptX + + self.assertEqual(self.ciphertext, ct) # encrypt + self.assertEqual(self.plaintext, pt) # decrypt + + if self.mac: + mac = b2a_hex(cipher.digest()) + self.assertEqual(self.mac, mac) + decipher.verify(a2b_hex(self.mac)) + +class CipherStreamingSelfTest(CipherSelfTest): + + def shortDescription(self): + desc = self.module_name + if self.mode is not None: + desc += " in %s mode" % (self.mode_name,) + return "%s should behave like a stream cipher" % (desc,) + + def runTest(self): + plaintext = a2b_hex(self.plaintext) + ciphertext = a2b_hex(self.ciphertext) + + # The cipher should work like a stream cipher + + # Test counter mode encryption, 3 bytes at a time + ct3 = [] + cipher = self._new() + for i in range(0, len(plaintext), 3): + ct3.append(cipher.encrypt(plaintext[i:i+3])) + ct3 = b2a_hex(b("").join(ct3)) + self.assertEqual(self.ciphertext, ct3) # encryption (3 bytes at a time) + + # Test counter mode decryption, 3 bytes at a time + pt3 = [] + cipher = self._new() + for i in range(0, len(ciphertext), 3): + pt3.append(cipher.encrypt(ciphertext[i:i+3])) + # PY3K: This is meant to be text, do not change to bytes (data) + pt3 = b2a_hex(b("").join(pt3)) + self.assertEqual(self.plaintext, pt3) # decryption (3 bytes at a time) + + +class RoundtripTest(unittest.TestCase): + def __init__(self, module, params): + from Cryptodome import Random + unittest.TestCase.__init__(self) + self.module = module + self.iv = Random.get_random_bytes(module.block_size) + self.key = b(params['key']) + self.plaintext = 100 * b(params['plaintext']) + self.module_name = params.get('module_name', None) + + def shortDescription(self): + return """%s .decrypt() output of .encrypt() should not be garbled""" % (self.module_name,) + + def runTest(self): + + ## ECB mode + mode = self.module.MODE_ECB + encryption_cipher = self.module.new(a2b_hex(self.key), mode) + ciphertext = encryption_cipher.encrypt(self.plaintext) + decryption_cipher = self.module.new(a2b_hex(self.key), mode) + decrypted_plaintext = decryption_cipher.decrypt(ciphertext) + self.assertEqual(self.plaintext, decrypted_plaintext) + + +class IVLengthTest(unittest.TestCase): + def __init__(self, module, params): + unittest.TestCase.__init__(self) + self.module = module + self.key = b(params['key']) + + def shortDescription(self): + return "Check that all modes except MODE_ECB and MODE_CTR require an IV of the proper length" + + def runTest(self): + self.assertRaises(TypeError, self.module.new, a2b_hex(self.key), + self.module.MODE_ECB, b("")) + + def _dummy_counter(self): + return "\0" * self.module.block_size + + +class NoDefaultECBTest(unittest.TestCase): + def __init__(self, module, params): + unittest.TestCase.__init__(self) + self.module = module + self.key = b(params['key']) + + def runTest(self): + self.assertRaises(TypeError, self.module.new, a2b_hex(self.key)) + + +class BlockSizeTest(unittest.TestCase): + def __init__(self, module, params): + unittest.TestCase.__init__(self) + self.module = module + self.key = a2b_hex(b(params['key'])) + + def runTest(self): + cipher = self.module.new(self.key, self.module.MODE_ECB) + self.assertEqual(cipher.block_size, self.module.block_size) + + +class ByteArrayTest(unittest.TestCase): + """Verify we can use bytearray's for encrypting and decrypting""" + + def __init__(self, module, params): + unittest.TestCase.__init__(self) + self.module = module + + # Extract the parameters + params = params.copy() + self.description = _extract(params, 'description') + self.key = b(_extract(params, 'key')) + self.plaintext = b(_extract(params, 'plaintext')) + self.ciphertext = b(_extract(params, 'ciphertext')) + self.module_name = _extract(params, 'module_name', None) + self.assoc_data = _extract(params, 'assoc_data', None) + self.mac = _extract(params, 'mac', None) + if self.assoc_data: + self.mac = b(self.mac) + + mode = _extract(params, 'mode', None) + self.mode_name = str(mode) + + if mode is not None: + # Block cipher + self.mode = getattr(self.module, "MODE_" + mode) + + self.iv = _extract(params, 'iv', None) + if self.iv is None: + self.iv = _extract(params, 'nonce', None) + if self.iv is not None: + self.iv = b(self.iv) + else: + # Stream cipher + self.mode = None + self.iv = _extract(params, 'iv', None) + if self.iv is not None: + self.iv = b(self.iv) + + self.extra_params = params + + def _new(self): + params = self.extra_params.copy() + key = a2b_hex(self.key) + + old_style = [] + if self.mode is not None: + old_style = [ self.mode ] + if self.iv is not None: + old_style += [ a2b_hex(self.iv) ] + + return self.module.new(key, *old_style, **params) + + def runTest(self): + + plaintext = a2b_hex(self.plaintext) + ciphertext = a2b_hex(self.ciphertext) + assoc_data = [] + if self.assoc_data: + assoc_data = [ bytearray(a2b_hex(b(x))) for x in self.assoc_data] + + cipher = self._new() + decipher = self._new() + + # Only AEAD modes + for comp in assoc_data: + cipher.update(comp) + decipher.update(comp) + + ct = b2a_hex(cipher.encrypt(bytearray(plaintext))) + pt = b2a_hex(decipher.decrypt(bytearray(ciphertext))) + + self.assertEqual(self.ciphertext, ct) # encrypt + self.assertEqual(self.plaintext, pt) # decrypt + + if self.mac: + mac = b2a_hex(cipher.digest()) + self.assertEqual(self.mac, mac) + decipher.verify(bytearray(a2b_hex(self.mac))) + + +class MemoryviewTest(unittest.TestCase): + """Verify we can use memoryviews for encrypting and decrypting""" + + def __init__(self, module, params): + unittest.TestCase.__init__(self) + self.module = module + + # Extract the parameters + params = params.copy() + self.description = _extract(params, 'description') + self.key = b(_extract(params, 'key')) + self.plaintext = b(_extract(params, 'plaintext')) + self.ciphertext = b(_extract(params, 'ciphertext')) + self.module_name = _extract(params, 'module_name', None) + self.assoc_data = _extract(params, 'assoc_data', None) + self.mac = _extract(params, 'mac', None) + if self.assoc_data: + self.mac = b(self.mac) + + mode = _extract(params, 'mode', None) + self.mode_name = str(mode) + + if mode is not None: + # Block cipher + self.mode = getattr(self.module, "MODE_" + mode) + + self.iv = _extract(params, 'iv', None) + if self.iv is None: + self.iv = _extract(params, 'nonce', None) + if self.iv is not None: + self.iv = b(self.iv) + else: + # Stream cipher + self.mode = None + self.iv = _extract(params, 'iv', None) + if self.iv is not None: + self.iv = b(self.iv) + + self.extra_params = params + + def _new(self): + params = self.extra_params.copy() + key = a2b_hex(self.key) + + old_style = [] + if self.mode is not None: + old_style = [ self.mode ] + if self.iv is not None: + old_style += [ a2b_hex(self.iv) ] + + return self.module.new(key, *old_style, **params) + + def runTest(self): + + plaintext = a2b_hex(self.plaintext) + ciphertext = a2b_hex(self.ciphertext) + assoc_data = [] + if self.assoc_data: + assoc_data = [ memoryview(a2b_hex(b(x))) for x in self.assoc_data] + + cipher = self._new() + decipher = self._new() + + # Only AEAD modes + for comp in assoc_data: + cipher.update(comp) + decipher.update(comp) + + ct = b2a_hex(cipher.encrypt(memoryview(plaintext))) + pt = b2a_hex(decipher.decrypt(memoryview(ciphertext))) + + self.assertEqual(self.ciphertext, ct) # encrypt + self.assertEqual(self.plaintext, pt) # decrypt + + if self.mac: + mac = b2a_hex(cipher.digest()) + self.assertEqual(self.mac, mac) + decipher.verify(memoryview(a2b_hex(self.mac))) + + +def make_block_tests(module, module_name, test_data, additional_params=dict()): + tests = [] + extra_tests_added = False + for i in range(len(test_data)): + row = test_data[i] + + # Build the "params" dictionary with + # - plaintext + # - ciphertext + # - key + # - mode (default is ECB) + # - (optionally) description + # - (optionally) any other parameter that this cipher mode requires + params = {} + if len(row) == 3: + (params['plaintext'], params['ciphertext'], params['key']) = row + elif len(row) == 4: + (params['plaintext'], params['ciphertext'], params['key'], params['description']) = row + elif len(row) == 5: + (params['plaintext'], params['ciphertext'], params['key'], params['description'], extra_params) = row + params.update(extra_params) + else: + raise AssertionError("Unsupported tuple size %d" % (len(row),)) + + if not "mode" in params: + params["mode"] = "ECB" + + # Build the display-name for the test + p2 = params.copy() + p_key = _extract(p2, 'key') + p_plaintext = _extract(p2, 'plaintext') + p_ciphertext = _extract(p2, 'ciphertext') + p_mode = _extract(p2, 'mode') + p_description = _extract(p2, 'description', None) + + if p_description is not None: + description = p_description + elif p_mode == 'ECB' and not p2: + description = "p=%s, k=%s" % (p_plaintext, p_key) + else: + description = "p=%s, k=%s, %r" % (p_plaintext, p_key, p2) + name = "%s #%d: %s" % (module_name, i+1, description) + params['description'] = name + params['module_name'] = module_name + params.update(additional_params) + + # Add extra test(s) to the test suite before the current test + if not extra_tests_added: + tests += [ + RoundtripTest(module, params), + IVLengthTest(module, params), + NoDefaultECBTest(module, params), + ByteArrayTest(module, params), + BlockSizeTest(module, params), + ] + extra_tests_added = True + + # Add the current test to the test suite + tests.append(CipherSelfTest(module, params)) + + return tests + +def make_stream_tests(module, module_name, test_data): + tests = [] + extra_tests_added = False + for i in range(len(test_data)): + row = test_data[i] + + # Build the "params" dictionary + params = {} + if len(row) == 3: + (params['plaintext'], params['ciphertext'], params['key']) = row + elif len(row) == 4: + (params['plaintext'], params['ciphertext'], params['key'], params['description']) = row + elif len(row) == 5: + (params['plaintext'], params['ciphertext'], params['key'], params['description'], extra_params) = row + params.update(extra_params) + else: + raise AssertionError("Unsupported tuple size %d" % (len(row),)) + + # Build the display-name for the test + p2 = params.copy() + p_key = _extract(p2, 'key') + p_plaintext = _extract(p2, 'plaintext') + p_ciphertext = _extract(p2, 'ciphertext') + p_description = _extract(p2, 'description', None) + + if p_description is not None: + description = p_description + elif not p2: + description = "p=%s, k=%s" % (p_plaintext, p_key) + else: + description = "p=%s, k=%s, %r" % (p_plaintext, p_key, p2) + name = "%s #%d: %s" % (module_name, i+1, description) + params['description'] = name + params['module_name'] = module_name + + # Add extra test(s) to the test suite before the current test + if not extra_tests_added: + tests += [ + ByteArrayTest(module, params), + ] + + tests.append(MemoryviewTest(module, params)) + extra_tests_added = True + + # Add the test to the test suite + tests.append(CipherSelfTest(module, params)) + tests.append(CipherStreamingSelfTest(module, params)) + return tests + +# vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/test_AES.py b/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/test_AES.py new file mode 100644 index 0000000..bd6c40e --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/test_AES.py @@ -0,0 +1,1351 @@ +# -*- coding: utf-8 -*- +# +# SelfTest/Cipher/AES.py: Self-test for the AES cipher +# +# Written in 2008 by Dwayne C. Litzenberger +# +# =================================================================== +# The contents of this file are dedicated to the public domain. To +# the extent that dedication to the public domain is not available, +# everyone is granted a worldwide, perpetual, royalty-free, +# non-exclusive license to exercise all rights associated with the +# contents of this file for any purpose whatsoever. +# No rights are reserved. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# =================================================================== + +"""Self-test suite for Cryptodome.Cipher.AES""" + +from __future__ import print_function + +import unittest +from Cryptodome.Hash import SHA256 +from Cryptodome.Cipher import AES +from Cryptodome.Util.py3compat import * +from binascii import hexlify + +# This is a list of (plaintext, ciphertext, key[, description[, params]]) tuples. +test_data = [ + # FIPS PUB 197 test vectors + # http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf + + ('00112233445566778899aabbccddeeff', '69c4e0d86a7b0430d8cdb78070b4c55a', + '000102030405060708090a0b0c0d0e0f', 'FIPS 197 C.1 (AES-128)'), + + ('00112233445566778899aabbccddeeff', 'dda97ca4864cdfe06eaf70a0ec0d7191', + '000102030405060708090a0b0c0d0e0f1011121314151617', + 'FIPS 197 C.2 (AES-192)'), + + ('00112233445566778899aabbccddeeff', '8ea2b7ca516745bfeafc49904b496089', + '000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f', + 'FIPS 197 C.3 (AES-256)'), + + # Rijndael128 test vectors + # Downloaded 2008-09-13 from + # http://www.iaik.tugraz.at/Research/krypto/AES/old/~rijmen/rijndael/testvalues.tar.gz + + # ecb_tbl.txt, KEYSIZE=128 + ('506812a45f08c889b97f5980038b8359', 'd8f532538289ef7d06b506a4fd5be9c9', + '00010203050607080a0b0c0d0f101112', + 'ecb-tbl-128: I=1'), + ('5c6d71ca30de8b8b00549984d2ec7d4b', '59ab30f4d4ee6e4ff9907ef65b1fb68c', + '14151617191a1b1c1e1f202123242526', + 'ecb-tbl-128: I=2'), + ('53f3f4c64f8616e4e7c56199f48f21f6', 'bf1ed2fcb2af3fd41443b56d85025cb1', + '28292a2b2d2e2f30323334353738393a', + 'ecb-tbl-128: I=3'), + ('a1eb65a3487165fb0f1c27ff9959f703', '7316632d5c32233edcb0780560eae8b2', + '3c3d3e3f41424344464748494b4c4d4e', + 'ecb-tbl-128: I=4'), + ('3553ecf0b1739558b08e350a98a39bfa', '408c073e3e2538072b72625e68b8364b', + '50515253555657585a5b5c5d5f606162', + 'ecb-tbl-128: I=5'), + ('67429969490b9711ae2b01dc497afde8', 'e1f94dfa776597beaca262f2f6366fea', + '64656667696a6b6c6e6f707173747576', + 'ecb-tbl-128: I=6'), + ('93385c1f2aec8bed192f5a8e161dd508', 'f29e986c6a1c27d7b29ffd7ee92b75f1', + '78797a7b7d7e7f80828384858788898a', + 'ecb-tbl-128: I=7'), + ('b5bf946be19beb8db3983b5f4c6e8ddb', '131c886a57f8c2e713aba6955e2b55b5', + '8c8d8e8f91929394969798999b9c9d9e', + 'ecb-tbl-128: I=8'), + ('41321ee10e21bd907227c4450ff42324', 'd2ab7662df9b8c740210e5eeb61c199d', + 'a0a1a2a3a5a6a7a8aaabacadafb0b1b2', + 'ecb-tbl-128: I=9'), + ('00a82f59c91c8486d12c0a80124f6089', '14c10554b2859c484cab5869bbe7c470', + 'b4b5b6b7b9babbbcbebfc0c1c3c4c5c6', + 'ecb-tbl-128: I=10'), + ('7ce0fd076754691b4bbd9faf8a1372fe', 'db4d498f0a49cf55445d502c1f9ab3b5', + 'c8c9cacbcdcecfd0d2d3d4d5d7d8d9da', + 'ecb-tbl-128: I=11'), + ('23605a8243d07764541bc5ad355b3129', '6d96fef7d66590a77a77bb2056667f7f', + 'dcdddedfe1e2e3e4e6e7e8e9ebecedee', + 'ecb-tbl-128: I=12'), + ('12a8cfa23ea764fd876232b4e842bc44', '316fb68edba736c53e78477bf913725c', + 'f0f1f2f3f5f6f7f8fafbfcfdfe010002', + 'ecb-tbl-128: I=13'), + ('bcaf32415e8308b3723e5fdd853ccc80', '6936f2b93af8397fd3a771fc011c8c37', + '04050607090a0b0c0e0f101113141516', + 'ecb-tbl-128: I=14'), + ('89afae685d801ad747ace91fc49adde0', 'f3f92f7a9c59179c1fcc2c2ba0b082cd', + '2c2d2e2f31323334363738393b3c3d3e', + 'ecb-tbl-128: I=15'), + ('f521d07b484357c4a69e76124a634216', '6a95ea659ee3889158e7a9152ff04ebc', + '40414243454647484a4b4c4d4f505152', + 'ecb-tbl-128: I=16'), + ('3e23b3bc065bcc152407e23896d77783', '1959338344e945670678a5d432c90b93', + '54555657595a5b5c5e5f606163646566', + 'ecb-tbl-128: I=17'), + ('79f0fba002be1744670e7e99290d8f52', 'e49bddd2369b83ee66e6c75a1161b394', + '68696a6b6d6e6f70727374757778797a', + 'ecb-tbl-128: I=18'), + ('da23fe9d5bd63e1d72e3dafbe21a6c2a', 'd3388f19057ff704b70784164a74867d', + '7c7d7e7f81828384868788898b8c8d8e', + 'ecb-tbl-128: I=19'), + ('e3f5698ba90b6a022efd7db2c7e6c823', '23aa03e2d5e4cd24f3217e596480d1e1', + 'a4a5a6a7a9aaabacaeafb0b1b3b4b5b6', + 'ecb-tbl-128: I=20'), + ('bdc2691d4f1b73d2700679c3bcbf9c6e', 'c84113d68b666ab2a50a8bdb222e91b9', + 'e0e1e2e3e5e6e7e8eaebecedeff0f1f2', + 'ecb-tbl-128: I=21'), + ('ba74e02093217ee1ba1b42bd5624349a', 'ac02403981cd4340b507963db65cb7b6', + '08090a0b0d0e0f10121314151718191a', + 'ecb-tbl-128: I=22'), + ('b5c593b5851c57fbf8b3f57715e8f680', '8d1299236223359474011f6bf5088414', + '6c6d6e6f71727374767778797b7c7d7e', + 'ecb-tbl-128: I=23'), + ('3da9bd9cec072381788f9387c3bbf4ee', '5a1d6ab8605505f7977e55b9a54d9b90', + '80818283858687888a8b8c8d8f909192', + 'ecb-tbl-128: I=24'), + ('4197f3051121702ab65d316b3c637374', '72e9c2d519cf555e4208805aabe3b258', + '94959697999a9b9c9e9fa0a1a3a4a5a6', + 'ecb-tbl-128: I=25'), + ('9f46c62ec4f6ee3f6e8c62554bc48ab7', 'a8f3e81c4a23a39ef4d745dffe026e80', + 'a8a9aaabadaeafb0b2b3b4b5b7b8b9ba', + 'ecb-tbl-128: I=26'), + ('0220673fe9e699a4ebc8e0dbeb6979c8', '546f646449d31458f9eb4ef5483aee6c', + 'bcbdbebfc1c2c3c4c6c7c8c9cbcccdce', + 'ecb-tbl-128: I=27'), + ('b2b99171337ded9bc8c2c23ff6f18867', '4dbe4bc84ac797c0ee4efb7f1a07401c', + 'd0d1d2d3d5d6d7d8dadbdcdddfe0e1e2', + 'ecb-tbl-128: I=28'), + ('a7facf4e301e984e5efeefd645b23505', '25e10bfb411bbd4d625ac8795c8ca3b3', + 'e4e5e6e7e9eaebeceeeff0f1f3f4f5f6', + 'ecb-tbl-128: I=29'), + ('f7c762e4a9819160fd7acfb6c4eedcdd', '315637405054ec803614e43def177579', + 'f8f9fafbfdfefe00020304050708090a', + 'ecb-tbl-128: I=30'), + ('9b64fc21ea08709f4915436faa70f1be', '60c5bc8a1410247295c6386c59e572a8', + '0c0d0e0f11121314161718191b1c1d1e', + 'ecb-tbl-128: I=31'), + ('52af2c3de07ee6777f55a4abfc100b3f', '01366fc8ca52dfe055d6a00a76471ba6', + '20212223252627282a2b2c2d2f303132', + 'ecb-tbl-128: I=32'), + ('2fca001224386c57aa3f968cbe2c816f', 'ecc46595516ec612449c3f581e7d42ff', + '34353637393a3b3c3e3f404143444546', + 'ecb-tbl-128: I=33'), + ('4149c73658a4a9c564342755ee2c132f', '6b7ffe4c602a154b06ee9c7dab5331c9', + '48494a4b4d4e4f50525354555758595a', + 'ecb-tbl-128: I=34'), + ('af60005a00a1772f7c07a48a923c23d2', '7da234c14039a240dd02dd0fbf84eb67', + '5c5d5e5f61626364666768696b6c6d6e', + 'ecb-tbl-128: I=35'), + ('6fccbc28363759914b6f0280afaf20c6', 'c7dc217d9e3604ffe7e91f080ecd5a3a', + '70717273757677787a7b7c7d7f808182', + 'ecb-tbl-128: I=36'), + ('7d82a43ddf4fefa2fc5947499884d386', '37785901863f5c81260ea41e7580cda5', + '84858687898a8b8c8e8f909193949596', + 'ecb-tbl-128: I=37'), + ('5d5a990eaab9093afe4ce254dfa49ef9', 'a07b9338e92ed105e6ad720fccce9fe4', + '98999a9b9d9e9fa0a2a3a4a5a7a8a9aa', + 'ecb-tbl-128: I=38'), + ('4cd1e2fd3f4434b553aae453f0ed1a02', 'ae0fb9722418cc21a7da816bbc61322c', + 'acadaeafb1b2b3b4b6b7b8b9bbbcbdbe', + 'ecb-tbl-128: I=39'), + ('5a2c9a9641d4299125fa1b9363104b5e', 'c826a193080ff91ffb21f71d3373c877', + 'c0c1c2c3c5c6c7c8cacbcccdcfd0d1d2', + 'ecb-tbl-128: I=40'), + ('b517fe34c0fa217d341740bfd4fe8dd4', '1181b11b0e494e8d8b0aa6b1d5ac2c48', + 'd4d5d6d7d9dadbdcdedfe0e1e3e4e5e6', + 'ecb-tbl-128: I=41'), + ('014baf2278a69d331d5180103643e99a', '6743c3d1519ab4f2cd9a78ab09a511bd', + 'e8e9eaebedeeeff0f2f3f4f5f7f8f9fa', + 'ecb-tbl-128: I=42'), + ('b529bd8164f20d0aa443d4932116841c', 'dc55c076d52bacdf2eefd952946a439d', + 'fcfdfeff01020304060708090b0c0d0e', + 'ecb-tbl-128: I=43'), + ('2e596dcbb2f33d4216a1176d5bd1e456', '711b17b590ffc72b5c8e342b601e8003', + '10111213151617181a1b1c1d1f202122', + 'ecb-tbl-128: I=44'), + ('7274a1ea2b7ee2424e9a0e4673689143', '19983bb0950783a537e1339f4aa21c75', + '24252627292a2b2c2e2f303133343536', + 'ecb-tbl-128: I=45'), + ('ae20020bd4f13e9d90140bee3b5d26af', '3ba7762e15554169c0f4fa39164c410c', + '38393a3b3d3e3f40424344454748494a', + 'ecb-tbl-128: I=46'), + ('baac065da7ac26e855e79c8849d75a02', 'a0564c41245afca7af8aa2e0e588ea89', + '4c4d4e4f51525354565758595b5c5d5e', + 'ecb-tbl-128: I=47'), + ('7c917d8d1d45fab9e2540e28832540cc', '5e36a42a2e099f54ae85ecd92e2381ed', + '60616263656667686a6b6c6d6f707172', + 'ecb-tbl-128: I=48'), + ('bde6f89e16daadb0e847a2a614566a91', '770036f878cd0f6ca2268172f106f2fe', + '74757677797a7b7c7e7f808183848586', + 'ecb-tbl-128: I=49'), + ('c9de163725f1f5be44ebb1db51d07fbc', '7e4e03908b716116443ccf7c94e7c259', + '88898a8b8d8e8f90929394959798999a', + 'ecb-tbl-128: I=50'), + ('3af57a58f0c07dffa669572b521e2b92', '482735a48c30613a242dd494c7f9185d', + '9c9d9e9fa1a2a3a4a6a7a8a9abacadae', + 'ecb-tbl-128: I=51'), + ('3d5ebac306dde4604f1b4fbbbfcdae55', 'b4c0f6c9d4d7079addf9369fc081061d', + 'b0b1b2b3b5b6b7b8babbbcbdbfc0c1c2', + 'ecb-tbl-128: I=52'), + ('c2dfa91bceb76a1183c995020ac0b556', 'd5810fe0509ac53edcd74f89962e6270', + 'c4c5c6c7c9cacbcccecfd0d1d3d4d5d6', + 'ecb-tbl-128: I=53'), + ('c70f54305885e9a0746d01ec56c8596b', '03f17a16b3f91848269ecdd38ebb2165', + 'd8d9dadbdddedfe0e2e3e4e5e7e8e9ea', + 'ecb-tbl-128: I=54'), + ('c4f81b610e98012ce000182050c0c2b2', 'da1248c3180348bad4a93b4d9856c9df', + 'ecedeeeff1f2f3f4f6f7f8f9fbfcfdfe', + 'ecb-tbl-128: I=55'), + ('eaab86b1d02a95d7404eff67489f97d4', '3d10d7b63f3452c06cdf6cce18be0c2c', + '00010203050607080a0b0c0d0f101112', + 'ecb-tbl-128: I=56'), + ('7c55bdb40b88870b52bec3738de82886', '4ab823e7477dfddc0e6789018fcb6258', + '14151617191a1b1c1e1f202123242526', + 'ecb-tbl-128: I=57'), + ('ba6eaa88371ff0a3bd875e3f2a975ce0', 'e6478ba56a77e70cfdaa5c843abde30e', + '28292a2b2d2e2f30323334353738393a', + 'ecb-tbl-128: I=58'), + ('08059130c4c24bd30cf0575e4e0373dc', '1673064895fbeaf7f09c5429ff75772d', + '3c3d3e3f41424344464748494b4c4d4e', + 'ecb-tbl-128: I=59'), + ('9a8eab004ef53093dfcf96f57e7eda82', '4488033ae9f2efd0ca9383bfca1a94e9', + '50515253555657585a5b5c5d5f606162', + 'ecb-tbl-128: I=60'), + ('0745b589e2400c25f117b1d796c28129', '978f3b8c8f9d6f46626cac3c0bcb9217', + '64656667696a6b6c6e6f707173747576', + 'ecb-tbl-128: I=61'), + ('2f1777781216cec3f044f134b1b92bbe', 'e08c8a7e582e15e5527f1d9e2eecb236', + '78797a7b7d7e7f80828384858788898a', + 'ecb-tbl-128: I=62'), + ('353a779ffc541b3a3805d90ce17580fc', 'cec155b76ac5ffda4cf4f9ca91e49a7a', + '8c8d8e8f91929394969798999b9c9d9e', + 'ecb-tbl-128: I=63'), + ('1a1eae4415cefcf08c4ac1c8f68bea8f', 'd5ac7165763225dd2a38cdc6862c29ad', + 'a0a1a2a3a5a6a7a8aaabacadafb0b1b2', + 'ecb-tbl-128: I=64'), + ('e6e7e4e5b0b3b2b5d4d5aaab16111013', '03680fe19f7ce7275452020be70e8204', + 'b4b5b6b7b9babbbcbebfc0c1c3c4c5c6', + 'ecb-tbl-128: I=65'), + ('f8f9fafbfbf8f9e677767170efe0e1e2', '461df740c9781c388e94bb861ceb54f6', + 'c8c9cacbcdcecfd0d2d3d4d5d7d8d9da', + 'ecb-tbl-128: I=66'), + ('63626160a1a2a3a445444b4a75727370', '451bd60367f96483042742219786a074', + 'dcdddedfe1e2e3e4e6e7e8e9ebecedee', + 'ecb-tbl-128: I=67'), + ('717073720605040b2d2c2b2a05fafbf9', 'e4dfa42671a02e57ef173b85c0ea9f2b', + 'f0f1f2f3f5f6f7f8fafbfcfdfe010002', + 'ecb-tbl-128: I=68'), + ('78797a7beae9e8ef3736292891969794', 'ed11b89e76274282227d854700a78b9e', + '04050607090a0b0c0e0f101113141516', + 'ecb-tbl-128: I=69'), + ('838281803231300fdddcdbdaa0afaead', '433946eaa51ea47af33895f2b90b3b75', + '18191a1b1d1e1f20222324252728292a', + 'ecb-tbl-128: I=70'), + ('18191a1bbfbcbdba75747b7a7f78797a', '6bc6d616a5d7d0284a5910ab35022528', + '2c2d2e2f31323334363738393b3c3d3e', + 'ecb-tbl-128: I=71'), + ('848586879b989996a3a2a5a4849b9a99', 'd2a920ecfe919d354b5f49eae9719c98', + '40414243454647484a4b4c4d4f505152', + 'ecb-tbl-128: I=72'), + ('0001020322212027cacbf4f551565754', '3a061b17f6a92885efbd0676985b373d', + '54555657595a5b5c5e5f606163646566', + 'ecb-tbl-128: I=73'), + ('cecfcccdafacadb2515057564a454447', 'fadeec16e33ea2f4688499d157e20d8f', + '68696a6b6d6e6f70727374757778797a', + 'ecb-tbl-128: I=74'), + ('92939091cdcecfc813121d1c80878685', '5cdefede59601aa3c3cda36fa6b1fa13', + '7c7d7e7f81828384868788898b8c8d8e', + 'ecb-tbl-128: I=75'), + ('d2d3d0d16f6c6d6259585f5ed1eeefec', '9574b00039844d92ebba7ee8719265f8', + '90919293959697989a9b9c9d9fa0a1a2', + 'ecb-tbl-128: I=76'), + ('acadaeaf878485820f0e1110d5d2d3d0', '9a9cf33758671787e5006928188643fa', + 'a4a5a6a7a9aaabacaeafb0b1b3b4b5b6', + 'ecb-tbl-128: I=77'), + ('9091929364676619e6e7e0e1757a7b78', '2cddd634c846ba66bb46cbfea4a674f9', + 'b8b9babbbdbebfc0c2c3c4c5c7c8c9ca', + 'ecb-tbl-128: I=78'), + ('babbb8b98a89888f74757a7b92959497', 'd28bae029393c3e7e26e9fafbbb4b98f', + 'cccdcecfd1d2d3d4d6d7d8d9dbdcddde', + 'ecb-tbl-128: I=79'), + ('8d8c8f8e6e6d6c633b3a3d3ccad5d4d7', 'ec27529b1bee0a9ab6a0d73ebc82e9b7', + 'e0e1e2e3e5e6e7e8eaebecedeff0f1f2', + 'ecb-tbl-128: I=80'), + ('86878485010203040808f7f767606162', '3cb25c09472aff6ee7e2b47ccd7ccb17', + 'f4f5f6f7f9fafbfcfefe010103040506', + 'ecb-tbl-128: I=81'), + ('8e8f8c8d656667788a8b8c8d010e0f0c', 'dee33103a7283370d725e44ca38f8fe5', + '08090a0b0d0e0f10121314151718191a', + 'ecb-tbl-128: I=82'), + ('c8c9cacb858687807a7b7475e7e0e1e2', '27f9bcd1aac64bffc11e7815702c1a69', + '1c1d1e1f21222324262728292b2c2d2e', + 'ecb-tbl-128: I=83'), + ('6d6c6f6e5053525d8c8d8a8badd2d3d0', '5df534ffad4ed0749a9988e9849d0021', + '30313233353637383a3b3c3d3f404142', + 'ecb-tbl-128: I=84'), + ('28292a2b393a3b3c0607181903040506', 'a48bee75db04fb60ca2b80f752a8421b', + '44454647494a4b4c4e4f505153545556', + 'ecb-tbl-128: I=85'), + ('a5a4a7a6b0b3b28ddbdadddcbdb2b3b0', '024c8cf70bc86ee5ce03678cb7af45f9', + '58595a5b5d5e5f60626364656768696a', + 'ecb-tbl-128: I=86'), + ('323330316467666130313e3f2c2b2a29', '3c19ac0f8a3a3862ce577831301e166b', + '6c6d6e6f71727374767778797b7c7d7e', + 'ecb-tbl-128: I=87'), + ('27262524080b0a05171611100b141516', 'c5e355b796a57421d59ca6be82e73bca', + '80818283858687888a8b8c8d8f909192', + 'ecb-tbl-128: I=88'), + ('040506074142434435340b0aa3a4a5a6', 'd94033276417abfb05a69d15b6e386e2', + '94959697999a9b9c9e9fa0a1a3a4a5a6', + 'ecb-tbl-128: I=89'), + ('242526271112130c61606766bdb2b3b0', '24b36559ea3a9b9b958fe6da3e5b8d85', + 'a8a9aaabadaeafb0b2b3b4b5b7b8b9ba', + 'ecb-tbl-128: I=90'), + ('4b4a4948252627209e9f9091cec9c8cb', '20fd4feaa0e8bf0cce7861d74ef4cb72', + 'bcbdbebfc1c2c3c4c6c7c8c9cbcccdce', + 'ecb-tbl-128: I=91'), + ('68696a6b6665646b9f9e9998d9e6e7e4', '350e20d5174277b9ec314c501570a11d', + 'd0d1d2d3d5d6d7d8dadbdcdddfe0e1e2', + 'ecb-tbl-128: I=92'), + ('34353637c5c6c7c0f0f1eeef7c7b7a79', '87a29d61b7c604d238fe73045a7efd57', + 'e4e5e6e7e9eaebeceeeff0f1f3f4f5f6', + 'ecb-tbl-128: I=93'), + ('32333031c2c1c13f0d0c0b0a050a0b08', '2c3164c1cc7d0064816bdc0faa362c52', + 'f8f9fafbfdfefe00020304050708090a', + 'ecb-tbl-128: I=94'), + ('cdcccfcebebdbcbbabaaa5a4181f1e1d', '195fe5e8a05a2ed594f6e4400eee10b3', + '0c0d0e0f11121314161718191b1c1d1e', + 'ecb-tbl-128: I=95'), + ('212023223635343ba0a1a6a7445b5a59', 'e4663df19b9a21a5a284c2bd7f905025', + '20212223252627282a2b2c2d2f303132', + 'ecb-tbl-128: I=96'), + ('0e0f0c0da8abaaad2f2e515002050407', '21b88714cfb4e2a933bd281a2c4743fd', + '34353637393a3b3c3e3f404143444546', + 'ecb-tbl-128: I=97'), + ('070605042a2928378e8f8889bdb2b3b0', 'cbfc3980d704fd0fc54378ab84e17870', + '48494a4b4d4e4f50525354555758595a', + 'ecb-tbl-128: I=98'), + ('cbcac9c893909196a9a8a7a6a5a2a3a0', 'bc5144baa48bdeb8b63e22e03da418ef', + '5c5d5e5f61626364666768696b6c6d6e', + 'ecb-tbl-128: I=99'), + ('80818283c1c2c3cc9c9d9a9b0cf3f2f1', '5a1dbaef1ee2984b8395da3bdffa3ccc', + '70717273757677787a7b7c7d7f808182', + 'ecb-tbl-128: I=100'), + ('1213101125262720fafbe4e5b1b6b7b4', 'f0b11cd0729dfcc80cec903d97159574', + '84858687898a8b8c8e8f909193949596', + 'ecb-tbl-128: I=101'), + ('7f7e7d7c3033320d97969190222d2c2f', '9f95314acfddc6d1914b7f19a9cc8209', + '98999a9b9d9e9fa0a2a3a4a5a7a8a9aa', + 'ecb-tbl-128: I=102'), + ('4e4f4c4d484b4a4d81808f8e53545556', '595736f6f0f70914a94e9e007f022519', + 'acadaeafb1b2b3b4b6b7b8b9bbbcbdbe', + 'ecb-tbl-128: I=103'), + ('dcdddedfb0b3b2bd15141312a1bebfbc', '1f19f57892cae586fcdfb4c694deb183', + 'c0c1c2c3c5c6c7c8cacbcccdcfd0d1d2', + 'ecb-tbl-128: I=104'), + ('93929190282b2a2dc4c5fafb92959497', '540700ee1f6f3dab0b3eddf6caee1ef5', + 'd4d5d6d7d9dadbdcdedfe0e1e3e4e5e6', + 'ecb-tbl-128: I=105'), + ('f5f4f7f6c4c7c6d9373631307e717073', '14a342a91019a331687a2254e6626ca2', + 'e8e9eaebedeeeff0f2f3f4f5f7f8f9fa', + 'ecb-tbl-128: I=106'), + ('93929190b6b5b4b364656a6b05020300', '7b25f3c3b2eea18d743ef283140f29ff', + 'fcfdfeff01020304060708090b0c0d0e', + 'ecb-tbl-128: I=107'), + ('babbb8b90d0e0f00a4a5a2a3043b3a39', '46c2587d66e5e6fa7f7ca6411ad28047', + '10111213151617181a1b1c1d1f202122', + 'ecb-tbl-128: I=108'), + ('d8d9dadb7f7c7d7a10110e0f787f7e7d', '09470e72229d954ed5ee73886dfeeba9', + '24252627292a2b2c2e2f303133343536', + 'ecb-tbl-128: I=109'), + ('fefffcfdefeced923b3a3d3c6768696a', 'd77c03de92d4d0d79ef8d4824ef365eb', + '38393a3b3d3e3f40424344454748494a', + 'ecb-tbl-128: I=110'), + ('d6d7d4d58a89888f96979899a5a2a3a0', '1d190219f290e0f1715d152d41a23593', + '4c4d4e4f51525354565758595b5c5d5e', + 'ecb-tbl-128: I=111'), + ('18191a1ba8abaaa5303136379b848586', 'a2cd332ce3a0818769616292e87f757b', + '60616263656667686a6b6c6d6f707172', + 'ecb-tbl-128: I=112'), + ('6b6a6968a4a7a6a1d6d72829b0b7b6b5', 'd54afa6ce60fbf9341a3690e21385102', + '74757677797a7b7c7e7f808183848586', + 'ecb-tbl-128: I=113'), + ('000102038a89889755545352a6a9a8ab', '06e5c364ded628a3f5e05e613e356f46', + '88898a8b8d8e8f90929394959798999a', + 'ecb-tbl-128: I=114'), + ('2d2c2f2eb3b0b1b6b6b7b8b9f2f5f4f7', 'eae63c0e62556dac85d221099896355a', + '9c9d9e9fa1a2a3a4a6a7a8a9abacadae', + 'ecb-tbl-128: I=115'), + ('979695943536373856575051e09f9e9d', '1fed060e2c6fc93ee764403a889985a2', + 'b0b1b2b3b5b6b7b8babbbcbdbfc0c1c2', + 'ecb-tbl-128: I=116'), + ('a4a5a6a7989b9a9db1b0afae7a7d7c7f', 'c25235c1a30fdec1c7cb5c5737b2a588', + 'c4c5c6c7c9cacbcccecfd0d1d3d4d5d6', + 'ecb-tbl-128: I=117'), + ('c1c0c3c2686b6a55a8a9aeafeae5e4e7', '796dbef95147d4d30873ad8b7b92efc0', + 'd8d9dadbdddedfe0e2e3e4e5e7e8e9ea', + 'ecb-tbl-128: I=118'), + ('c1c0c3c2141716118c8d828364636261', 'cbcf0fb34d98d0bd5c22ce37211a46bf', + 'ecedeeeff1f2f3f4f6f7f8f9fbfcfdfe', + 'ecb-tbl-128: I=119'), + ('93929190cccfcec196979091e0fffefd', '94b44da6466126cafa7c7fd09063fc24', + '00010203050607080a0b0c0d0f101112', + 'ecb-tbl-128: I=120'), + ('b4b5b6b7f9fafbfc25241b1a6e69686b', 'd78c5b5ebf9b4dbda6ae506c5074c8fe', + '14151617191a1b1c1e1f202123242526', + 'ecb-tbl-128: I=121'), + ('868784850704051ac7c6c1c08788898a', '6c27444c27204b043812cf8cf95f9769', + '28292a2b2d2e2f30323334353738393a', + 'ecb-tbl-128: I=122'), + ('f4f5f6f7aaa9a8affdfcf3f277707172', 'be94524ee5a2aa50bba8b75f4c0aebcf', + '3c3d3e3f41424344464748494b4c4d4e', + 'ecb-tbl-128: I=123'), + ('d3d2d1d00605040bc3c2c5c43e010003', 'a0aeaae91ba9f31f51aeb3588cf3a39e', + '50515253555657585a5b5c5d5f606162', + 'ecb-tbl-128: I=124'), + ('73727170424140476a6b74750d0a0b08', '275297779c28266ef9fe4c6a13c08488', + '64656667696a6b6c6e6f707173747576', + 'ecb-tbl-128: I=125'), + ('c2c3c0c10a0908f754555253a1aeafac', '86523d92bb8672cb01cf4a77fd725882', + '78797a7b7d7e7f80828384858788898a', + 'ecb-tbl-128: I=126'), + ('6d6c6f6ef8fbfafd82838c8df8fffefd', '4b8327640e9f33322a04dd96fcbf9a36', + '8c8d8e8f91929394969798999b9c9d9e', + 'ecb-tbl-128: I=127'), + ('f5f4f7f684878689a6a7a0a1d2cdcccf', 'ce52af650d088ca559425223f4d32694', + 'a0a1a2a3a5a6a7a8aaabacadafb0b1b2', + 'ecb-tbl-128: I=128'), + + # ecb_tbl.txt, KEYSIZE=192 + ('2d33eef2c0430a8a9ebf45e809c40bb6', 'dff4945e0336df4c1c56bc700eff837f', + '00010203050607080a0b0c0d0f10111214151617191a1b1c', + 'ecb-tbl-192: I=1'), + ('6aa375d1fa155a61fb72353e0a5a8756', 'b6fddef4752765e347d5d2dc196d1252', + '1e1f20212324252628292a2b2d2e2f30323334353738393a', + 'ecb-tbl-192: I=2'), + ('bc3736518b9490dcb8ed60eb26758ed4', 'd23684e3d963b3afcf1a114aca90cbd6', + '3c3d3e3f41424344464748494b4c4d4e5051525355565758', + 'ecb-tbl-192: I=3'), + ('aa214402b46cffb9f761ec11263a311e', '3a7ac027753e2a18c2ceab9e17c11fd0', + '5a5b5c5d5f60616264656667696a6b6c6e6f707173747576', + 'ecb-tbl-192: I=4'), + ('02aea86e572eeab66b2c3af5e9a46fd6', '8f6786bd007528ba26603c1601cdd0d8', + '78797a7b7d7e7f80828384858788898a8c8d8e8f91929394', + 'ecb-tbl-192: I=5'), + ('e2aef6acc33b965c4fa1f91c75ff6f36', 'd17d073b01e71502e28b47ab551168b3', + '969798999b9c9d9ea0a1a2a3a5a6a7a8aaabacadafb0b1b2', + 'ecb-tbl-192: I=6'), + ('0659df46427162b9434865dd9499f91d', 'a469da517119fab95876f41d06d40ffa', + 'b4b5b6b7b9babbbcbebfc0c1c3c4c5c6c8c9cacbcdcecfd0', + 'ecb-tbl-192: I=7'), + ('49a44239c748feb456f59c276a5658df', '6091aa3b695c11f5c0b6ad26d3d862ff', + 'd2d3d4d5d7d8d9dadcdddedfe1e2e3e4e6e7e8e9ebecedee', + 'ecb-tbl-192: I=8'), + ('66208f6e9d04525bdedb2733b6a6be37', '70f9e67f9f8df1294131662dc6e69364', + 'f0f1f2f3f5f6f7f8fafbfcfdfe01000204050607090a0b0c', + 'ecb-tbl-192: I=9'), + ('3393f8dfc729c97f5480b950bc9666b0', 'd154dcafad8b207fa5cbc95e9996b559', + '0e0f10111314151618191a1b1d1e1f20222324252728292a', + 'ecb-tbl-192: I=10'), + ('606834c8ce063f3234cf1145325dbd71', '4934d541e8b46fa339c805a7aeb9e5da', + '2c2d2e2f31323334363738393b3c3d3e4041424345464748', + 'ecb-tbl-192: I=11'), + ('fec1c04f529bbd17d8cecfcc4718b17f', '62564c738f3efe186e1a127a0c4d3c61', + '4a4b4c4d4f50515254555657595a5b5c5e5f606163646566', + 'ecb-tbl-192: I=12'), + ('32df99b431ed5dc5acf8caf6dc6ce475', '07805aa043986eb23693e23bef8f3438', + '68696a6b6d6e6f70727374757778797a7c7d7e7f81828384', + 'ecb-tbl-192: I=13'), + ('7fdc2b746f3f665296943b83710d1f82', 'df0b4931038bade848dee3b4b85aa44b', + '868788898b8c8d8e90919293959697989a9b9c9d9fa0a1a2', + 'ecb-tbl-192: I=14'), + ('8fba1510a3c5b87e2eaa3f7a91455ca2', '592d5fded76582e4143c65099309477c', + 'a4a5a6a7a9aaabacaeafb0b1b3b4b5b6b8b9babbbdbebfc0', + 'ecb-tbl-192: I=15'), + ('2c9b468b1c2eed92578d41b0716b223b', 'c9b8d6545580d3dfbcdd09b954ed4e92', + 'c2c3c4c5c7c8c9cacccdcecfd1d2d3d4d6d7d8d9dbdcddde', + 'ecb-tbl-192: I=16'), + ('0a2bbf0efc6bc0034f8a03433fca1b1a', '5dccd5d6eb7c1b42acb008201df707a0', + 'e0e1e2e3e5e6e7e8eaebecedeff0f1f2f4f5f6f7f9fafbfc', + 'ecb-tbl-192: I=17'), + ('25260e1f31f4104d387222e70632504b', 'a2a91682ffeb6ed1d34340946829e6f9', + 'fefe01010304050608090a0b0d0e0f10121314151718191a', + 'ecb-tbl-192: I=18'), + ('c527d25a49f08a5228d338642ae65137', 'e45d185b797000348d9267960a68435d', + '1c1d1e1f21222324262728292b2c2d2e3031323335363738', + 'ecb-tbl-192: I=19'), + ('3b49fc081432f5890d0e3d87e884a69e', '45e060dae5901cda8089e10d4f4c246b', + '3a3b3c3d3f40414244454647494a4b4c4e4f505153545556', + 'ecb-tbl-192: I=20'), + ('d173f9ed1e57597e166931df2754a083', 'f6951afacc0079a369c71fdcff45df50', + '58595a5b5d5e5f60626364656768696a6c6d6e6f71727374', + 'ecb-tbl-192: I=21'), + ('8c2b7cafa5afe7f13562daeae1adede0', '9e95e00f351d5b3ac3d0e22e626ddad6', + '767778797b7c7d7e80818283858687888a8b8c8d8f909192', + 'ecb-tbl-192: I=22'), + ('aaf4ec8c1a815aeb826cab741339532c', '9cb566ff26d92dad083b51fdc18c173c', + '94959697999a9b9c9e9fa0a1a3a4a5a6a8a9aaabadaeafb0', + 'ecb-tbl-192: I=23'), + ('40be8c5d9108e663f38f1a2395279ecf', 'c9c82766176a9b228eb9a974a010b4fb', + 'd0d1d2d3d5d6d7d8dadbdcdddfe0e1e2e4e5e6e7e9eaebec', + 'ecb-tbl-192: I=24'), + ('0c8ad9bc32d43e04716753aa4cfbe351', 'd8e26aa02945881d5137f1c1e1386e88', + '2a2b2c2d2f30313234353637393a3b3c3e3f404143444546', + 'ecb-tbl-192: I=25'), + ('1407b1d5f87d63357c8dc7ebbaebbfee', 'c0e024ccd68ff5ffa4d139c355a77c55', + '48494a4b4d4e4f50525354555758595a5c5d5e5f61626364', + 'ecb-tbl-192: I=26'), + ('e62734d1ae3378c4549e939e6f123416', '0b18b3d16f491619da338640df391d43', + '84858687898a8b8c8e8f90919394959698999a9b9d9e9fa0', + 'ecb-tbl-192: I=27'), + ('5a752cff2a176db1a1de77f2d2cdee41', 'dbe09ac8f66027bf20cb6e434f252efc', + 'a2a3a4a5a7a8a9aaacadaeafb1b2b3b4b6b7b8b9bbbcbdbe', + 'ecb-tbl-192: I=28'), + ('a9c8c3a4eabedc80c64730ddd018cd88', '6d04e5e43c5b9cbe05feb9606b6480fe', + 'c0c1c2c3c5c6c7c8cacbcccdcfd0d1d2d4d5d6d7d9dadbdc', + 'ecb-tbl-192: I=29'), + ('ee9b3dbbdb86180072130834d305999a', 'dd1d6553b96be526d9fee0fbd7176866', + '1a1b1c1d1f20212224252627292a2b2c2e2f303133343536', + 'ecb-tbl-192: I=30'), + ('a7fa8c3586b8ebde7568ead6f634a879', '0260ca7e3f979fd015b0dd4690e16d2a', + '38393a3b3d3e3f40424344454748494a4c4d4e4f51525354', + 'ecb-tbl-192: I=31'), + ('37e0f4a87f127d45ac936fe7ad88c10a', '9893734de10edcc8a67c3b110b8b8cc6', + '929394959798999a9c9d9e9fa1a2a3a4a6a7a8a9abacadae', + 'ecb-tbl-192: I=32'), + ('3f77d8b5d92bac148e4e46f697a535c5', '93b30b750516b2d18808d710c2ee84ef', + '464748494b4c4d4e50515253555657585a5b5c5d5f606162', + 'ecb-tbl-192: I=33'), + ('d25ebb686c40f7e2c4da1014936571ca', '16f65fa47be3cb5e6dfe7c6c37016c0e', + '828384858788898a8c8d8e8f91929394969798999b9c9d9e', + 'ecb-tbl-192: I=34'), + ('4f1c769d1e5b0552c7eca84dea26a549', 'f3847210d5391e2360608e5acb560581', + 'a0a1a2a3a5a6a7a8aaabacadafb0b1b2b4b5b6b7b9babbbc', + 'ecb-tbl-192: I=35'), + ('8548e2f882d7584d0fafc54372b6633a', '8754462cd223366d0753913e6af2643d', + 'bebfc0c1c3c4c5c6c8c9cacbcdcecfd0d2d3d4d5d7d8d9da', + 'ecb-tbl-192: I=36'), + ('87d7a336cb476f177cd2a51af2a62cdf', '1ea20617468d1b806a1fd58145462017', + 'dcdddedfe1e2e3e4e6e7e8e9ebecedeef0f1f2f3f5f6f7f8', + 'ecb-tbl-192: I=37'), + ('03b1feac668c4e485c1065dfc22b44ee', '3b155d927355d737c6be9dda60136e2e', + 'fafbfcfdfe01000204050607090a0b0c0e0f101113141516', + 'ecb-tbl-192: I=38'), + ('bda15e66819fa72d653a6866aa287962', '26144f7b66daa91b6333dbd3850502b3', + '18191a1b1d1e1f20222324252728292a2c2d2e2f31323334', + 'ecb-tbl-192: I=39'), + ('4d0c7a0d2505b80bf8b62ceb12467f0a', 'e4f9a4ab52ced8134c649bf319ebcc90', + '363738393b3c3d3e40414243454647484a4b4c4d4f505152', + 'ecb-tbl-192: I=40'), + ('626d34c9429b37211330986466b94e5f', 'b9ddd29ac6128a6cab121e34a4c62b36', + '54555657595a5b5c5e5f60616364656668696a6b6d6e6f70', + 'ecb-tbl-192: I=41'), + ('333c3e6bf00656b088a17e5ff0e7f60a', '6fcddad898f2ce4eff51294f5eaaf5c9', + '727374757778797a7c7d7e7f81828384868788898b8c8d8e', + 'ecb-tbl-192: I=42'), + ('687ed0cdc0d2a2bc8c466d05ef9d2891', 'c9a6fe2bf4028080bea6f7fc417bd7e3', + '90919293959697989a9b9c9d9fa0a1a2a4a5a6a7a9aaabac', + 'ecb-tbl-192: I=43'), + ('487830e78cc56c1693e64b2a6660c7b6', '6a2026846d8609d60f298a9c0673127f', + 'aeafb0b1b3b4b5b6b8b9babbbdbebfc0c2c3c4c5c7c8c9ca', + 'ecb-tbl-192: I=44'), + ('7a48d6b7b52b29392aa2072a32b66160', '2cb25c005e26efea44336c4c97a4240b', + 'cccdcecfd1d2d3d4d6d7d8d9dbdcdddee0e1e2e3e5e6e7e8', + 'ecb-tbl-192: I=45'), + ('907320e64c8c5314d10f8d7a11c8618d', '496967ab8680ddd73d09a0e4c7dcc8aa', + 'eaebecedeff0f1f2f4f5f6f7f9fafbfcfefe010103040506', + 'ecb-tbl-192: I=46'), + ('b561f2ca2d6e65a4a98341f3ed9ff533', 'd5af94de93487d1f3a8c577cb84a66a4', + '08090a0b0d0e0f10121314151718191a1c1d1e1f21222324', + 'ecb-tbl-192: I=47'), + ('df769380d212792d026f049e2e3e48ef', '84bdac569cae2828705f267cc8376e90', + '262728292b2c2d2e30313233353637383a3b3c3d3f404142', + 'ecb-tbl-192: I=48'), + ('79f374bc445bdabf8fccb8843d6054c6', 'f7401dda5ad5ab712b7eb5d10c6f99b6', + '44454647494a4b4c4e4f50515354555658595a5b5d5e5f60', + 'ecb-tbl-192: I=49'), + ('4e02f1242fa56b05c68dbae8fe44c9d6', '1c9d54318539ebd4c3b5b7e37bf119f0', + '626364656768696a6c6d6e6f71727374767778797b7c7d7e', + 'ecb-tbl-192: I=50'), + ('cf73c93cbff57ac635a6f4ad2a4a1545', 'aca572d65fb2764cffd4a6eca090ea0d', + '80818283858687888a8b8c8d8f90919294959697999a9b9c', + 'ecb-tbl-192: I=51'), + ('9923548e2875750725b886566784c625', '36d9c627b8c2a886a10ccb36eae3dfbb', + '9e9fa0a1a3a4a5a6a8a9aaabadaeafb0b2b3b4b5b7b8b9ba', + 'ecb-tbl-192: I=52'), + ('4888336b723a022c9545320f836a4207', '010edbf5981e143a81d646e597a4a568', + 'bcbdbebfc1c2c3c4c6c7c8c9cbcccdced0d1d2d3d5d6d7d8', + 'ecb-tbl-192: I=53'), + ('f84d9a5561b0608b1160dee000c41ba8', '8db44d538dc20cc2f40f3067fd298e60', + 'dadbdcdddfe0e1e2e4e5e6e7e9eaebeceeeff0f1f3f4f5f6', + 'ecb-tbl-192: I=54'), + ('c23192a0418e30a19b45ae3e3625bf22', '930eb53bc71e6ac4b82972bdcd5aafb3', + 'f8f9fafbfdfefe00020304050708090a0c0d0e0f11121314', + 'ecb-tbl-192: I=55'), + ('b84e0690b28b0025381ad82a15e501a7', '6c42a81edcbc9517ccd89c30c95597b4', + '161718191b1c1d1e20212223252627282a2b2c2d2f303132', + 'ecb-tbl-192: I=56'), + ('acef5e5c108876c4f06269f865b8f0b0', 'da389847ad06df19d76ee119c71e1dd3', + '34353637393a3b3c3e3f40414344454648494a4b4d4e4f50', + 'ecb-tbl-192: I=57'), + ('0f1b3603e0f5ddea4548246153a5e064', 'e018fdae13d3118f9a5d1a647a3f0462', + '525354555758595a5c5d5e5f61626364666768696b6c6d6e', + 'ecb-tbl-192: I=58'), + ('fbb63893450d42b58c6d88cd3c1809e3', '2aa65db36264239d3846180fabdfad20', + '70717273757677787a7b7c7d7f80818284858687898a8b8c', + 'ecb-tbl-192: I=59'), + ('4bef736df150259dae0c91354e8a5f92', '1472163e9a4f780f1ceb44b07ecf4fdb', + '8e8f90919394959698999a9b9d9e9fa0a2a3a4a5a7a8a9aa', + 'ecb-tbl-192: I=60'), + ('7d2d46242056ef13d3c3fc93c128f4c7', 'c8273fdc8f3a9f72e91097614b62397c', + 'acadaeafb1b2b3b4b6b7b8b9bbbcbdbec0c1c2c3c5c6c7c8', + 'ecb-tbl-192: I=61'), + ('e9c1ba2df415657a256edb33934680fd', '66c8427dcd733aaf7b3470cb7d976e3f', + 'cacbcccdcfd0d1d2d4d5d6d7d9dadbdcdedfe0e1e3e4e5e6', + 'ecb-tbl-192: I=62'), + ('e23ee277b0aa0a1dfb81f7527c3514f1', '146131cb17f1424d4f8da91e6f80c1d0', + 'e8e9eaebedeeeff0f2f3f4f5f7f8f9fafcfdfeff01020304', + 'ecb-tbl-192: I=63'), + ('3e7445b0b63caaf75e4a911e12106b4c', '2610d0ad83659081ae085266a88770dc', + '060708090b0c0d0e10111213151617181a1b1c1d1f202122', + 'ecb-tbl-192: I=64'), + ('767774752023222544455a5be6e1e0e3', '38a2b5a974b0575c5d733917fb0d4570', + '24252627292a2b2c2e2f30313334353638393a3b3d3e3f40', + 'ecb-tbl-192: I=65'), + ('72737475717e7f7ce9e8ebea696a6b6c', 'e21d401ebc60de20d6c486e4f39a588b', + '424344454748494a4c4d4e4f51525354565758595b5c5d5e', + 'ecb-tbl-192: I=66'), + ('dfdedddc25262728c9c8cfcef1eeefec', 'e51d5f88c670b079c0ca1f0c2c4405a2', + '60616263656667686a6b6c6d6f70717274757677797a7b7c', + 'ecb-tbl-192: I=67'), + ('fffe0100707776755f5e5d5c7675746b', '246a94788a642fb3d1b823c8762380c8', + '7e7f80818384858688898a8b8d8e8f90929394959798999a', + 'ecb-tbl-192: I=68'), + ('e0e1e2e3424140479f9e9190292e2f2c', 'b80c391c5c41a4c3b30c68e0e3d7550f', + '9c9d9e9fa1a2a3a4a6a7a8a9abacadaeb0b1b2b3b5b6b7b8', + 'ecb-tbl-192: I=69'), + ('2120272690efeeed3b3a39384e4d4c4b', 'b77c4754fc64eb9a1154a9af0bb1f21c', + 'babbbcbdbfc0c1c2c4c5c6c7c9cacbcccecfd0d1d3d4d5d6', + 'ecb-tbl-192: I=70'), + ('ecedeeef5350516ea1a0a7a6a3acadae', 'fb554de520d159a06bf219fc7f34a02f', + 'd8d9dadbdddedfe0e2e3e4e5e7e8e9eaecedeeeff1f2f3f4', + 'ecb-tbl-192: I=71'), + ('32333c3d25222320e9e8ebeacecdccc3', 'a89fba152d76b4927beed160ddb76c57', + 'f6f7f8f9fbfcfdfe00010203050607080a0b0c0d0f101112', + 'ecb-tbl-192: I=72'), + ('40414243626160678a8bb4b511161714', '5676eab4a98d2e8473b3f3d46424247c', + '14151617191a1b1c1e1f20212324252628292a2b2d2e2f30', + 'ecb-tbl-192: I=73'), + ('94959293f5fafbf81f1e1d1c7c7f7e79', '4e8f068bd7ede52a639036ec86c33568', + '323334353738393a3c3d3e3f41424344464748494b4c4d4e', + 'ecb-tbl-192: I=74'), + ('bebfbcbd191a1b14cfcec9c8546b6a69', 'f0193c4d7aff1791ee4c07eb4a1824fc', + '50515253555657585a5b5c5d5f60616264656667696a6b6c', + 'ecb-tbl-192: I=75'), + ('2c2d3233898e8f8cbbbab9b8333031ce', 'ac8686eeca9ba761afe82d67b928c33f', + '6e6f70717374757678797a7b7d7e7f80828384858788898a', + 'ecb-tbl-192: I=76'), + ('84858687bfbcbdba37363938fdfafbf8', '5faf8573e33b145b6a369cd3606ab2c9', + '8c8d8e8f91929394969798999b9c9d9ea0a1a2a3a5a6a7a8', + 'ecb-tbl-192: I=77'), + ('828384857669686b909192930b08090e', '31587e9944ab1c16b844ecad0df2e7da', + 'aaabacadafb0b1b2b4b5b6b7b9babbbcbebfc0c1c3c4c5c6', + 'ecb-tbl-192: I=78'), + ('bebfbcbd9695948b707176779e919093', 'd017fecd91148aba37f6f3068aa67d8a', + 'c8c9cacbcdcecfd0d2d3d4d5d7d8d9dadcdddedfe1e2e3e4', + 'ecb-tbl-192: I=79'), + ('8b8a85846067666521202322d0d3d2dd', '788ef2f021a73cba2794b616078a8500', + 'e6e7e8e9ebecedeef0f1f2f3f5f6f7f8fafbfcfdfe010002', + 'ecb-tbl-192: I=80'), + ('76777475f1f2f3f4f8f9e6e777707172', '5d1ef20dced6bcbc12131ac7c54788aa', + '04050607090a0b0c0e0f10111314151618191a1b1d1e1f20', + 'ecb-tbl-192: I=81'), + ('a4a5a2a34f404142b4b5b6b727242522', 'b3c8cf961faf9ea05fdde6d1e4d8f663', + '222324252728292a2c2d2e2f31323334363738393b3c3d3e', + 'ecb-tbl-192: I=82'), + ('94959697e1e2e3ec16171011839c9d9e', '143075c70605861c7fac6526199e459f', + '40414243454647484a4b4c4d4f50515254555657595a5b5c', + 'ecb-tbl-192: I=83'), + ('03023d3c06010003dedfdcddfffcfde2', 'a5ae12eade9a87268d898bfc8fc0252a', + '5e5f60616364656668696a6b6d6e6f70727374757778797a', + 'ecb-tbl-192: I=84'), + ('10111213f1f2f3f4cecfc0c1dbdcddde', '0924f7cf2e877a4819f5244a360dcea9', + '7c7d7e7f81828384868788898b8c8d8e9091929395969798', + 'ecb-tbl-192: I=85'), + ('67666160724d4c4f1d1c1f1e73707176', '3d9e9635afcc3e291cc7ab3f27d1c99a', + '9a9b9c9d9fa0a1a2a4a5a6a7a9aaabacaeafb0b1b3b4b5b6', + 'ecb-tbl-192: I=86'), + ('e6e7e4e5a8abaad584858283909f9e9d', '9d80feebf87510e2b8fb98bb54fd788c', + 'b8b9babbbdbebfc0c2c3c4c5c7c8c9cacccdcecfd1d2d3d4', + 'ecb-tbl-192: I=87'), + ('71707f7e565150537d7c7f7e6162636c', '5f9d1a082a1a37985f174002eca01309', + 'd6d7d8d9dbdcdddee0e1e2e3e5e6e7e8eaebecedeff0f1f2', + 'ecb-tbl-192: I=88'), + ('64656667212223245555aaaa03040506', 'a390ebb1d1403930184a44b4876646e4', + 'f4f5f6f7f9fafbfcfefe01010304050608090a0b0d0e0f10', + 'ecb-tbl-192: I=89'), + ('9e9f9899aba4a5a6cfcecdcc2b28292e', '700fe918981c3195bb6c4bcb46b74e29', + '121314151718191a1c1d1e1f21222324262728292b2c2d2e', + 'ecb-tbl-192: I=90'), + ('c7c6c5c4d1d2d3dc626364653a454447', '907984406f7bf2d17fb1eb15b673d747', + '30313233353637383a3b3c3d3f40414244454647494a4b4c', + 'ecb-tbl-192: I=91'), + ('f6f7e8e9e0e7e6e51d1c1f1e5b585966', 'c32a956dcfc875c2ac7c7cc8b8cc26e1', + '4e4f50515354555658595a5b5d5e5f60626364656768696a', + 'ecb-tbl-192: I=92'), + ('bcbdbebf5d5e5f5868696667f4f3f2f1', '02646e2ebfa9b820cf8424e9b9b6eb51', + '6c6d6e6f71727374767778797b7c7d7e8081828385868788', + 'ecb-tbl-192: I=93'), + ('40414647b0afaead9b9a99989b98999e', '621fda3a5bbd54c6d3c685816bd4ead8', + '8a8b8c8d8f90919294959697999a9b9c9e9fa0a1a3a4a5a6', + 'ecb-tbl-192: I=94'), + ('69686b6a0201001f0f0e0908b4bbbab9', 'd4e216040426dfaf18b152469bc5ac2f', + 'a8a9aaabadaeafb0b2b3b4b5b7b8b9babcbdbebfc1c2c3c4', + 'ecb-tbl-192: I=95'), + ('c7c6c9c8d8dfdedd5a5b5859bebdbcb3', '9d0635b9d33b6cdbd71f5d246ea17cc8', + 'c6c7c8c9cbcccdced0d1d2d3d5d6d7d8dadbdcdddfe0e1e2', + 'ecb-tbl-192: I=96'), + ('dedfdcdd787b7a7dfffee1e0b2b5b4b7', '10abad1bd9bae5448808765583a2cc1a', + 'e4e5e6e7e9eaebeceeeff0f1f3f4f5f6f8f9fafbfdfefe00', + 'ecb-tbl-192: I=97'), + ('4d4c4b4a606f6e6dd0d1d2d3fbf8f9fe', '6891889e16544e355ff65a793c39c9a8', + '020304050708090a0c0d0e0f11121314161718191b1c1d1e', + 'ecb-tbl-192: I=98'), + ('b7b6b5b4d7d4d5dae5e4e3e2e1fefffc', 'cc735582e68072c163cd9ddf46b91279', + '20212223252627282a2b2c2d2f30313234353637393a3b3c', + 'ecb-tbl-192: I=99'), + ('cecfb0b1f7f0f1f2aeafacad3e3d3c23', 'c5c68b9aeeb7f878df578efa562f9574', + '3e3f40414344454648494a4b4d4e4f50525354555758595a', + 'ecb-tbl-192: I=100'), + ('cacbc8c9cdcecfc812131c1d494e4f4c', '5f4764395a667a47d73452955d0d2ce8', + '5c5d5e5f61626364666768696b6c6d6e7071727375767778', + 'ecb-tbl-192: I=101'), + ('9d9c9b9ad22d2c2fb1b0b3b20c0f0e09', '701448331f66106cefddf1eb8267c357', + '7a7b7c7d7f80818284858687898a8b8c8e8f909193949596', + 'ecb-tbl-192: I=102'), + ('7a7b787964676659959493924f404142', 'cb3ee56d2e14b4e1941666f13379d657', + '98999a9b9d9e9fa0a2a3a4a5a7a8a9aaacadaeafb1b2b3b4', + 'ecb-tbl-192: I=103'), + ('aaaba4a5cec9c8cb1f1e1d1caba8a9a6', '9fe16efd18ab6e1981191851fedb0764', + 'b6b7b8b9bbbcbdbec0c1c2c3c5c6c7c8cacbcccdcfd0d1d2', + 'ecb-tbl-192: I=104'), + ('93929190282b2a2dc4c5fafb92959497', '3dc9ba24e1b223589b147adceb4c8e48', + 'd4d5d6d7d9dadbdcdedfe0e1e3e4e5e6e8e9eaebedeeeff0', + 'ecb-tbl-192: I=105'), + ('efeee9e8ded1d0d339383b3a888b8a8d', '1c333032682e7d4de5e5afc05c3e483c', + 'f2f3f4f5f7f8f9fafcfdfeff01020304060708090b0c0d0e', + 'ecb-tbl-192: I=106'), + ('7f7e7d7ca2a1a0af78797e7f112e2f2c', 'd593cc99a95afef7e92038e05a59d00a', + '10111213151617181a1b1c1d1f20212224252627292a2b2c', + 'ecb-tbl-192: I=107'), + ('84859a9b2b2c2d2e868784852625245b', '51e7f96f53b4353923452c222134e1ec', + '2e2f30313334353638393a3b3d3e3f40424344454748494a', + 'ecb-tbl-192: I=108'), + ('b0b1b2b3070405026869666710171615', '4075b357a1a2b473400c3b25f32f81a4', + '4c4d4e4f51525354565758595b5c5d5e6061626365666768', + 'ecb-tbl-192: I=109'), + ('acadaaabbda2a3a00d0c0f0e595a5b5c', '302e341a3ebcd74f0d55f61714570284', + '6a6b6c6d6f70717274757677797a7b7c7e7f808183848586', + 'ecb-tbl-192: I=110'), + ('121310115655544b5253545569666764', '57abdd8231280da01c5042b78cf76522', + '88898a8b8d8e8f90929394959798999a9c9d9e9fa1a2a3a4', + 'ecb-tbl-192: I=111'), + ('dedfd0d166616063eaebe8e94142434c', '17f9ea7eea17ac1adf0e190fef799e92', + 'a6a7a8a9abacadaeb0b1b2b3b5b6b7b8babbbcbdbfc0c1c2', + 'ecb-tbl-192: I=112'), + ('dbdad9d81417161166677879e0e7e6e5', '2e1bdd563dd87ee5c338dd6d098d0a7a', + 'c4c5c6c7c9cacbcccecfd0d1d3d4d5d6d8d9dadbdddedfe0', + 'ecb-tbl-192: I=113'), + ('6a6b6c6de0efeeed2b2a2928c0c3c2c5', 'eb869996e6f8bfb2bfdd9e0c4504dbb2', + 'e2e3e4e5e7e8e9eaecedeeeff1f2f3f4f6f7f8f9fbfcfdfe', + 'ecb-tbl-192: I=114'), + ('b1b0b3b21714151a1a1b1c1d5649484b', 'c2e01549e9decf317468b3e018c61ba8', + '00010203050607080a0b0c0d0f10111214151617191a1b1c', + 'ecb-tbl-192: I=115'), + ('39380706a3a4a5a6c4c5c6c77271706f', '8da875d033c01dd463b244a1770f4a22', + '1e1f20212324252628292a2b2d2e2f30323334353738393a', + 'ecb-tbl-192: I=116'), + ('5c5d5e5f1013121539383736e2e5e4e7', '8ba0dcf3a186844f026d022f8839d696', + '3c3d3e3f41424344464748494b4c4d4e5051525355565758', + 'ecb-tbl-192: I=117'), + ('43424544ead5d4d72e2f2c2d64676661', 'e9691ff9a6cc6970e51670a0fd5b88c1', + '5a5b5c5d5f60616264656667696a6b6c6e6f707173747576', + 'ecb-tbl-192: I=118'), + ('55545756989b9a65f8f9feff18171615', 'f2baec06faeed30f88ee63ba081a6e5b', + '78797a7b7d7e7f80828384858788898a8c8d8e8f91929394', + 'ecb-tbl-192: I=119'), + ('05040b0a525554573c3d3e3f4a494847', '9c39d4c459ae5753394d6094adc21e78', + '969798999b9c9d9ea0a1a2a3a5a6a7a8aaabacadafb0b1b2', + 'ecb-tbl-192: I=120'), + ('14151617595a5b5c8584fbfa8e89888b', '6345b532a11904502ea43ba99c6bd2b2', + 'b4b5b6b7b9babbbcbebfc0c1c3c4c5c6c8c9cacbcdcecfd0', + 'ecb-tbl-192: I=121'), + ('7c7d7a7bfdf2f3f029282b2a51525354', '5ffae3061a95172e4070cedce1e428c8', + 'd2d3d4d5d7d8d9dadcdddedfe1e2e3e4e6e7e8e9ebecedee', + 'ecb-tbl-192: I=122'), + ('38393a3b1e1d1c1341404746c23d3c3e', '0a4566be4cdf9adce5dec865b5ab34cd', + 'f0f1f2f3f5f6f7f8fafbfcfdfe01000204050607090a0b0c', + 'ecb-tbl-192: I=123'), + ('8d8c939240474645818083827c7f7e41', 'ca17fcce79b7404f2559b22928f126fb', + '0e0f10111314151618191a1b1d1e1f20222324252728292a', + 'ecb-tbl-192: I=124'), + ('3b3a39381a19181f32333c3d45424340', '97ca39b849ed73a6470a97c821d82f58', + '2c2d2e2f31323334363738393b3c3d3e4041424345464748', + 'ecb-tbl-192: I=125'), + ('f0f1f6f738272625828380817f7c7d7a', '8198cb06bc684c6d3e9b7989428dcf7a', + '4a4b4c4d4f50515254555657595a5b5c5e5f606163646566', + 'ecb-tbl-192: I=126'), + ('89888b8a0407061966676061141b1a19', 'f53c464c705ee0f28d9a4c59374928bd', + '68696a6b6d6e6f70727374757778797a7c7d7e7f81828384', + 'ecb-tbl-192: I=127'), + ('d3d2dddcaaadacaf9c9d9e9fe8ebeae5', '9adb3d4cca559bb98c3e2ed73dbf1154', + '868788898b8c8d8e90919293959697989a9b9c9d9fa0a1a2', + 'ecb-tbl-192: I=128'), + + # ecb_tbl.txt, KEYSIZE=256 + ('834eadfccac7e1b30664b1aba44815ab', '1946dabf6a03a2a2c3d0b05080aed6fc', + '00010203050607080a0b0c0d0f10111214151617191a1b1c1e1f202123242526', + 'ecb-tbl-256: I=1'), + ('d9dc4dba3021b05d67c0518f72b62bf1', '5ed301d747d3cc715445ebdec62f2fb4', + '28292a2b2d2e2f30323334353738393a3c3d3e3f41424344464748494b4c4d4e', + 'ecb-tbl-256: I=2'), + ('a291d86301a4a739f7392173aa3c604c', '6585c8f43d13a6beab6419fc5935b9d0', + '50515253555657585a5b5c5d5f60616264656667696a6b6c6e6f707173747576', + 'ecb-tbl-256: I=3'), + ('4264b2696498de4df79788a9f83e9390', '2a5b56a596680fcc0e05f5e0f151ecae', + '78797a7b7d7e7f80828384858788898a8c8d8e8f91929394969798999b9c9d9e', + 'ecb-tbl-256: I=4'), + ('ee9932b3721804d5a83ef5949245b6f6', 'f5d6ff414fd2c6181494d20c37f2b8c4', + 'a0a1a2a3a5a6a7a8aaabacadafb0b1b2b4b5b6b7b9babbbcbebfc0c1c3c4c5c6', + 'ecb-tbl-256: I=5'), + ('e6248f55c5fdcbca9cbbb01c88a2ea77', '85399c01f59fffb5204f19f8482f00b8', + 'c8c9cacbcdcecfd0d2d3d4d5d7d8d9dadcdddedfe1e2e3e4e6e7e8e9ebecedee', + 'ecb-tbl-256: I=6'), + ('b8358e41b9dff65fd461d55a99266247', '92097b4c88a041ddf98144bc8d22e8e7', + 'f0f1f2f3f5f6f7f8fafbfcfdfe01000204050607090a0b0c0e0f101113141516', + 'ecb-tbl-256: I=7'), + ('f0e2d72260af58e21e015ab3a4c0d906', '89bd5b73b356ab412aef9f76cea2d65c', + '18191a1b1d1e1f20222324252728292a2c2d2e2f31323334363738393b3c3d3e', + 'ecb-tbl-256: I=8'), + ('475b8b823ce8893db3c44a9f2a379ff7', '2536969093c55ff9454692f2fac2f530', + '40414243454647484a4b4c4d4f50515254555657595a5b5c5e5f606163646566', + 'ecb-tbl-256: I=9'), + ('688f5281945812862f5f3076cf80412f', '07fc76a872843f3f6e0081ee9396d637', + '68696a6b6d6e6f70727374757778797a7c7d7e7f81828384868788898b8c8d8e', + 'ecb-tbl-256: I=10'), + ('08d1d2bc750af553365d35e75afaceaa', 'e38ba8ec2aa741358dcc93e8f141c491', + '90919293959697989a9b9c9d9fa0a1a2a4a5a6a7a9aaabacaeafb0b1b3b4b5b6', + 'ecb-tbl-256: I=11'), + ('8707121f47cc3efceca5f9a8474950a1', 'd028ee23e4a89075d0b03e868d7d3a42', + 'b8b9babbbdbebfc0c2c3c4c5c7c8c9cacccdcecfd1d2d3d4d6d7d8d9dbdcddde', + 'ecb-tbl-256: I=12'), + ('e51aa0b135dba566939c3b6359a980c5', '8cd9423dfc459e547155c5d1d522e540', + 'e0e1e2e3e5e6e7e8eaebecedeff0f1f2f4f5f6f7f9fafbfcfefe010103040506', + 'ecb-tbl-256: I=13'), + ('069a007fc76a459f98baf917fedf9521', '080e9517eb1677719acf728086040ae3', + '08090a0b0d0e0f10121314151718191a1c1d1e1f21222324262728292b2c2d2e', + 'ecb-tbl-256: I=14'), + ('726165c1723fbcf6c026d7d00b091027', '7c1700211a3991fc0ecded0ab3e576b0', + '30313233353637383a3b3c3d3f40414244454647494a4b4c4e4f505153545556', + 'ecb-tbl-256: I=15'), + ('d7c544de91d55cfcde1f84ca382200ce', 'dabcbcc855839251db51e224fbe87435', + '58595a5b5d5e5f60626364656768696a6c6d6e6f71727374767778797b7c7d7e', + 'ecb-tbl-256: I=16'), + ('fed3c9a161b9b5b2bd611b41dc9da357', '68d56fad0406947a4dd27a7448c10f1d', + '80818283858687888a8b8c8d8f90919294959697999a9b9c9e9fa0a1a3a4a5a6', + 'ecb-tbl-256: I=17'), + ('4f634cdc6551043409f30b635832cf82', 'da9a11479844d1ffee24bbf3719a9925', + 'a8a9aaabadaeafb0b2b3b4b5b7b8b9babcbdbebfc1c2c3c4c6c7c8c9cbcccdce', + 'ecb-tbl-256: I=18'), + ('109ce98db0dfb36734d9f3394711b4e6', '5e4ba572f8d23e738da9b05ba24b8d81', + 'd0d1d2d3d5d6d7d8dadbdcdddfe0e1e2e4e5e6e7e9eaebeceeeff0f1f3f4f5f6', + 'ecb-tbl-256: I=19'), + ('4ea6dfaba2d8a02ffdffa89835987242', 'a115a2065d667e3f0b883837a6e903f8', + '70717273757677787a7b7c7d7f80818284858687898a8b8c8e8f909193949596', + 'ecb-tbl-256: I=20'), + ('5ae094f54af58e6e3cdbf976dac6d9ef', '3e9e90dc33eac2437d86ad30b137e66e', + '98999a9b9d9e9fa0a2a3a4a5a7a8a9aaacadaeafb1b2b3b4b6b7b8b9bbbcbdbe', + 'ecb-tbl-256: I=21'), + ('764d8e8e0f29926dbe5122e66354fdbe', '01ce82d8fbcdae824cb3c48e495c3692', + 'c0c1c2c3c5c6c7c8cacbcccdcfd0d1d2d4d5d6d7d9dadbdcdedfe0e1e3e4e5e6', + 'ecb-tbl-256: I=22'), + ('3f0418f888cdf29a982bf6b75410d6a9', '0c9cff163ce936faaf083cfd3dea3117', + 'e8e9eaebedeeeff0f2f3f4f5f7f8f9fafcfdfeff01020304060708090b0c0d0e', + 'ecb-tbl-256: I=23'), + ('e4a3e7cb12cdd56aa4a75197a9530220', '5131ba9bd48f2bba85560680df504b52', + '10111213151617181a1b1c1d1f20212224252627292a2b2c2e2f303133343536', + 'ecb-tbl-256: I=24'), + ('211677684aac1ec1a160f44c4ebf3f26', '9dc503bbf09823aec8a977a5ad26ccb2', + '38393a3b3d3e3f40424344454748494a4c4d4e4f51525354565758595b5c5d5e', + 'ecb-tbl-256: I=25'), + ('d21e439ff749ac8f18d6d4b105e03895', '9a6db0c0862e506a9e397225884041d7', + '60616263656667686a6b6c6d6f70717274757677797a7b7c7e7f808183848586', + 'ecb-tbl-256: I=26'), + ('d9f6ff44646c4725bd4c0103ff5552a7', '430bf9570804185e1ab6365fc6a6860c', + '88898a8b8d8e8f90929394959798999a9c9d9e9fa1a2a3a4a6a7a8a9abacadae', + 'ecb-tbl-256: I=27'), + ('0b1256c2a00b976250cfc5b0c37ed382', '3525ebc02f4886e6a5a3762813e8ce8a', + 'b0b1b2b3b5b6b7b8babbbcbdbfc0c1c2c4c5c6c7c9cacbcccecfd0d1d3d4d5d6', + 'ecb-tbl-256: I=28'), + ('b056447ffc6dc4523a36cc2e972a3a79', '07fa265c763779cce224c7bad671027b', + 'd8d9dadbdddedfe0e2e3e4e5e7e8e9eaecedeeeff1f2f3f4f6f7f8f9fbfcfdfe', + 'ecb-tbl-256: I=29'), + ('5e25ca78f0de55802524d38da3fe4456', 'e8b72b4e8be243438c9fff1f0e205872', + '00010203050607080a0b0c0d0f10111214151617191a1b1c1e1f202123242526', + 'ecb-tbl-256: I=30'), + ('a5bcf4728fa5eaad8567c0dc24675f83', '109d4f999a0e11ace1f05e6b22cbcb50', + '28292a2b2d2e2f30323334353738393a3c3d3e3f41424344464748494b4c4d4e', + 'ecb-tbl-256: I=31'), + ('814e59f97ed84646b78b2ca022e9ca43', '45a5e8d4c3ed58403ff08d68a0cc4029', + '50515253555657585a5b5c5d5f60616264656667696a6b6c6e6f707173747576', + 'ecb-tbl-256: I=32'), + ('15478beec58f4775c7a7f5d4395514d7', '196865964db3d417b6bd4d586bcb7634', + '78797a7b7d7e7f80828384858788898a8c8d8e8f91929394969798999b9c9d9e', + 'ecb-tbl-256: I=33'), + ('253548ffca461c67c8cbc78cd59f4756', '60436ad45ac7d30d99195f815d98d2ae', + 'a0a1a2a3a5a6a7a8aaabacadafb0b1b2b4b5b6b7b9babbbcbebfc0c1c3c4c5c6', + 'ecb-tbl-256: I=34'), + ('fd7ad8d73b9b0f8cc41600640f503d65', 'bb07a23f0b61014b197620c185e2cd75', + 'c8c9cacbcdcecfd0d2d3d4d5d7d8d9dadcdddedfe1e2e3e4e6e7e8e9ebecedee', + 'ecb-tbl-256: I=35'), + ('06199de52c6cbf8af954cd65830bcd56', '5bc0b2850129c854423aff0751fe343b', + 'f0f1f2f3f5f6f7f8fafbfcfdfe01000204050607090a0b0c0e0f101113141516', + 'ecb-tbl-256: I=36'), + ('f17c4ffe48e44c61bd891e257e725794', '7541a78f96738e6417d2a24bd2beca40', + '18191a1b1d1e1f20222324252728292a2c2d2e2f31323334363738393b3c3d3e', + 'ecb-tbl-256: I=37'), + ('9a5b4a402a3e8a59be6bf5cd8154f029', 'b0a303054412882e464591f1546c5b9e', + '40414243454647484a4b4c4d4f50515254555657595a5b5c5e5f606163646566', + 'ecb-tbl-256: I=38'), + ('79bd40b91a7e07dc939d441782ae6b17', '778c06d8a355eeee214fcea14b4e0eef', + '68696a6b6d6e6f70727374757778797a7c7d7e7f81828384868788898b8c8d8e', + 'ecb-tbl-256: I=39'), + ('d8ceaaf8976e5fbe1012d8c84f323799', '09614206d15cbace63227d06db6beebb', + '90919293959697989a9b9c9d9fa0a1a2a4a5a6a7a9aaabacaeafb0b1b3b4b5b6', + 'ecb-tbl-256: I=40'), + ('3316e2751e2e388b083da23dd6ac3fbe', '41b97fb20e427a9fdbbb358d9262255d', + 'b8b9babbbdbebfc0c2c3c4c5c7c8c9cacccdcecfd1d2d3d4d6d7d8d9dbdcddde', + 'ecb-tbl-256: I=41'), + ('8b7cfbe37de7dca793521819242c5816', 'c1940f703d845f957652c2d64abd7adf', + 'e0e1e2e3e5e6e7e8eaebecedeff0f1f2f4f5f6f7f9fafbfcfefe010103040506', + 'ecb-tbl-256: I=42'), + ('f23f033c0eebf8ec55752662fd58ce68', 'd2d44fcdae5332343366db297efcf21b', + '08090a0b0d0e0f10121314151718191a1c1d1e1f21222324262728292b2c2d2e', + 'ecb-tbl-256: I=43'), + ('59eb34f6c8bdbacc5fc6ad73a59a1301', 'ea8196b79dbe167b6aa9896e287eed2b', + '30313233353637383a3b3c3d3f40414244454647494a4b4c4e4f505153545556', + 'ecb-tbl-256: I=44'), + ('dcde8b6bd5cf7cc22d9505e3ce81261a', 'd6b0b0c4ba6c7dbe5ed467a1e3f06c2d', + '58595a5b5d5e5f60626364656768696a6c6d6e6f71727374767778797b7c7d7e', + 'ecb-tbl-256: I=45'), + ('e33cf7e524fed781e7042ff9f4b35dc7', 'ec51eb295250c22c2fb01816fb72bcae', + '80818283858687888a8b8c8d8f90919294959697999a9b9c9e9fa0a1a3a4a5a6', + 'ecb-tbl-256: I=46'), + ('27963c8facdf73062867d164df6d064c', 'aded6630a07ce9c7408a155d3bd0d36f', + 'a8a9aaabadaeafb0b2b3b4b5b7b8b9babcbdbebfc1c2c3c4c6c7c8c9cbcccdce', + 'ecb-tbl-256: I=47'), + ('77b1ce386b551b995f2f2a1da994eef8', '697c9245b9937f32f5d1c82319f0363a', + 'd0d1d2d3d5d6d7d8dadbdcdddfe0e1e2e4e5e6e7e9eaebeceeeff0f1f3f4f5f6', + 'ecb-tbl-256: I=48'), + ('f083388b013679efcf0bb9b15d52ae5c', 'aad5ad50c6262aaec30541a1b7b5b19c', + 'f8f9fafbfdfefe00020304050708090a0c0d0e0f11121314161718191b1c1d1e', + 'ecb-tbl-256: I=49'), + ('c5009e0dab55db0abdb636f2600290c8', '7d34b893855341ec625bd6875ac18c0d', + '20212223252627282a2b2c2d2f30313234353637393a3b3c3e3f404143444546', + 'ecb-tbl-256: I=50'), + ('7804881e26cd532d8514d3683f00f1b9', '7ef05105440f83862f5d780e88f02b41', + '48494a4b4d4e4f50525354555758595a5c5d5e5f61626364666768696b6c6d6e', + 'ecb-tbl-256: I=51'), + ('46cddcd73d1eb53e675ca012870a92a3', 'c377c06403382061af2c9c93a8e70df6', + '70717273757677787a7b7c7d7f80818284858687898a8b8c8e8f909193949596', + 'ecb-tbl-256: I=52'), + ('a9fb44062bb07fe130a8e8299eacb1ab', '1dbdb3ffdc052dacc83318853abc6de5', + '98999a9b9d9e9fa0a2a3a4a5a7a8a9aaacadaeafb1b2b3b4b6b7b8b9bbbcbdbe', + 'ecb-tbl-256: I=53'), + ('2b6ff8d7a5cc3a28a22d5a6f221af26b', '69a6eab00432517d0bf483c91c0963c7', + 'c0c1c2c3c5c6c7c8cacbcccdcfd0d1d2d4d5d6d7d9dadbdcdedfe0e1e3e4e5e6', + 'ecb-tbl-256: I=54'), + ('1a9527c29b8add4b0e3e656dbb2af8b4', '0797f41dc217c80446e1d514bd6ab197', + 'e8e9eaebedeeeff0f2f3f4f5f7f8f9fafcfdfeff01020304060708090b0c0d0e', + 'ecb-tbl-256: I=55'), + ('7f99cf2c75244df015eb4b0c1050aeae', '9dfd76575902a637c01343c58e011a03', + '10111213151617181a1b1c1d1f20212224252627292a2b2c2e2f303133343536', + 'ecb-tbl-256: I=56'), + ('e84ff85b0d9454071909c1381646c4ed', 'acf4328ae78f34b9fa9b459747cc2658', + '38393a3b3d3e3f40424344454748494a4c4d4e4f51525354565758595b5c5d5e', + 'ecb-tbl-256: I=57'), + ('89afd40f99521280d5399b12404f6db4', 'b0479aea12bac4fe2384cf98995150c6', + '60616263656667686a6b6c6d6f70717274757677797a7b7c7e7f808183848586', + 'ecb-tbl-256: I=58'), + ('a09ef32dbc5119a35ab7fa38656f0329', '9dd52789efe3ffb99f33b3da5030109a', + '88898a8b8d8e8f90929394959798999a9c9d9e9fa1a2a3a4a6a7a8a9abacadae', + 'ecb-tbl-256: I=59'), + ('61773457f068c376c7829b93e696e716', 'abbb755e4621ef8f1214c19f649fb9fd', + 'b0b1b2b3b5b6b7b8babbbcbdbfc0c1c2c4c5c6c7c9cacbcccecfd0d1d3d4d5d6', + 'ecb-tbl-256: I=60'), + ('a34f0cae726cce41dd498747d891b967', 'da27fb8174357bce2bed0e7354f380f9', + 'd8d9dadbdddedfe0e2e3e4e5e7e8e9eaecedeeeff1f2f3f4f6f7f8f9fbfcfdfe', + 'ecb-tbl-256: I=61'), + ('856f59496c7388ee2d2b1a27b7697847', 'c59a0663f0993838f6e5856593bdc5ef', + '00010203050607080a0b0c0d0f10111214151617191a1b1c1e1f202123242526', + 'ecb-tbl-256: I=62'), + ('cb090c593ef7720bd95908fb93b49df4', 'ed60b264b5213e831607a99c0ce5e57e', + '28292a2b2d2e2f30323334353738393a3c3d3e3f41424344464748494b4c4d4e', + 'ecb-tbl-256: I=63'), + ('a0ac75cd2f1923d460fc4d457ad95baf', 'e50548746846f3eb77b8c520640884ed', + '50515253555657585a5b5c5d5f60616264656667696a6b6c6e6f707173747576', + 'ecb-tbl-256: I=64'), + ('2a2b282974777689e8e9eeef525d5c5f', '28282cc7d21d6a2923641e52d188ef0c', + '78797a7b7d7e7f80828384858788898a8c8d8e8f91929394969798999b9c9d9e', + 'ecb-tbl-256: I=65'), + ('909192939390919e0f0e09089788898a', '0dfa5b02abb18e5a815305216d6d4f8e', + 'a0a1a2a3a5a6a7a8aaabacadafb0b1b2b4b5b6b7b9babbbcbebfc0c1c3c4c5c6', + 'ecb-tbl-256: I=66'), + ('777675748d8e8f907170777649464744', '7359635c0eecefe31d673395fb46fb99', + 'c8c9cacbcdcecfd0d2d3d4d5d7d8d9dadcdddedfe1e2e3e4e6e7e8e9ebecedee', + 'ecb-tbl-256: I=67'), + ('717073720605040b2d2c2b2a05fafbf9', '73c679f7d5aef2745c9737bb4c47fb36', + 'f0f1f2f3f5f6f7f8fafbfcfdfe01000204050607090a0b0c0e0f101113141516', + 'ecb-tbl-256: I=68'), + ('64656667fefdfcc31b1a1d1ca5aaaba8', 'b192bd472a4d2eafb786e97458967626', + '18191a1b1d1e1f20222324252728292a2c2d2e2f31323334363738393b3c3d3e', + 'ecb-tbl-256: I=69'), + ('dbdad9d86a696867b5b4b3b2c8d7d6d5', '0ec327f6c8a2b147598ca3fde61dc6a4', + '40414243454647484a4b4c4d4f50515254555657595a5b5c5e5f606163646566', + 'ecb-tbl-256: I=70'), + ('5c5d5e5fe3e0e1fe31303736333c3d3e', 'fc418eb3c41b859b38d4b6f646629729', + '68696a6b6d6e6f70727374757778797a7c7d7e7f81828384868788898b8c8d8e', + 'ecb-tbl-256: I=71'), + ('545556574b48494673727574546b6a69', '30249e5ac282b1c981ea64b609f3a154', + '90919293959697989a9b9c9d9fa0a1a2a4a5a6a7a9aaabacaeafb0b1b3b4b5b6', + 'ecb-tbl-256: I=72'), + ('ecedeeefc6c5c4bb56575051f5fafbf8', '5e6e08646d12150776bb43c2d78a9703', + 'b8b9babbbdbebfc0c2c3c4c5c7c8c9cacccdcecfd1d2d3d4d6d7d8d9dbdcddde', + 'ecb-tbl-256: I=73'), + ('464744452724252ac9c8cfced2cdcccf', 'faeb3d5de652cd3447dceb343f30394a', + 'e0e1e2e3e5e6e7e8eaebecedeff0f1f2f4f5f6f7f9fafbfcfefe010103040506', + 'ecb-tbl-256: I=74'), + ('e6e7e4e54142435c878681801c131211', 'a8e88706823f6993ef80d05c1c7b2cf0', + '08090a0b0d0e0f10121314151718191a1c1d1e1f21222324262728292b2c2d2e', + 'ecb-tbl-256: I=75'), + ('72737071cfcccdc2f9f8fffe710e0f0c', '8ced86677e6e00a1a1b15968f2d3cce6', + '30313233353637383a3b3c3d3f40414244454647494a4b4c4e4f505153545556', + 'ecb-tbl-256: I=76'), + ('505152537370714ec3c2c5c4010e0f0c', '9fc7c23858be03bdebb84e90db6786a9', + '58595a5b5d5e5f60626364656768696a6c6d6e6f71727374767778797b7c7d7e', + 'ecb-tbl-256: I=77'), + ('a8a9aaab5c5f5e51aeafa8a93d222320', 'b4fbd65b33f70d8cf7f1111ac4649c36', + '80818283858687888a8b8c8d8f90919294959697999a9b9c9e9fa0a1a3a4a5a6', + 'ecb-tbl-256: I=78'), + ('dedfdcddf6f5f4eb10111617fef1f0f3', 'c5c32d5ed03c4b53cc8c1bd0ef0dbbf6', + 'a8a9aaabadaeafb0b2b3b4b5b7b8b9babcbdbebfc1c2c3c4c6c7c8c9cbcccdce', + 'ecb-tbl-256: I=79'), + ('bdbcbfbe5e5d5c530b0a0d0cfac5c4c7', 'd1a7f03b773e5c212464b63709c6a891', + 'd0d1d2d3d5d6d7d8dadbdcdddfe0e1e2e4e5e6e7e9eaebeceeeff0f1f3f4f5f6', + 'ecb-tbl-256: I=80'), + ('8a8b8889050606f8f4f5f2f3636c6d6e', '6b7161d8745947ac6950438ea138d028', + 'f8f9fafbfdfefe00020304050708090a0c0d0e0f11121314161718191b1c1d1e', + 'ecb-tbl-256: I=81'), + ('a6a7a4a54d4e4f40b2b3b4b539262724', 'fd47a9f7e366ee7a09bc508b00460661', + '20212223252627282a2b2c2d2f30313234353637393a3b3c3e3f404143444546', + 'ecb-tbl-256: I=82'), + ('9c9d9e9fe9eaebf40e0f08099b949596', '00d40b003dc3a0d9310b659b98c7e416', + '48494a4b4d4e4f50525354555758595a5c5d5e5f61626364666768696b6c6d6e', + 'ecb-tbl-256: I=83'), + ('2d2c2f2e1013121dcccdcacbed121310', 'eea4c79dcc8e2bda691f20ac48be0717', + '70717273757677787a7b7c7d7f80818284858687898a8b8c8e8f909193949596', + 'ecb-tbl-256: I=84'), + ('f4f5f6f7edeeefd0eaebecedf7f8f9fa', 'e78f43b11c204403e5751f89d05a2509', + '98999a9b9d9e9fa0a2a3a4a5a7a8a9aaacadaeafb1b2b3b4b6b7b8b9bbbcbdbe', + 'ecb-tbl-256: I=85'), + ('3d3c3f3e282b2a2573727574150a0b08', 'd0f0e3d1f1244bb979931e38dd1786ef', + 'c0c1c2c3c5c6c7c8cacbcccdcfd0d1d2d4d5d6d7d9dadbdcdedfe0e1e3e4e5e6', + 'ecb-tbl-256: I=86'), + ('b6b7b4b5f8fbfae5b4b5b2b3a0afaead', '042e639dc4e1e4dde7b75b749ea6f765', + 'e8e9eaebedeeeff0f2f3f4f5f7f8f9fafcfdfeff01020304060708090b0c0d0e', + 'ecb-tbl-256: I=87'), + ('b7b6b5b4989b9a95878681809ba4a5a6', 'bc032fdd0efe29503a980a7d07ab46a8', + '10111213151617181a1b1c1d1f20212224252627292a2b2c2e2f303133343536', + 'ecb-tbl-256: I=88'), + ('a8a9aaabe5e6e798e9e8efee4748494a', '0c93ac949c0da6446effb86183b6c910', + '38393a3b3d3e3f40424344454748494a4c4d4e4f51525354565758595b5c5d5e', + 'ecb-tbl-256: I=89'), + ('ecedeeefd9dadbd4b9b8bfbe657a7b78', 'e0d343e14da75c917b4a5cec4810d7c2', + '60616263656667686a6b6c6d6f70717274757677797a7b7c7e7f808183848586', + 'ecb-tbl-256: I=90'), + ('7f7e7d7c696a6b74cacbcccd929d9c9f', '0eafb821748408279b937b626792e619', + '88898a8b8d8e8f90929394959798999a9c9d9e9fa1a2a3a4a6a7a8a9abacadae', + 'ecb-tbl-256: I=91'), + ('08090a0b0605040bfffef9f8b9c6c7c4', 'fa1ac6e02d23b106a1fef18b274a553f', + 'b0b1b2b3b5b6b7b8babbbcbdbfc0c1c2c4c5c6c7c9cacbcccecfd0d1d3d4d5d6', + 'ecb-tbl-256: I=92'), + ('08090a0bf1f2f3ccfcfdfafb68676665', '0dadfe019cd12368075507df33c1a1e9', + 'd8d9dadbdddedfe0e2e3e4e5e7e8e9eaecedeeeff1f2f3f4f6f7f8f9fbfcfdfe', + 'ecb-tbl-256: I=93'), + ('cacbc8c93a393837050403020d121310', '3a0879b414465d9ffbaf86b33a63a1b9', + '00010203050607080a0b0c0d0f10111214151617191a1b1c1e1f202123242526', + 'ecb-tbl-256: I=94'), + ('e9e8ebea8281809f8f8e8988343b3a39', '62199fadc76d0be1805d3ba0b7d914bf', + '28292a2b2d2e2f30323334353738393a3c3d3e3f41424344464748494b4c4d4e', + 'ecb-tbl-256: I=95'), + ('515053524645444bd0d1d6d7340b0a09', '1b06d6c5d333e742730130cf78e719b4', + '50515253555657585a5b5c5d5f60616264656667696a6b6c6e6f707173747576', + 'ecb-tbl-256: I=96'), + ('42434041ecefee1193929594c6c9c8cb', 'f1f848824c32e9dcdcbf21580f069329', + '78797a7b7d7e7f80828384858788898a8c8d8e8f91929394969798999b9c9d9e', + 'ecb-tbl-256: I=97'), + ('efeeedecc2c1c0cf76777071455a5b58', '1a09050cbd684f784d8e965e0782f28a', + 'a0a1a2a3a5a6a7a8aaabacadafb0b1b2b4b5b6b7b9babbbcbebfc0c1c3c4c5c6', + 'ecb-tbl-256: I=98'), + ('5f5e5d5c3f3c3d221d1c1b1a19161714', '79c2969e7ded2ba7d088f3f320692360', + 'c8c9cacbcdcecfd0d2d3d4d5d7d8d9dadcdddedfe1e2e3e4e6e7e8e9ebecedee', + 'ecb-tbl-256: I=99'), + ('000102034142434c1c1d1a1b8d727371', '091a658a2f7444c16accb669450c7b63', + 'f0f1f2f3f5f6f7f8fafbfcfdfe01000204050607090a0b0c0e0f101113141516', + 'ecb-tbl-256: I=100'), + ('8e8f8c8db1b2b38c56575051050a0b08', '97c1e3a72cca65fa977d5ed0e8a7bbfc', + '18191a1b1d1e1f20222324252728292a2c2d2e2f31323334363738393b3c3d3e', + 'ecb-tbl-256: I=101'), + ('a7a6a5a4e8ebeae57f7e7978cad5d4d7', '70c430c6db9a17828937305a2df91a2a', + '40414243454647484a4b4c4d4f50515254555657595a5b5c5e5f606163646566', + 'ecb-tbl-256: I=102'), + ('8a8b888994979689454443429f909192', '629553457fbe2479098571c7c903fde8', + '68696a6b6d6e6f70727374757778797a7c7d7e7f81828384868788898b8c8d8e', + 'ecb-tbl-256: I=103'), + ('8c8d8e8fe0e3e2ed45444342f1cecfcc', 'a25b25a61f612669e7d91265c7d476ba', + '90919293959697989a9b9c9d9fa0a1a2a4a5a6a7a9aaabacaeafb0b1b3b4b5b6', + 'ecb-tbl-256: I=104'), + ('fffefdfc4c4f4e31d8d9dedfb6b9b8bb', 'eb7e4e49b8ae0f024570dda293254fed', + 'b8b9babbbdbebfc0c2c3c4c5c7c8c9cacccdcecfd1d2d3d4d6d7d8d9dbdcddde', + 'ecb-tbl-256: I=105'), + ('fdfcfffecccfcec12f2e29286679787b', '38fe15d61cca84516e924adce5014f67', + 'e0e1e2e3e5e6e7e8eaebecedeff0f1f2f4f5f6f7f9fafbfcfefe010103040506', + 'ecb-tbl-256: I=106'), + ('67666564bab9b8a77071767719161714', '3ad208492249108c9f3ebeb167ad0583', + '08090a0b0d0e0f10121314151718191a1c1d1e1f21222324262728292b2c2d2e', + 'ecb-tbl-256: I=107'), + ('9a9b98992d2e2f2084858283245b5a59', '299ba9f9bf5ab05c3580fc26edd1ed12', + '30313233353637383a3b3c3d3f40414244454647494a4b4c4e4f505153545556', + 'ecb-tbl-256: I=108'), + ('a4a5a6a70b0809365c5d5a5b2c232221', '19dc705b857a60fb07717b2ea5717781', + '58595a5b5d5e5f60626364656768696a6c6d6e6f71727374767778797b7c7d7e', + 'ecb-tbl-256: I=109'), + ('464744455754555af3f2f5f4afb0b1b2', 'ffc8aeb885b5efcad06b6dbebf92e76b', + '80818283858687888a8b8c8d8f90919294959697999a9b9c9e9fa0a1a3a4a5a6', + 'ecb-tbl-256: I=110'), + ('323330317675746b7273747549464744', 'f58900c5e0b385253ff2546250a0142b', + 'a8a9aaabadaeafb0b2b3b4b5b7b8b9babcbdbebfc1c2c3c4c6c7c8c9cbcccdce', + 'ecb-tbl-256: I=111'), + ('a8a9aaab181b1a15808186872b141516', '2ee67b56280bc462429cee6e3370cbc1', + 'd0d1d2d3d5d6d7d8dadbdcdddfe0e1e2e4e5e6e7e9eaebeceeeff0f1f3f4f5f6', + 'ecb-tbl-256: I=112'), + ('e7e6e5e4202323ddaaabacad343b3a39', '20db650a9c8e9a84ab4d25f7edc8f03f', + 'f8f9fafbfdfefe00020304050708090a0c0d0e0f11121314161718191b1c1d1e', + 'ecb-tbl-256: I=113'), + ('a8a9aaab2221202fedecebea1e010003', '3c36da169525cf818843805f25b78ae5', + '20212223252627282a2b2c2d2f30313234353637393a3b3c3e3f404143444546', + 'ecb-tbl-256: I=114'), + ('f9f8fbfa5f5c5d42424344450e010003', '9a781d960db9e45e37779042fea51922', + '48494a4b4d4e4f50525354555758595a5c5d5e5f61626364666768696b6c6d6e', + 'ecb-tbl-256: I=115'), + ('57565554f5f6f7f89697909120dfdedd', '6560395ec269c672a3c288226efdba77', + '70717273757677787a7b7c7d7f80818284858687898a8b8c8e8f909193949596', + 'ecb-tbl-256: I=116'), + ('f8f9fafbcccfcef1dddcdbda0e010003', '8c772b7a189ac544453d5916ebb27b9a', + '98999a9b9d9e9fa0a2a3a4a5a7a8a9aaacadaeafb1b2b3b4b6b7b8b9bbbcbdbe', + 'ecb-tbl-256: I=117'), + ('d9d8dbda7073727d80818687c2dddcdf', '77ca5468cc48e843d05f78eed9d6578f', + 'c0c1c2c3c5c6c7c8cacbcccdcfd0d1d2d4d5d6d7d9dadbdcdedfe0e1e3e4e5e6', + 'ecb-tbl-256: I=118'), + ('c5c4c7c6080b0a1588898e8f68676665', '72cdcc71dc82c60d4429c9e2d8195baa', + 'e8e9eaebedeeeff0f2f3f4f5f7f8f9fafcfdfeff01020304060708090b0c0d0e', + 'ecb-tbl-256: I=119'), + ('83828180dcdfded186878081f0cfcecd', '8080d68ce60e94b40b5b8b69eeb35afa', + '10111213151617181a1b1c1d1f20212224252627292a2b2c2e2f303133343536', + 'ecb-tbl-256: I=120'), + ('98999a9bdddedfa079787f7e0a050407', '44222d3cde299c04369d58ac0eba1e8e', + '38393a3b3d3e3f40424344454748494a4c4d4e4f51525354565758595b5c5d5e', + 'ecb-tbl-256: I=121'), + ('cecfcccd4f4c4d429f9e9998dfc0c1c2', '9b8721b0a8dfc691c5bc5885dbfcb27a', + '60616263656667686a6b6c6d6f70717274757677797a7b7c7e7f808183848586', + 'ecb-tbl-256: I=122'), + ('404142436665647b29282f2eaba4a5a6', '0dc015ce9a3a3414b5e62ec643384183', + '88898a8b8d8e8f90929394959798999a9c9d9e9fa1a2a3a4a6a7a8a9abacadae', + 'ecb-tbl-256: I=123'), + ('33323130e6e5e4eb23222524dea1a0a3', '705715448a8da412025ce38345c2a148', + 'b0b1b2b3b5b6b7b8babbbcbdbfc0c1c2c4c5c6c7c9cacbcccecfd0d1d3d4d5d6', + 'ecb-tbl-256: I=124'), + ('cfcecdccf6f5f4cbe6e7e0e199969794', 'c32b5b0b6fbae165266c569f4b6ecf0b', + 'd8d9dadbdddedfe0e2e3e4e5e7e8e9eaecedeeeff1f2f3f4f6f7f8f9fbfcfdfe', + 'ecb-tbl-256: I=125'), + ('babbb8b97271707fdcdddadb29363734', '4dca6c75192a01ddca9476af2a521e87', + '00010203050607080a0b0c0d0f10111214151617191a1b1c1e1f202123242526', + 'ecb-tbl-256: I=126'), + ('c9c8cbca4447465926272021545b5a59', '058691e627ecbc36ac07b6db423bd698', + '28292a2b2d2e2f30323334353738393a3c3d3e3f41424344464748494b4c4d4e', + 'ecb-tbl-256: I=127'), + ('050407067477767956575051221d1c1f', '7444527095838fe080fc2bcdd30847eb', + '50515253555657585a5b5c5d5f60616264656667696a6b6c6e6f707173747576', + 'ecb-tbl-256: I=128'), + + # FIPS PUB 800-38A test vectors, 2001 edition. Annex F. + + ('6bc1bee22e409f96e93d7e117393172a'+'ae2d8a571e03ac9c9eb76fac45af8e51'+ + '30c81c46a35ce411e5fbc1191a0a52ef'+'f69f2445df4f9b17ad2b417be66c3710', + '3ad77bb40d7a3660a89ecaf32466ef97'+'f5d3d58503b9699de785895a96fdbaaf'+ + '43b1cd7f598ece23881b00e3ed030688'+'7b0c785e27e8ad3f8223207104725dd4', + '2b7e151628aed2a6abf7158809cf4f3c', + 'NIST 800-38A, F.1.1, ECB and AES-128'), + + ('6bc1bee22e409f96e93d7e117393172a'+'ae2d8a571e03ac9c9eb76fac45af8e51'+ + '30c81c46a35ce411e5fbc1191a0a52ef'+'f69f2445df4f9b17ad2b417be66c3710', + 'bd334f1d6e45f25ff712a214571fa5cc'+'974104846d0ad3ad7734ecb3ecee4eef'+ + 'ef7afd2270e2e60adce0ba2face6444e'+'9a4b41ba738d6c72fb16691603c18e0e', + '8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b', + 'NIST 800-38A, F.1.3, ECB and AES-192'), + + ('6bc1bee22e409f96e93d7e117393172a'+'ae2d8a571e03ac9c9eb76fac45af8e51'+ + '30c81c46a35ce411e5fbc1191a0a52ef'+'f69f2445df4f9b17ad2b417be66c3710', + 'f3eed1bdb5d2a03c064b5a7e3db181f8'+'591ccb10d410ed26dc5ba74a31362870'+ + 'b6ed21b99ca6f4f9f153e7b1beafed1d'+'23304b7a39f9f3ff067d8d8f9e24ecc7', + '603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4', + 'NIST 800-38A, F.1.3, ECB and AES-256'), + +] + +test_data_8_lanes = [] +for td in test_data: + test_data_8_lanes.append((td[0] * 8, td[1] * 8, td[2], td[3])) +test_data += test_data_8_lanes + +class TestMultipleBlocks(unittest.TestCase): + + def __init__(self, use_aesni): + unittest.TestCase.__init__(self) + self.use_aesni = use_aesni + + def runTest(self): + # Encrypt data which is 8*2+4 bytes long, so as to trigger (for the + # AESNI variant) both the path that parallelizes 8 lanes and the one + # that processes data serially + + tvs = [ + (b'a' * 16, 'c0b27011eb15bf144d2fc9fae80ea16d4c231cb230416c5fac02e6835ad9d7d0'), + (b'a' * 24, 'df8435ce361a78c535b41dcb57da952abbf9ee5954dc6fbcd75fd00fa626915d'), + (b'a' * 32, '211402de6c80db1f92ba255881178e1f70783b8cfd3b37808205e48b80486cd8') + ] + + for key, expected in tvs: + + cipher = AES.new(key, AES.MODE_ECB, use_aesni=self.use_aesni) + h = SHA256.new() + + pt = b"".join([ tobytes('{0:016x}'.format(x)) for x in range(20) ]) + ct = cipher.encrypt(pt) + self.assertEqual(SHA256.new(ct).hexdigest(), expected) + + +class TestIncompleteBlocks(unittest.TestCase): + + def __init__(self, use_aesni): + unittest.TestCase.__init__(self) + self.use_aesni = use_aesni + + def runTest(self): + # Encrypt data with length not multiple of 16 bytes + + cipher = AES.new(b'4'*16, AES.MODE_ECB, use_aesni=self.use_aesni) + + for msg_len in range(1, 16): + self.assertRaises(ValueError, cipher.encrypt, b'1' * msg_len) + self.assertRaises(ValueError, cipher.encrypt, b'1' * (msg_len+16)) + self.assertRaises(ValueError, cipher.decrypt, b'1' * msg_len) + self.assertRaises(ValueError, cipher.decrypt, b'1' * (msg_len+16)) + + self.assertEqual(cipher.encrypt(b''), b'') + self.assertEqual(cipher.decrypt(b''), b'') + + +class TestOutput(unittest.TestCase): + + def __init__(self, use_aesni): + unittest.TestCase.__init__(self) + self.use_aesni = use_aesni + + def runTest(self): + # Encrypt/Decrypt data and test output parameter + + cipher = AES.new(b'4'*16, AES.MODE_ECB, use_aesni=self.use_aesni) + + pt = b'5' * 16 + ct = cipher.encrypt(pt) + + output = bytearray(16) + res = cipher.encrypt(pt, output=output) + self.assertEqual(ct, output) + self.assertEqual(res, None) + + res = cipher.decrypt(ct, output=output) + self.assertEqual(pt, output) + self.assertEqual(res, None) + + output = memoryview(bytearray(16)) + cipher.encrypt(pt, output=output) + self.assertEqual(ct, output) + + cipher.decrypt(ct, output=output) + self.assertEqual(pt, output) + + self.assertRaises(TypeError, cipher.encrypt, pt, output=b'0'*16) + self.assertRaises(TypeError, cipher.decrypt, ct, output=b'0'*16) + + shorter_output = bytearray(15) + self.assertRaises(ValueError, cipher.encrypt, pt, output=shorter_output) + self.assertRaises(ValueError, cipher.decrypt, ct, output=shorter_output) + + +def get_tests(config={}): + from Cryptodome.Util import _cpu_features + from .common import make_block_tests + + tests = make_block_tests(AES, "AES", test_data, {'use_aesni': False}) + tests += [ TestMultipleBlocks(False) ] + tests += [ TestIncompleteBlocks(False) ] + if _cpu_features.have_aes_ni(): + # Run tests with AES-NI instructions if they are available. + tests += make_block_tests(AES, "AESNI", test_data, {'use_aesni': True}) + tests += [ TestMultipleBlocks(True) ] + tests += [ TestIncompleteBlocks(True) ] + tests += [ TestOutput(True) ] + else: + print("Skipping AESNI tests") + return tests + +if __name__ == '__main__': + import unittest + suite = lambda: unittest.TestSuite(get_tests()) + unittest.main(defaultTest='suite') + +# vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/test_ARC2.py b/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/test_ARC2.py new file mode 100644 index 0000000..0072506 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/test_ARC2.py @@ -0,0 +1,167 @@ +# -*- coding: utf-8 -*- +# +# SelfTest/Cipher/ARC2.py: Self-test for the Alleged-RC2 cipher +# +# Written in 2008 by Dwayne C. Litzenberger +# +# =================================================================== +# The contents of this file are dedicated to the public domain. To +# the extent that dedication to the public domain is not available, +# everyone is granted a worldwide, perpetual, royalty-free, +# non-exclusive license to exercise all rights associated with the +# contents of this file for any purpose whatsoever. +# No rights are reserved. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# =================================================================== + +"""Self-test suite for Cryptodome.Cipher.ARC2""" + +import unittest + +from Cryptodome.Util.py3compat import b, bchr + +from Cryptodome.Cipher import ARC2 + +# This is a list of (plaintext, ciphertext, key[, description[, extra_params]]) tuples. +test_data = [ + # Test vectors from RFC 2268 + + # 63-bit effective key length + ('0000000000000000', 'ebb773f993278eff', '0000000000000000', + 'RFC2268-1', dict(effective_keylen=63)), + + # 64-bit effective key length + ('ffffffffffffffff', '278b27e42e2f0d49', 'ffffffffffffffff', + 'RFC2268-2', dict(effective_keylen=64)), + ('1000000000000001', '30649edf9be7d2c2', '3000000000000000', + 'RFC2268-3', dict(effective_keylen=64)), + #('0000000000000000', '61a8a244adacccf0', '88', + # 'RFC2268-4', dict(effective_keylen=64)), + ('0000000000000000', '6ccf4308974c267f', '88bca90e90875a', + 'RFC2268-5', dict(effective_keylen=64)), + ('0000000000000000', '1a807d272bbe5db1', '88bca90e90875a7f0f79c384627bafb2', + 'RFC2268-6', dict(effective_keylen=64)), + + # 128-bit effective key length + ('0000000000000000', '2269552ab0f85ca6', '88bca90e90875a7f0f79c384627bafb2', + "RFC2268-7", dict(effective_keylen=128)), + ('0000000000000000', '5b78d3a43dfff1f1', + '88bca90e90875a7f0f79c384627bafb216f80a6f85920584c42fceb0be255daf1e', + "RFC2268-8", dict(effective_keylen=129)), + + # Test vectors from PyCryptodome 2.0.1's testdata.py + # 1024-bit effective key length + ('0000000000000000', '624fb3e887419e48', '5068696c6970476c617373', + 'PCTv201-0'), + ('ffffffffffffffff', '79cadef44c4a5a85', '5068696c6970476c617373', + 'PCTv201-1'), + ('0001020304050607', '90411525b34e4c2c', '5068696c6970476c617373', + 'PCTv201-2'), + ('0011223344556677', '078656aaba61cbfb', '5068696c6970476c617373', + 'PCTv201-3'), + ('0000000000000000', 'd7bcc5dbb4d6e56a', 'ffffffffffffffff', + 'PCTv201-4'), + ('ffffffffffffffff', '7259018ec557b357', 'ffffffffffffffff', + 'PCTv201-5'), + ('0001020304050607', '93d20a497f2ccb62', 'ffffffffffffffff', + 'PCTv201-6'), + ('0011223344556677', 'cb15a7f819c0014d', 'ffffffffffffffff', + 'PCTv201-7'), + ('0000000000000000', '63ac98cdf3843a7a', 'ffffffffffffffff5065746572477265656e6177617953e5ffe553', + 'PCTv201-8'), + ('ffffffffffffffff', '3fb49e2fa12371dd', 'ffffffffffffffff5065746572477265656e6177617953e5ffe553', + 'PCTv201-9'), + ('0001020304050607', '46414781ab387d5f', 'ffffffffffffffff5065746572477265656e6177617953e5ffe553', + 'PCTv201-10'), + ('0011223344556677', 'be09dc81feaca271', 'ffffffffffffffff5065746572477265656e6177617953e5ffe553', + 'PCTv201-11'), + ('0000000000000000', 'e64221e608be30ab', '53e5ffe553', + 'PCTv201-12'), + ('ffffffffffffffff', '862bc60fdcd4d9a9', '53e5ffe553', + 'PCTv201-13'), + ('0001020304050607', '6a34da50fa5e47de', '53e5ffe553', + 'PCTv201-14'), + ('0011223344556677', '584644c34503122c', '53e5ffe553', + 'PCTv201-15'), +] + +class BufferOverflowTest(unittest.TestCase): + # Test a buffer overflow found in older versions of PyCrypto + + def runTest(self): + """ARC2 with keylength > 128""" + key = b("x") * 16384 + self.assertRaises(ValueError, ARC2.new, key, ARC2.MODE_ECB) + +class KeyLength(unittest.TestCase): + + def runTest(self): + ARC2.new(b'\x00' * 16, ARC2.MODE_ECB, effective_keylen=40) + self.assertRaises(ValueError, ARC2.new, bchr(0) * 4, ARC2.MODE_ECB) + self.assertRaises(ValueError, ARC2.new, bchr(0) * 129, ARC2.MODE_ECB) + + self.assertRaises(ValueError, ARC2.new, bchr(0) * 16, ARC2.MODE_ECB, + effective_keylen=39) + self.assertRaises(ValueError, ARC2.new, bchr(0) * 16, ARC2.MODE_ECB, + effective_keylen=1025) + + +class TestOutput(unittest.TestCase): + + def runTest(self): + # Encrypt/Decrypt data and test output parameter + + cipher = ARC2.new(b'4'*16, ARC2.MODE_ECB) + + pt = b'5' * 16 + ct = cipher.encrypt(pt) + + output = bytearray(16) + res = cipher.encrypt(pt, output=output) + self.assertEqual(ct, output) + self.assertEqual(res, None) + + res = cipher.decrypt(ct, output=output) + self.assertEqual(pt, output) + self.assertEqual(res, None) + + output = memoryview(bytearray(16)) + cipher.encrypt(pt, output=output) + self.assertEqual(ct, output) + + cipher.decrypt(ct, output=output) + self.assertEqual(pt, output) + + self.assertRaises(TypeError, cipher.encrypt, pt, output=b'0'*16) + self.assertRaises(TypeError, cipher.decrypt, ct, output=b'0'*16) + + shorter_output = bytearray(7) + self.assertRaises(ValueError, cipher.encrypt, pt, output=shorter_output) + self.assertRaises(ValueError, cipher.decrypt, ct, output=shorter_output) + + +def get_tests(config={}): + from Cryptodome.Cipher import ARC2 + from .common import make_block_tests + + tests = make_block_tests(ARC2, "ARC2", test_data) + tests.append(BufferOverflowTest()) + tests.append(KeyLength()) + tests += [TestOutput()] + + return tests + +if __name__ == '__main__': + import unittest + suite = lambda: unittest.TestSuite(get_tests()) + unittest.main(defaultTest='suite') + +# vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/test_ARC4.py b/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/test_ARC4.py new file mode 100644 index 0000000..a160c98 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/test_ARC4.py @@ -0,0 +1,471 @@ +# -*- coding: utf-8 -*- +# +# SelfTest/Cipher/ARC4.py: Self-test for the Alleged-RC4 cipher +# +# Written in 2008 by Dwayne C. Litzenberger +# +# =================================================================== +# The contents of this file are dedicated to the public domain. To +# the extent that dedication to the public domain is not available, +# everyone is granted a worldwide, perpetual, royalty-free, +# non-exclusive license to exercise all rights associated with the +# contents of this file for any purpose whatsoever. +# No rights are reserved. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# =================================================================== + +"""Self-test suite for Cryptodome.Cipher.ARC4""" + +import unittest + +from Cryptodome.Util.py3compat import b +from Cryptodome.SelfTest.st_common import list_test_cases +from binascii import unhexlify + +from Cryptodome.Cipher import ARC4 + +# This is a list of (plaintext, ciphertext, key[, description]) tuples. +test_data = [ + # Test vectors from Eric Rescorla's message with the subject + # "RC4 compatibility testing", sent to the cipherpunks mailing list on + # September 13, 1994. + # http://cypherpunks.venona.com/date/1994/09/msg00420.html + + ('0123456789abcdef', '75b7878099e0c596', '0123456789abcdef', + 'Test vector 0'), + + ('0000000000000000', '7494c2e7104b0879', '0123456789abcdef', + 'Test vector 1'), + + ('0000000000000000', 'de188941a3375d3a', '0000000000000000', + 'Test vector 2'), + + ('00000000000000000000', 'd6a141a7ec3c38dfbd61', 'ef012345', + 'Test vector 3'), + + ('01' * 512, + '7595c3e6114a09780c4ad452338e1ffd9a1be9498f813d76533449b6778dcad8' + + 'c78a8d2ba9ac66085d0e53d59c26c2d1c490c1ebbe0ce66d1b6b1b13b6b919b8' + + '47c25a91447a95e75e4ef16779cde8bf0a95850e32af9689444fd377108f98fd' + + 'cbd4e726567500990bcc7e0ca3c4aaa304a387d20f3b8fbbcd42a1bd311d7a43' + + '03dda5ab078896ae80c18b0af66dff319616eb784e495ad2ce90d7f772a81747' + + 'b65f62093b1e0db9e5ba532fafec47508323e671327df9444432cb7367cec82f' + + '5d44c0d00b67d650a075cd4b70dedd77eb9b10231b6b5b741347396d62897421' + + 'd43df9b42e446e358e9c11a9b2184ecbef0cd8e7a877ef968f1390ec9b3d35a5' + + '585cb009290e2fcde7b5ec66d9084be44055a619d9dd7fc3166f9487f7cb2729' + + '12426445998514c15d53a18c864ce3a2b7555793988126520eacf2e3066e230c' + + '91bee4dd5304f5fd0405b35bd99c73135d3d9bc335ee049ef69b3867bf2d7bd1' + + 'eaa595d8bfc0066ff8d31509eb0c6caa006c807a623ef84c3d33c195d23ee320' + + 'c40de0558157c822d4b8c569d849aed59d4e0fd7f379586b4b7ff684ed6a189f' + + '7486d49b9c4bad9ba24b96abf924372c8a8fffb10d55354900a77a3db5f205e1' + + 'b99fcd8660863a159ad4abe40fa48934163ddde542a6585540fd683cbfd8c00f' + + '12129a284deacc4cdefe58be7137541c047126c8d49e2755ab181ab7e940b0c0', + '0123456789abcdef', + "Test vector 4"), + # shortest key - generated with arc4 package + ('7468697320697320616e206578616d706c65', + '7260677d38495a09585d69321e17eaf3cdd0', + '01'), +] + + +class RFC6229_Tests(unittest.TestCase): + # Test vectors from RFC 6229. Each test vector is a tuple with two items: + # the ARC4 key and a dictionary. The dictionary has keystream offsets as keys + # and the 16-byte keystream starting at the relevant offset as value. + rfc6229_data = [ + # Page 3 + ( + '0102030405', + { + 0: 'b2 39 63 05 f0 3d c0 27 cc c3 52 4a 0a 11 18 a8', + 16: '69 82 94 4f 18 fc 82 d5 89 c4 03 a4 7a 0d 09 19', + 240: '28 cb 11 32 c9 6c e2 86 42 1d ca ad b8 b6 9e ae', + 256: '1c fc f6 2b 03 ed db 64 1d 77 df cf 7f 8d 8c 93', + 496: '42 b7 d0 cd d9 18 a8 a3 3d d5 17 81 c8 1f 40 41', + 512: '64 59 84 44 32 a7 da 92 3c fb 3e b4 98 06 61 f6', + 752: 'ec 10 32 7b de 2b ee fd 18 f9 27 76 80 45 7e 22', + 768: 'eb 62 63 8d 4f 0b a1 fe 9f ca 20 e0 5b f8 ff 2b', + 1008: '45 12 90 48 e6 a0 ed 0b 56 b4 90 33 8f 07 8d a5', + 1024: '30 ab bc c7 c2 0b 01 60 9f 23 ee 2d 5f 6b b7 df', + 1520: '32 94 f7 44 d8 f9 79 05 07 e7 0f 62 e5 bb ce ea', + 1536: 'd8 72 9d b4 18 82 25 9b ee 4f 82 53 25 f5 a1 30', + 2032: '1e b1 4a 0c 13 b3 bf 47 fa 2a 0b a9 3a d4 5b 8b', + 2048: 'cc 58 2f 8b a9 f2 65 e2 b1 be 91 12 e9 75 d2 d7', + 3056: 'f2 e3 0f 9b d1 02 ec bf 75 aa ad e9 bc 35 c4 3c', + 3072: 'ec 0e 11 c4 79 dc 32 9d c8 da 79 68 fe 96 56 81', + 4080: '06 83 26 a2 11 84 16 d2 1f 9d 04 b2 cd 1c a0 50', + 4096: 'ff 25 b5 89 95 99 67 07 e5 1f bd f0 8b 34 d8 75' + } + ), + # Page 4 + ( + '01020304050607', + { + 0: '29 3f 02 d4 7f 37 c9 b6 33 f2 af 52 85 fe b4 6b', + 16: 'e6 20 f1 39 0d 19 bd 84 e2 e0 fd 75 20 31 af c1', + 240: '91 4f 02 53 1c 92 18 81 0d f6 0f 67 e3 38 15 4c', + 256: 'd0 fd b5 83 07 3c e8 5a b8 39 17 74 0e c0 11 d5', + 496: '75 f8 14 11 e8 71 cf fa 70 b9 0c 74 c5 92 e4 54', + 512: '0b b8 72 02 93 8d ad 60 9e 87 a5 a1 b0 79 e5 e4', + 752: 'c2 91 12 46 b6 12 e7 e7 b9 03 df ed a1 da d8 66', + 768: '32 82 8f 91 50 2b 62 91 36 8d e8 08 1d e3 6f c2', + 1008: 'f3 b9 a7 e3 b2 97 bf 9a d8 04 51 2f 90 63 ef f1', + 1024: '8e cb 67 a9 ba 1f 55 a5 a0 67 e2 b0 26 a3 67 6f', + 1520: 'd2 aa 90 2b d4 2d 0d 7c fd 34 0c d4 58 10 52 9f', + 1536: '78 b2 72 c9 6e 42 ea b4 c6 0b d9 14 e3 9d 06 e3', + 2032: 'f4 33 2f d3 1a 07 93 96 ee 3c ee 3f 2a 4f f0 49', + 2048: '05 45 97 81 d4 1f da 7f 30 c1 be 7e 12 46 c6 23', + 3056: 'ad fd 38 68 b8 e5 14 85 d5 e6 10 01 7e 3d d6 09', + 3072: 'ad 26 58 1c 0c 5b e4 5f 4c ea 01 db 2f 38 05 d5', + 4080: 'f3 17 2c ef fc 3b 3d 99 7c 85 cc d5 af 1a 95 0c', + 4096: 'e7 4b 0b 97 31 22 7f d3 7c 0e c0 8a 47 dd d8 b8' + } + ), + ( + '0102030405060708', + { + 0: '97 ab 8a 1b f0 af b9 61 32 f2 f6 72 58 da 15 a8', + 16: '82 63 ef db 45 c4 a1 86 84 ef 87 e6 b1 9e 5b 09', + 240: '96 36 eb c9 84 19 26 f4 f7 d1 f3 62 bd df 6e 18', + 256: 'd0 a9 90 ff 2c 05 fe f5 b9 03 73 c9 ff 4b 87 0a', + 496: '73 23 9f 1d b7 f4 1d 80 b6 43 c0 c5 25 18 ec 63', + 512: '16 3b 31 99 23 a6 bd b4 52 7c 62 61 26 70 3c 0f', + 752: '49 d6 c8 af 0f 97 14 4a 87 df 21 d9 14 72 f9 66', + 768: '44 17 3a 10 3b 66 16 c5 d5 ad 1c ee 40 c8 63 d0', + 1008: '27 3c 9c 4b 27 f3 22 e4 e7 16 ef 53 a4 7d e7 a4', + 1024: 'c6 d0 e7 b2 26 25 9f a9 02 34 90 b2 61 67 ad 1d', + 1520: '1f e8 98 67 13 f0 7c 3d 9a e1 c1 63 ff 8c f9 d3', + 1536: '83 69 e1 a9 65 61 0b e8 87 fb d0 c7 91 62 aa fb', + 2032: '0a 01 27 ab b4 44 84 b9 fb ef 5a bc ae 1b 57 9f', + 2048: 'c2 cd ad c6 40 2e 8e e8 66 e1 f3 7b db 47 e4 2c', + 3056: '26 b5 1e a3 7d f8 e1 d6 f7 6f c3 b6 6a 74 29 b3', + 3072: 'bc 76 83 20 5d 4f 44 3d c1 f2 9d da 33 15 c8 7b', + 4080: 'd5 fa 5a 34 69 d2 9a aa f8 3d 23 58 9d b8 c8 5b', + 4096: '3f b4 6e 2c 8f 0f 06 8e dc e8 cd cd 7d fc 58 62' + } + ), + # Page 5 + ( + '0102030405060708090a', + { + 0: 'ed e3 b0 46 43 e5 86 cc 90 7d c2 18 51 70 99 02', + 16: '03 51 6b a7 8f 41 3b eb 22 3a a5 d4 d2 df 67 11', + 240: '3c fd 6c b5 8e e0 fd de 64 01 76 ad 00 00 04 4d', + 256: '48 53 2b 21 fb 60 79 c9 11 4c 0f fd 9c 04 a1 ad', + 496: '3e 8c ea 98 01 71 09 97 90 84 b1 ef 92 f9 9d 86', + 512: 'e2 0f b4 9b db 33 7e e4 8b 8d 8d c0 f4 af ef fe', + 752: '5c 25 21 ea cd 79 66 f1 5e 05 65 44 be a0 d3 15', + 768: 'e0 67 a7 03 19 31 a2 46 a6 c3 87 5d 2f 67 8a cb', + 1008: 'a6 4f 70 af 88 ae 56 b6 f8 75 81 c0 e2 3e 6b 08', + 1024: 'f4 49 03 1d e3 12 81 4e c6 f3 19 29 1f 4a 05 16', + 1520: 'bd ae 85 92 4b 3c b1 d0 a2 e3 3a 30 c6 d7 95 99', + 1536: '8a 0f ed db ac 86 5a 09 bc d1 27 fb 56 2e d6 0a', + 2032: 'b5 5a 0a 5b 51 a1 2a 8b e3 48 99 c3 e0 47 51 1a', + 2048: 'd9 a0 9c ea 3c e7 5f e3 96 98 07 03 17 a7 13 39', + 3056: '55 22 25 ed 11 77 f4 45 84 ac 8c fa 6c 4e b5 fc', + 3072: '7e 82 cb ab fc 95 38 1b 08 09 98 44 21 29 c2 f8', + 4080: '1f 13 5e d1 4c e6 0a 91 36 9d 23 22 be f2 5e 3c', + 4096: '08 b6 be 45 12 4a 43 e2 eb 77 95 3f 84 dc 85 53' + } + ), + ( + '0102030405060708090a0b0c0d0e0f10', + { + 0: '9a c7 cc 9a 60 9d 1e f7 b2 93 28 99 cd e4 1b 97', + 16: '52 48 c4 95 90 14 12 6a 6e 8a 84 f1 1d 1a 9e 1c', + 240: '06 59 02 e4 b6 20 f6 cc 36 c8 58 9f 66 43 2f 2b', + 256: 'd3 9d 56 6b c6 bc e3 01 07 68 15 15 49 f3 87 3f', + 496: 'b6 d1 e6 c4 a5 e4 77 1c ad 79 53 8d f2 95 fb 11', + 512: 'c6 8c 1d 5c 55 9a 97 41 23 df 1d bc 52 a4 3b 89', + 752: 'c5 ec f8 8d e8 97 fd 57 fe d3 01 70 1b 82 a2 59', + 768: 'ec cb e1 3d e1 fc c9 1c 11 a0 b2 6c 0b c8 fa 4d', + 1008: 'e7 a7 25 74 f8 78 2a e2 6a ab cf 9e bc d6 60 65', + 1024: 'bd f0 32 4e 60 83 dc c6 d3 ce dd 3c a8 c5 3c 16', + 1520: 'b4 01 10 c4 19 0b 56 22 a9 61 16 b0 01 7e d2 97', + 1536: 'ff a0 b5 14 64 7e c0 4f 63 06 b8 92 ae 66 11 81', + 2032: 'd0 3d 1b c0 3c d3 3d 70 df f9 fa 5d 71 96 3e bd', + 2048: '8a 44 12 64 11 ea a7 8b d5 1e 8d 87 a8 87 9b f5', + 3056: 'fa be b7 60 28 ad e2 d0 e4 87 22 e4 6c 46 15 a3', + 3072: 'c0 5d 88 ab d5 03 57 f9 35 a6 3c 59 ee 53 76 23', + 4080: 'ff 38 26 5c 16 42 c1 ab e8 d3 c2 fe 5e 57 2b f8', + 4096: 'a3 6a 4c 30 1a e8 ac 13 61 0c cb c1 22 56 ca cc' + } + ), + # Page 6 + ( + '0102030405060708090a0b0c0d0e0f101112131415161718', + { + 0: '05 95 e5 7f e5 f0 bb 3c 70 6e da c8 a4 b2 db 11', + 16: 'df de 31 34 4a 1a f7 69 c7 4f 07 0a ee 9e 23 26', + 240: 'b0 6b 9b 1e 19 5d 13 d8 f4 a7 99 5c 45 53 ac 05', + 256: '6b d2 37 8e c3 41 c9 a4 2f 37 ba 79 f8 8a 32 ff', + 496: 'e7 0b ce 1d f7 64 5a db 5d 2c 41 30 21 5c 35 22', + 512: '9a 57 30 c7 fc b4 c9 af 51 ff da 89 c7 f1 ad 22', + 752: '04 85 05 5f d4 f6 f0 d9 63 ef 5a b9 a5 47 69 82', + 768: '59 1f c6 6b cd a1 0e 45 2b 03 d4 55 1f 6b 62 ac', + 1008: '27 53 cc 83 98 8a fa 3e 16 88 a1 d3 b4 2c 9a 02', + 1024: '93 61 0d 52 3d 1d 3f 00 62 b3 c2 a3 bb c7 c7 f0', + 1520: '96 c2 48 61 0a ad ed fe af 89 78 c0 3d e8 20 5a', + 1536: '0e 31 7b 3d 1c 73 b9 e9 a4 68 8f 29 6d 13 3a 19', + 2032: 'bd f0 e6 c3 cc a5 b5 b9 d5 33 b6 9c 56 ad a1 20', + 2048: '88 a2 18 b6 e2 ec e1 e6 24 6d 44 c7 59 d1 9b 10', + 3056: '68 66 39 7e 95 c1 40 53 4f 94 26 34 21 00 6e 40', + 3072: '32 cb 0a 1e 95 42 c6 b3 b8 b3 98 ab c3 b0 f1 d5', + 4080: '29 a0 b8 ae d5 4a 13 23 24 c6 2e 42 3f 54 b4 c8', + 4096: '3c b0 f3 b5 02 0a 98 b8 2a f9 fe 15 44 84 a1 68' + } + ), + ( + '0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20', + { + 0: 'ea a6 bd 25 88 0b f9 3d 3f 5d 1e 4c a2 61 1d 91', + 16: 'cf a4 5c 9f 7e 71 4b 54 bd fa 80 02 7c b1 43 80', + 240: '11 4a e3 44 de d7 1b 35 f2 e6 0f eb ad 72 7f d8', + 256: '02 e1 e7 05 6b 0f 62 39 00 49 64 22 94 3e 97 b6', + 496: '91 cb 93 c7 87 96 4e 10 d9 52 7d 99 9c 6f 93 6b', + 512: '49 b1 8b 42 f8 e8 36 7c be b5 ef 10 4b a1 c7 cd', + 752: '87 08 4b 3b a7 00 ba de 95 56 10 67 27 45 b3 74', + 768: 'e7 a7 b9 e9 ec 54 0d 5f f4 3b db 12 79 2d 1b 35', + 1008: 'c7 99 b5 96 73 8f 6b 01 8c 76 c7 4b 17 59 bd 90', + 1024: '7f ec 5b fd 9f 9b 89 ce 65 48 30 90 92 d7 e9 58', + 1520: '40 f2 50 b2 6d 1f 09 6a 4a fd 4c 34 0a 58 88 15', + 1536: '3e 34 13 5c 79 db 01 02 00 76 76 51 cf 26 30 73', + 2032: 'f6 56 ab cc f8 8d d8 27 02 7b 2c e9 17 d4 64 ec', + 2048: '18 b6 25 03 bf bc 07 7f ba bb 98 f2 0d 98 ab 34', + 3056: '8a ed 95 ee 5b 0d cb fb ef 4e b2 1d 3a 3f 52 f9', + 3072: '62 5a 1a b0 0e e3 9a 53 27 34 6b dd b0 1a 9c 18', + 4080: 'a1 3a 7c 79 c7 e1 19 b5 ab 02 96 ab 28 c3 00 b9', + 4096: 'f3 e4 c0 a2 e0 2d 1d 01 f7 f0 a7 46 18 af 2b 48' + } + ), + # Page 7 + ( + '833222772a', + { + 0: '80 ad 97 bd c9 73 df 8a 2e 87 9e 92 a4 97 ef da', + 16: '20 f0 60 c2 f2 e5 12 65 01 d3 d4 fe a1 0d 5f c0', + 240: 'fa a1 48 e9 90 46 18 1f ec 6b 20 85 f3 b2 0e d9', + 256: 'f0 da f5 ba b3 d5 96 83 98 57 84 6f 73 fb fe 5a', + 496: '1c 7e 2f c4 63 92 32 fe 29 75 84 b2 96 99 6b c8', + 512: '3d b9 b2 49 40 6c c8 ed ff ac 55 cc d3 22 ba 12', + 752: 'e4 f9 f7 e0 06 61 54 bb d1 25 b7 45 56 9b c8 97', + 768: '75 d5 ef 26 2b 44 c4 1a 9c f6 3a e1 45 68 e1 b9', + 1008: '6d a4 53 db f8 1e 82 33 4a 3d 88 66 cb 50 a1 e3', + 1024: '78 28 d0 74 11 9c ab 5c 22 b2 94 d7 a9 bf a0 bb', + 1520: 'ad b8 9c ea 9a 15 fb e6 17 29 5b d0 4b 8c a0 5c', + 1536: '62 51 d8 7f d4 aa ae 9a 7e 4a d5 c2 17 d3 f3 00', + 2032: 'e7 11 9b d6 dd 9b 22 af e8 f8 95 85 43 28 81 e2', + 2048: '78 5b 60 fd 7e c4 e9 fc b6 54 5f 35 0d 66 0f ab', + 3056: 'af ec c0 37 fd b7 b0 83 8e b3 d7 0b cd 26 83 82', + 3072: 'db c1 a7 b4 9d 57 35 8c c9 fa 6d 61 d7 3b 7c f0', + 4080: '63 49 d1 26 a3 7a fc ba 89 79 4f 98 04 91 4f dc', + 4096: 'bf 42 c3 01 8c 2f 7c 66 bf de 52 49 75 76 81 15' + } + ), + ( + '1910833222772a', + { + 0: 'bc 92 22 db d3 27 4d 8f c6 6d 14 cc bd a6 69 0b', + 16: '7a e6 27 41 0c 9a 2b e6 93 df 5b b7 48 5a 63 e3', + 240: '3f 09 31 aa 03 de fb 30 0f 06 01 03 82 6f 2a 64', + 256: 'be aa 9e c8 d5 9b b6 81 29 f3 02 7c 96 36 11 81', + 496: '74 e0 4d b4 6d 28 64 8d 7d ee 8a 00 64 b0 6c fe', + 512: '9b 5e 81 c6 2f e0 23 c5 5b e4 2f 87 bb f9 32 b8', + 752: 'ce 17 8f c1 82 6e fe cb c1 82 f5 79 99 a4 61 40', + 768: '8b df 55 cd 55 06 1c 06 db a6 be 11 de 4a 57 8a', + 1008: '62 6f 5f 4d ce 65 25 01 f3 08 7d 39 c9 2c c3 49', + 1024: '42 da ac 6a 8f 9a b9 a7 fd 13 7c 60 37 82 56 82', + 1520: 'cc 03 fd b7 91 92 a2 07 31 2f 53 f5 d4 dc 33 d9', + 1536: 'f7 0f 14 12 2a 1c 98 a3 15 5d 28 b8 a0 a8 a4 1d', + 2032: '2a 3a 30 7a b2 70 8a 9c 00 fe 0b 42 f9 c2 d6 a1', + 2048: '86 26 17 62 7d 22 61 ea b0 b1 24 65 97 ca 0a e9', + 3056: '55 f8 77 ce 4f 2e 1d db bf 8e 13 e2 cd e0 fd c8', + 3072: '1b 15 56 cb 93 5f 17 33 37 70 5f bb 5d 50 1f c1', + 4080: 'ec d0 e9 66 02 be 7f 8d 50 92 81 6c cc f2 c2 e9', + 4096: '02 78 81 fa b4 99 3a 1c 26 20 24 a9 4f ff 3f 61' + } + ), + # Page 8 + ( + '641910833222772a', + { + 0: 'bb f6 09 de 94 13 17 2d 07 66 0c b6 80 71 69 26', + 16: '46 10 1a 6d ab 43 11 5d 6c 52 2b 4f e9 36 04 a9', + 240: 'cb e1 ff f2 1c 96 f3 ee f6 1e 8f e0 54 2c bd f0', + 256: '34 79 38 bf fa 40 09 c5 12 cf b4 03 4b 0d d1 a7', + 496: '78 67 a7 86 d0 0a 71 47 90 4d 76 dd f1 e5 20 e3', + 512: '8d 3e 9e 1c ae fc cc b3 fb f8 d1 8f 64 12 0b 32', + 752: '94 23 37 f8 fd 76 f0 fa e8 c5 2d 79 54 81 06 72', + 768: 'b8 54 8c 10 f5 16 67 f6 e6 0e 18 2f a1 9b 30 f7', + 1008: '02 11 c7 c6 19 0c 9e fd 12 37 c3 4c 8f 2e 06 c4', + 1024: 'bd a6 4f 65 27 6d 2a ac b8 f9 02 12 20 3a 80 8e', + 1520: 'bd 38 20 f7 32 ff b5 3e c1 93 e7 9d 33 e2 7c 73', + 1536: 'd0 16 86 16 86 19 07 d4 82 e3 6c da c8 cf 57 49', + 2032: '97 b0 f0 f2 24 b2 d2 31 71 14 80 8f b0 3a f7 a0', + 2048: 'e5 96 16 e4 69 78 79 39 a0 63 ce ea 9a f9 56 d1', + 3056: 'c4 7e 0d c1 66 09 19 c1 11 01 20 8f 9e 69 aa 1f', + 3072: '5a e4 f1 28 96 b8 37 9a 2a ad 89 b5 b5 53 d6 b0', + 4080: '6b 6b 09 8d 0c 29 3b c2 99 3d 80 bf 05 18 b6 d9', + 4096: '81 70 cc 3c cd 92 a6 98 62 1b 93 9d d3 8f e7 b9' + } + ), + ( + '8b37641910833222772a', + { + 0: 'ab 65 c2 6e dd b2 87 60 0d b2 fd a1 0d 1e 60 5c', + 16: 'bb 75 90 10 c2 96 58 f2 c7 2d 93 a2 d1 6d 29 30', + 240: 'b9 01 e8 03 6e d1 c3 83 cd 3c 4c 4d d0 a6 ab 05', + 256: '3d 25 ce 49 22 92 4c 55 f0 64 94 33 53 d7 8a 6c', + 496: '12 c1 aa 44 bb f8 7e 75 e6 11 f6 9b 2c 38 f4 9b', + 512: '28 f2 b3 43 4b 65 c0 98 77 47 00 44 c6 ea 17 0d', + 752: 'bd 9e f8 22 de 52 88 19 61 34 cf 8a f7 83 93 04', + 768: '67 55 9c 23 f0 52 15 84 70 a2 96 f7 25 73 5a 32', + 1008: '8b ab 26 fb c2 c1 2b 0f 13 e2 ab 18 5e ab f2 41', + 1024: '31 18 5a 6d 69 6f 0c fa 9b 42 80 8b 38 e1 32 a2', + 1520: '56 4d 3d ae 18 3c 52 34 c8 af 1e 51 06 1c 44 b5', + 1536: '3c 07 78 a7 b5 f7 2d 3c 23 a3 13 5c 7d 67 b9 f4', + 2032: 'f3 43 69 89 0f cf 16 fb 51 7d ca ae 44 63 b2 dd', + 2048: '02 f3 1c 81 e8 20 07 31 b8 99 b0 28 e7 91 bf a7', + 3056: '72 da 64 62 83 22 8c 14 30 08 53 70 17 95 61 6f', + 3072: '4e 0a 8c 6f 79 34 a7 88 e2 26 5e 81 d6 d0 c8 f4', + 4080: '43 8d d5 ea fe a0 11 1b 6f 36 b4 b9 38 da 2a 68', + 4096: '5f 6b fc 73 81 58 74 d9 71 00 f0 86 97 93 57 d8' + } + ), + # Page 9 + ( + 'ebb46227c6cc8b37641910833222772a', + { + 0: '72 0c 94 b6 3e df 44 e1 31 d9 50 ca 21 1a 5a 30', + 16: 'c3 66 fd ea cf 9c a8 04 36 be 7c 35 84 24 d2 0b', + 240: 'b3 39 4a 40 aa bf 75 cb a4 22 82 ef 25 a0 05 9f', + 256: '48 47 d8 1d a4 94 2d bc 24 9d ef c4 8c 92 2b 9f', + 496: '08 12 8c 46 9f 27 53 42 ad da 20 2b 2b 58 da 95', + 512: '97 0d ac ef 40 ad 98 72 3b ac 5d 69 55 b8 17 61', + 752: '3c b8 99 93 b0 7b 0c ed 93 de 13 d2 a1 10 13 ac', + 768: 'ef 2d 67 6f 15 45 c2 c1 3d c6 80 a0 2f 4a db fe', + 1008: 'b6 05 95 51 4f 24 bc 9f e5 22 a6 ca d7 39 36 44', + 1024: 'b5 15 a8 c5 01 17 54 f5 90 03 05 8b db 81 51 4e', + 1520: '3c 70 04 7e 8c bc 03 8e 3b 98 20 db 60 1d a4 95', + 1536: '11 75 da 6e e7 56 de 46 a5 3e 2b 07 56 60 b7 70', + 2032: '00 a5 42 bb a0 21 11 cc 2c 65 b3 8e bd ba 58 7e', + 2048: '58 65 fd bb 5b 48 06 41 04 e8 30 b3 80 f2 ae de', + 3056: '34 b2 1a d2 ad 44 e9 99 db 2d 7f 08 63 f0 d9 b6', + 3072: '84 a9 21 8f c3 6e 8a 5f 2c cf be ae 53 a2 7d 25', + 4080: 'a2 22 1a 11 b8 33 cc b4 98 a5 95 40 f0 54 5f 4a', + 4096: '5b be b4 78 7d 59 e5 37 3f db ea 6c 6f 75 c2 9b' + } + ), + ( + 'c109163908ebe51debb46227c6cc8b37641910833222772a', + { + 0: '54 b6 4e 6b 5a 20 b5 e2 ec 84 59 3d c7 98 9d a7', + 16: 'c1 35 ee e2 37 a8 54 65 ff 97 dc 03 92 4f 45 ce', + 240: 'cf cc 92 2f b4 a1 4a b4 5d 61 75 aa bb f2 d2 01', + 256: '83 7b 87 e2 a4 46 ad 0e f7 98 ac d0 2b 94 12 4f', + 496: '17 a6 db d6 64 92 6a 06 36 b3 f4 c3 7a 4f 46 94', + 512: '4a 5f 9f 26 ae ee d4 d4 a2 5f 63 2d 30 52 33 d9', + 752: '80 a3 d0 1e f0 0c 8e 9a 42 09 c1 7f 4e eb 35 8c', + 768: 'd1 5e 7d 5f fa aa bc 02 07 bf 20 0a 11 77 93 a2', + 1008: '34 96 82 bf 58 8e aa 52 d0 aa 15 60 34 6a ea fa', + 1024: 'f5 85 4c db 76 c8 89 e3 ad 63 35 4e 5f 72 75 e3', + 1520: '53 2c 7c ec cb 39 df 32 36 31 84 05 a4 b1 27 9c', + 1536: 'ba ef e6 d9 ce b6 51 84 22 60 e0 d1 e0 5e 3b 90', + 2032: 'e8 2d 8c 6d b5 4e 3c 63 3f 58 1c 95 2b a0 42 07', + 2048: '4b 16 e5 0a bd 38 1b d7 09 00 a9 cd 9a 62 cb 23', + 3056: '36 82 ee 33 bd 14 8b d9 f5 86 56 cd 8f 30 d9 fb', + 3072: '1e 5a 0b 84 75 04 5d 9b 20 b2 62 86 24 ed fd 9e', + 4080: '63 ed d6 84 fb 82 62 82 fe 52 8f 9c 0e 92 37 bc', + 4096: 'e4 dd 2e 98 d6 96 0f ae 0b 43 54 54 56 74 33 91' + } + ), + # Page 10 + ( + '1ada31d5cf688221c109163908ebe51debb46227c6cc8b37641910833222772a', + { + 0: 'dd 5b cb 00 18 e9 22 d4 94 75 9d 7c 39 5d 02 d3', + 16: 'c8 44 6f 8f 77 ab f7 37 68 53 53 eb 89 a1 c9 eb', + 240: 'af 3e 30 f9 c0 95 04 59 38 15 15 75 c3 fb 90 98', + 256: 'f8 cb 62 74 db 99 b8 0b 1d 20 12 a9 8e d4 8f 0e', + 496: '25 c3 00 5a 1c b8 5d e0 76 25 98 39 ab 71 98 ab', + 512: '9d cb c1 83 e8 cb 99 4b 72 7b 75 be 31 80 76 9c', + 752: 'a1 d3 07 8d fa 91 69 50 3e d9 d4 49 1d ee 4e b2', + 768: '85 14 a5 49 58 58 09 6f 59 6e 4b cd 66 b1 06 65', + 1008: '5f 40 d5 9e c1 b0 3b 33 73 8e fa 60 b2 25 5d 31', + 1024: '34 77 c7 f7 64 a4 1b ac ef f9 0b f1 4f 92 b7 cc', + 1520: 'ac 4e 95 36 8d 99 b9 eb 78 b8 da 8f 81 ff a7 95', + 1536: '8c 3c 13 f8 c2 38 8b b7 3f 38 57 6e 65 b7 c4 46', + 2032: '13 c4 b9 c1 df b6 65 79 ed dd 8a 28 0b 9f 73 16', + 2048: 'dd d2 78 20 55 01 26 69 8e fa ad c6 4b 64 f6 6e', + 3056: 'f0 8f 2e 66 d2 8e d1 43 f3 a2 37 cf 9d e7 35 59', + 3072: '9e a3 6c 52 55 31 b8 80 ba 12 43 34 f5 7b 0b 70', + 4080: 'd5 a3 9e 3d fc c5 02 80 ba c4 a6 b5 aa 0d ca 7d', + 4096: '37 0b 1c 1f e6 55 91 6d 97 fd 0d 47 ca 1d 72 b8' + } + ) + ] + + def test_keystream(self): + for tv in self.rfc6229_data: + key = unhexlify(b((tv[0]))) + cipher = ARC4.new(key) + count = 0 + for offset in range(0, 4096+1, 16): + ct = cipher.encrypt(b('\x00')*16) + expected = tv[1].get(offset) + if expected: + expected = unhexlify(b(expected.replace(" ", ''))) + self.assertEqual(ct, expected) + count += 1 + self.assertEqual(count, len(tv[1])) + + +class Drop_Tests(unittest.TestCase): + key = b('\xAA')*16 + data = b('\x00')*5000 + + def setUp(self): + self.cipher = ARC4.new(self.key) + + def test_drop256_encrypt(self): + cipher_drop = ARC4.new(self.key, 256) + ct_drop = cipher_drop.encrypt(self.data[:16]) + ct = self.cipher.encrypt(self.data)[256:256+16] + self.assertEqual(ct_drop, ct) + + def test_drop256_decrypt(self): + cipher_drop = ARC4.new(self.key, 256) + pt_drop = cipher_drop.decrypt(self.data[:16]) + pt = self.cipher.decrypt(self.data)[256:256+16] + self.assertEqual(pt_drop, pt) + + +class KeyLength(unittest.TestCase): + + def runTest(self): + self.assertRaises(ValueError, ARC4.new, b'') + self.assertRaises(ValueError, ARC4.new, b'\x00' * 257) + + +def get_tests(config={}): + from .common import make_stream_tests + tests = make_stream_tests(ARC4, "ARC4", test_data) + tests += list_test_cases(RFC6229_Tests) + tests += list_test_cases(Drop_Tests) + tests.append(KeyLength()) + return tests + + +if __name__ == '__main__': + def suite(): + return unittest.TestSuite(get_tests()) + unittest.main(defaultTest='suite') diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/test_Blowfish.py b/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/test_Blowfish.py new file mode 100644 index 0000000..ca5c603 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/test_Blowfish.py @@ -0,0 +1,160 @@ +# -*- coding: utf-8 -*- +# +# SelfTest/Cipher/test_Blowfish.py: Self-test for the Blowfish cipher +# +# Written in 2008 by Dwayne C. Litzenberger +# +# =================================================================== +# The contents of this file are dedicated to the public domain. To +# the extent that dedication to the public domain is not available, +# everyone is granted a worldwide, perpetual, royalty-free, +# non-exclusive license to exercise all rights associated with the +# contents of this file for any purpose whatsoever. +# No rights are reserved. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# =================================================================== + +"""Self-test suite for Cryptodome.Cipher.Blowfish""" + +import unittest + +from Cryptodome.Util.py3compat import bchr + +from Cryptodome.Cipher import Blowfish + +# This is a list of (plaintext, ciphertext, key) tuples. +test_data = [ + # Test vectors from http://www.schneier.com/code/vectors.txt + ('0000000000000000', '4ef997456198dd78', '0000000000000000'), + ('ffffffffffffffff', '51866fd5b85ecb8a', 'ffffffffffffffff'), + ('1000000000000001', '7d856f9a613063f2', '3000000000000000'), + ('1111111111111111', '2466dd878b963c9d', '1111111111111111'), + ('1111111111111111', '61f9c3802281b096', '0123456789abcdef'), + ('0123456789abcdef', '7d0cc630afda1ec7', '1111111111111111'), + ('0000000000000000', '4ef997456198dd78', '0000000000000000'), + ('0123456789abcdef', '0aceab0fc6a0a28d', 'fedcba9876543210'), + ('01a1d6d039776742', '59c68245eb05282b', '7ca110454a1a6e57'), + ('5cd54ca83def57da', 'b1b8cc0b250f09a0', '0131d9619dc1376e'), + ('0248d43806f67172', '1730e5778bea1da4', '07a1133e4a0b2686'), + ('51454b582ddf440a', 'a25e7856cf2651eb', '3849674c2602319e'), + ('42fd443059577fa2', '353882b109ce8f1a', '04b915ba43feb5b6'), + ('059b5e0851cf143a', '48f4d0884c379918', '0113b970fd34f2ce'), + ('0756d8e0774761d2', '432193b78951fc98', '0170f175468fb5e6'), + ('762514b829bf486a', '13f04154d69d1ae5', '43297fad38e373fe'), + ('3bdd119049372802', '2eedda93ffd39c79', '07a7137045da2a16'), + ('26955f6835af609a', 'd887e0393c2da6e3', '04689104c2fd3b2f'), + ('164d5e404f275232', '5f99d04f5b163969', '37d06bb516cb7546'), + ('6b056e18759f5cca', '4a057a3b24d3977b', '1f08260d1ac2465e'), + ('004bd6ef09176062', '452031c1e4fada8e', '584023641aba6176'), + ('480d39006ee762f2', '7555ae39f59b87bd', '025816164629b007'), + ('437540c8698f3cfa', '53c55f9cb49fc019', '49793ebc79b3258f'), + ('072d43a077075292', '7a8e7bfa937e89a3', '4fb05e1515ab73a7'), + ('02fe55778117f12a', 'cf9c5d7a4986adb5', '49e95d6d4ca229bf'), + ('1d9d5c5018f728c2', 'd1abb290658bc778', '018310dc409b26d6'), + ('305532286d6f295a', '55cb3774d13ef201', '1c587f1c13924fef'), + ('0123456789abcdef', 'fa34ec4847b268b2', '0101010101010101'), + ('0123456789abcdef', 'a790795108ea3cae', '1f1f1f1f0e0e0e0e'), + ('0123456789abcdef', 'c39e072d9fac631d', 'e0fee0fef1fef1fe'), + ('ffffffffffffffff', '014933e0cdaff6e4', '0000000000000000'), + ('0000000000000000', 'f21e9a77b71c49bc', 'ffffffffffffffff'), + ('0000000000000000', '245946885754369a', '0123456789abcdef'), + ('ffffffffffffffff', '6b5c5a9c5d9e0a5a', 'fedcba9876543210'), + #('fedcba9876543210', 'f9ad597c49db005e', 'f0'), + #('fedcba9876543210', 'e91d21c1d961a6d6', 'f0e1'), + #('fedcba9876543210', 'e9c2b70a1bc65cf3', 'f0e1d2'), + ('fedcba9876543210', 'be1e639408640f05', 'f0e1d2c3'), + ('fedcba9876543210', 'b39e44481bdb1e6e', 'f0e1d2c3b4'), + ('fedcba9876543210', '9457aa83b1928c0d', 'f0e1d2c3b4a5'), + ('fedcba9876543210', '8bb77032f960629d', 'f0e1d2c3b4a596'), + ('fedcba9876543210', 'e87a244e2cc85e82', 'f0e1d2c3b4a59687'), + ('fedcba9876543210', '15750e7a4f4ec577', 'f0e1d2c3b4a5968778'), + ('fedcba9876543210', '122ba70b3ab64ae0', 'f0e1d2c3b4a596877869'), + ('fedcba9876543210', '3a833c9affc537f6', 'f0e1d2c3b4a5968778695a'), + ('fedcba9876543210', '9409da87a90f6bf2', 'f0e1d2c3b4a5968778695a4b'), + ('fedcba9876543210', '884f80625060b8b4', 'f0e1d2c3b4a5968778695a4b3c'), + ('fedcba9876543210', '1f85031c19e11968', 'f0e1d2c3b4a5968778695a4b3c2d'), + ('fedcba9876543210', '79d9373a714ca34f', 'f0e1d2c3b4a5968778695a4b3c2d1e'), + ('fedcba9876543210', '93142887ee3be15c', + 'f0e1d2c3b4a5968778695a4b3c2d1e0f'), + ('fedcba9876543210', '03429e838ce2d14b', + 'f0e1d2c3b4a5968778695a4b3c2d1e0f00'), + ('fedcba9876543210', 'a4299e27469ff67b', + 'f0e1d2c3b4a5968778695a4b3c2d1e0f0011'), + ('fedcba9876543210', 'afd5aed1c1bc96a8', + 'f0e1d2c3b4a5968778695a4b3c2d1e0f001122'), + ('fedcba9876543210', '10851c0e3858da9f', + 'f0e1d2c3b4a5968778695a4b3c2d1e0f00112233'), + ('fedcba9876543210', 'e6f51ed79b9db21f', + 'f0e1d2c3b4a5968778695a4b3c2d1e0f0011223344'), + ('fedcba9876543210', '64a6e14afd36b46f', + 'f0e1d2c3b4a5968778695a4b3c2d1e0f001122334455'), + ('fedcba9876543210', '80c7d7d45a5479ad', + 'f0e1d2c3b4a5968778695a4b3c2d1e0f00112233445566'), + ('fedcba9876543210', '05044b62fa52d080', + 'f0e1d2c3b4a5968778695a4b3c2d1e0f0011223344556677'), +] + + +class KeyLength(unittest.TestCase): + + def runTest(self): + self.assertRaises(ValueError, Blowfish.new, bchr(0) * 3, + Blowfish.MODE_ECB) + self.assertRaises(ValueError, Blowfish.new, bchr(0) * 57, + Blowfish.MODE_ECB) + + +class TestOutput(unittest.TestCase): + + def runTest(self): + # Encrypt/Decrypt data and test output parameter + + cipher = Blowfish.new(b'4'*16, Blowfish.MODE_ECB) + + pt = b'5' * 16 + ct = cipher.encrypt(pt) + + output = bytearray(16) + res = cipher.encrypt(pt, output=output) + self.assertEqual(ct, output) + self.assertEqual(res, None) + + res = cipher.decrypt(ct, output=output) + self.assertEqual(pt, output) + self.assertEqual(res, None) + + output = memoryview(bytearray(16)) + cipher.encrypt(pt, output=output) + self.assertEqual(ct, output) + + cipher.decrypt(ct, output=output) + self.assertEqual(pt, output) + + self.assertRaises(TypeError, cipher.encrypt, pt, output=b'0'*16) + self.assertRaises(TypeError, cipher.decrypt, ct, output=b'0'*16) + + shorter_output = bytearray(7) + self.assertRaises(ValueError, cipher.encrypt, pt, output=shorter_output) + self.assertRaises(ValueError, cipher.decrypt, ct, output=shorter_output) + + +def get_tests(config={}): + from .common import make_block_tests + tests = make_block_tests(Blowfish, "Blowfish", test_data) + tests.append(KeyLength()) + tests += [TestOutput()] + return tests + + +if __name__ == '__main__': + import unittest + suite = lambda: unittest.TestSuite(get_tests()) + unittest.main(defaultTest='suite') diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/test_CAST.py b/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/test_CAST.py new file mode 100644 index 0000000..8bc21fd --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/test_CAST.py @@ -0,0 +1,101 @@ +# -*- coding: utf-8 -*- +# +# SelfTest/Cipher/CAST.py: Self-test for the CAST-128 (CAST5) cipher +# +# Written in 2008 by Dwayne C. Litzenberger +# +# =================================================================== +# The contents of this file are dedicated to the public domain. To +# the extent that dedication to the public domain is not available, +# everyone is granted a worldwide, perpetual, royalty-free, +# non-exclusive license to exercise all rights associated with the +# contents of this file for any purpose whatsoever. +# No rights are reserved. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# =================================================================== + +"""Self-test suite for Cryptodome.Cipher.CAST""" + +import unittest + +from Cryptodome.Util.py3compat import bchr + +from Cryptodome.Cipher import CAST + +# This is a list of (plaintext, ciphertext, key) tuples. +test_data = [ + # Test vectors from RFC 2144, B.1 + ('0123456789abcdef', '238b4fe5847e44b2', + '0123456712345678234567893456789a', + '128-bit key'), + + ('0123456789abcdef', 'eb6a711a2c02271b', + '01234567123456782345', + '80-bit key'), + + ('0123456789abcdef', '7ac816d16e9b302e', + '0123456712', + '40-bit key'), +] + + +class KeyLength(unittest.TestCase): + + def runTest(self): + self.assertRaises(ValueError, CAST.new, bchr(0) * 4, CAST.MODE_ECB) + self.assertRaises(ValueError, CAST.new, bchr(0) * 17, CAST.MODE_ECB) + + +class TestOutput(unittest.TestCase): + + def runTest(self): + # Encrypt/Decrypt data and test output parameter + + cipher = CAST.new(b'4'*16, CAST.MODE_ECB) + + pt = b'5' * 16 + ct = cipher.encrypt(pt) + + output = bytearray(16) + res = cipher.encrypt(pt, output=output) + self.assertEqual(ct, output) + self.assertEqual(res, None) + + res = cipher.decrypt(ct, output=output) + self.assertEqual(pt, output) + self.assertEqual(res, None) + + output = memoryview(bytearray(16)) + cipher.encrypt(pt, output=output) + self.assertEqual(ct, output) + + cipher.decrypt(ct, output=output) + self.assertEqual(pt, output) + + self.assertRaises(TypeError, cipher.encrypt, pt, output=b'0'*16) + self.assertRaises(TypeError, cipher.decrypt, ct, output=b'0'*16) + + shorter_output = bytearray(7) + self.assertRaises(ValueError, cipher.encrypt, pt, output=shorter_output) + self.assertRaises(ValueError, cipher.decrypt, ct, output=shorter_output) + + +def get_tests(config={}): + from .common import make_block_tests + + tests = make_block_tests(CAST, "CAST", test_data) + tests.append(KeyLength()) + tests.append(TestOutput()) + return tests + +if __name__ == '__main__': + suite = lambda: unittest.TestSuite(get_tests()) + unittest.main(defaultTest='suite') diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/test_CBC.py b/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/test_CBC.py new file mode 100644 index 0000000..f118eb6 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/test_CBC.py @@ -0,0 +1,556 @@ +# =================================================================== +# +# Copyright (c) 2014, Legrandin +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# =================================================================== + +import unittest +from binascii import unhexlify + +from Cryptodome.SelfTest.loader import load_test_vectors +from Cryptodome.SelfTest.st_common import list_test_cases +from Cryptodome.Util.py3compat import tobytes, is_string +from Cryptodome.Cipher import AES, DES3, DES +from Cryptodome.Hash import SHAKE128 + + +def get_tag_random(tag, length): + return SHAKE128.new(data=tobytes(tag)).read(length) + +class BlockChainingTests(unittest.TestCase): + + key_128 = get_tag_random("key_128", 16) + key_192 = get_tag_random("key_192", 24) + iv_128 = get_tag_random("iv_128", 16) + iv_64 = get_tag_random("iv_64", 8) + data_128 = get_tag_random("data_128", 16) + + def test_loopback_128(self): + cipher = AES.new(self.key_128, self.aes_mode, self.iv_128) + pt = get_tag_random("plaintext", 16 * 100) + ct = cipher.encrypt(pt) + + cipher = AES.new(self.key_128, self.aes_mode, self.iv_128) + pt2 = cipher.decrypt(ct) + self.assertEqual(pt, pt2) + + def test_loopback_64(self): + cipher = DES3.new(self.key_192, self.des3_mode, self.iv_64) + pt = get_tag_random("plaintext", 8 * 100) + ct = cipher.encrypt(pt) + + cipher = DES3.new(self.key_192, self.des3_mode, self.iv_64) + pt2 = cipher.decrypt(ct) + self.assertEqual(pt, pt2) + + def test_iv(self): + # If not passed, the iv is created randomly + cipher = AES.new(self.key_128, self.aes_mode) + iv1 = cipher.iv + cipher = AES.new(self.key_128, self.aes_mode) + iv2 = cipher.iv + self.assertNotEqual(iv1, iv2) + self.assertEqual(len(iv1), 16) + + # IV can be passed in uppercase or lowercase + cipher = AES.new(self.key_128, self.aes_mode, self.iv_128) + ct = cipher.encrypt(self.data_128) + + cipher = AES.new(self.key_128, self.aes_mode, iv=self.iv_128) + self.assertEqual(ct, cipher.encrypt(self.data_128)) + + cipher = AES.new(self.key_128, self.aes_mode, IV=self.iv_128) + self.assertEqual(ct, cipher.encrypt(self.data_128)) + + def test_iv_must_be_bytes(self): + self.assertRaises(TypeError, AES.new, self.key_128, self.aes_mode, + iv = u'test1234567890-*') + + def test_only_one_iv(self): + # Only one IV/iv keyword allowed + self.assertRaises(TypeError, AES.new, self.key_128, self.aes_mode, + iv=self.iv_128, IV=self.iv_128) + + def test_iv_with_matching_length(self): + self.assertRaises(ValueError, AES.new, self.key_128, self.aes_mode, + b"") + self.assertRaises(ValueError, AES.new, self.key_128, self.aes_mode, + self.iv_128[:15]) + self.assertRaises(ValueError, AES.new, self.key_128, self.aes_mode, + self.iv_128 + b"0") + + def test_block_size_128(self): + cipher = AES.new(self.key_128, self.aes_mode, self.iv_128) + self.assertEqual(cipher.block_size, AES.block_size) + + def test_block_size_64(self): + cipher = DES3.new(self.key_192, self.des3_mode, self.iv_64) + self.assertEqual(cipher.block_size, DES3.block_size) + + def test_unaligned_data_128(self): + cipher = AES.new(self.key_128, self.aes_mode, self.iv_128) + for wrong_length in range(1,16): + self.assertRaises(ValueError, cipher.encrypt, b"5" * wrong_length) + + cipher = AES.new(self.key_128, self.aes_mode, self.iv_128) + for wrong_length in range(1,16): + self.assertRaises(ValueError, cipher.decrypt, b"5" * wrong_length) + + def test_unaligned_data_64(self): + cipher = DES3.new(self.key_192, self.des3_mode, self.iv_64) + for wrong_length in range(1,8): + self.assertRaises(ValueError, cipher.encrypt, b"5" * wrong_length) + + cipher = DES3.new(self.key_192, self.des3_mode, self.iv_64) + for wrong_length in range(1,8): + self.assertRaises(ValueError, cipher.decrypt, b"5" * wrong_length) + + def test_IV_iv_attributes(self): + data = get_tag_random("data", 16 * 100) + for func in "encrypt", "decrypt": + cipher = AES.new(self.key_128, self.aes_mode, self.iv_128) + getattr(cipher, func)(data) + self.assertEqual(cipher.iv, self.iv_128) + self.assertEqual(cipher.IV, self.iv_128) + + def test_unknown_parameters(self): + self.assertRaises(TypeError, AES.new, self.key_128, self.aes_mode, + self.iv_128, 7) + self.assertRaises(TypeError, AES.new, self.key_128, self.aes_mode, + iv=self.iv_128, unknown=7) + # But some are only known by the base cipher (e.g. use_aesni consumed by the AES module) + AES.new(self.key_128, self.aes_mode, iv=self.iv_128, use_aesni=False) + + def test_null_encryption_decryption(self): + for func in "encrypt", "decrypt": + cipher = AES.new(self.key_128, self.aes_mode, self.iv_128) + result = getattr(cipher, func)(b"") + self.assertEqual(result, b"") + + def test_either_encrypt_or_decrypt(self): + cipher = AES.new(self.key_128, self.aes_mode, self.iv_128) + cipher.encrypt(b"") + self.assertRaises(TypeError, cipher.decrypt, b"") + + cipher = AES.new(self.key_128, self.aes_mode, self.iv_128) + cipher.decrypt(b"") + self.assertRaises(TypeError, cipher.encrypt, b"") + + def test_data_must_be_bytes(self): + cipher = AES.new(self.key_128, self.aes_mode, self.iv_128) + self.assertRaises(TypeError, cipher.encrypt, u'test1234567890-*') + + cipher = AES.new(self.key_128, self.aes_mode, self.iv_128) + self.assertRaises(TypeError, cipher.decrypt, u'test1234567890-*') + + def test_bytearray(self): + data = b"1" * 128 + data_ba = bytearray(data) + + # Encrypt + key_ba = bytearray(self.key_128) + iv_ba = bytearray(self.iv_128) + + cipher1 = AES.new(self.key_128, self.aes_mode, self.iv_128) + ref1 = cipher1.encrypt(data) + + cipher2 = AES.new(key_ba, self.aes_mode, iv_ba) + key_ba[:3] = b'\xFF\xFF\xFF' + iv_ba[:3] = b'\xFF\xFF\xFF' + ref2 = cipher2.encrypt(data_ba) + + self.assertEqual(ref1, ref2) + self.assertEqual(cipher1.iv, cipher2.iv) + + # Decrypt + key_ba = bytearray(self.key_128) + iv_ba = bytearray(self.iv_128) + + cipher3 = AES.new(self.key_128, self.aes_mode, self.iv_128) + ref3 = cipher3.decrypt(data) + + cipher4 = AES.new(key_ba, self.aes_mode, iv_ba) + key_ba[:3] = b'\xFF\xFF\xFF' + iv_ba[:3] = b'\xFF\xFF\xFF' + ref4 = cipher4.decrypt(data_ba) + + self.assertEqual(ref3, ref4) + + def test_memoryview(self): + data = b"1" * 128 + data_mv = memoryview(bytearray(data)) + + # Encrypt + key_mv = memoryview(bytearray(self.key_128)) + iv_mv = memoryview(bytearray(self.iv_128)) + + cipher1 = AES.new(self.key_128, self.aes_mode, self.iv_128) + ref1 = cipher1.encrypt(data) + + cipher2 = AES.new(key_mv, self.aes_mode, iv_mv) + key_mv[:3] = b'\xFF\xFF\xFF' + iv_mv[:3] = b'\xFF\xFF\xFF' + ref2 = cipher2.encrypt(data_mv) + + self.assertEqual(ref1, ref2) + self.assertEqual(cipher1.iv, cipher2.iv) + + # Decrypt + key_mv = memoryview(bytearray(self.key_128)) + iv_mv = memoryview(bytearray(self.iv_128)) + + cipher3 = AES.new(self.key_128, self.aes_mode, self.iv_128) + ref3 = cipher3.decrypt(data) + + cipher4 = AES.new(key_mv, self.aes_mode, iv_mv) + key_mv[:3] = b'\xFF\xFF\xFF' + iv_mv[:3] = b'\xFF\xFF\xFF' + ref4 = cipher4.decrypt(data_mv) + + self.assertEqual(ref3, ref4) + + def test_output_param(self): + + pt = b'5' * 128 + cipher = AES.new(b'4'*16, self.aes_mode, iv=self.iv_128) + ct = cipher.encrypt(pt) + + output = bytearray(128) + cipher = AES.new(b'4'*16, self.aes_mode, iv=self.iv_128) + res = cipher.encrypt(pt, output=output) + self.assertEqual(ct, output) + self.assertEqual(res, None) + + cipher = AES.new(b'4'*16, self.aes_mode, iv=self.iv_128) + res = cipher.decrypt(ct, output=output) + self.assertEqual(pt, output) + self.assertEqual(res, None) + + + def test_output_param_same_buffer(self): + + pt = b'5' * 128 + cipher = AES.new(b'4'*16, self.aes_mode, iv=self.iv_128) + ct = cipher.encrypt(pt) + + pt_ba = bytearray(pt) + cipher = AES.new(b'4'*16, self.aes_mode, iv=self.iv_128) + res = cipher.encrypt(pt_ba, output=pt_ba) + self.assertEqual(ct, pt_ba) + self.assertEqual(res, None) + + ct_ba = bytearray(ct) + cipher = AES.new(b'4'*16, self.aes_mode, iv=self.iv_128) + res = cipher.decrypt(ct_ba, output=ct_ba) + self.assertEqual(pt, ct_ba) + self.assertEqual(res, None) + + + def test_output_param_memoryview(self): + + pt = b'5' * 128 + cipher = AES.new(b'4'*16, self.aes_mode, iv=self.iv_128) + ct = cipher.encrypt(pt) + + output = memoryview(bytearray(128)) + cipher = AES.new(b'4'*16, self.aes_mode, iv=self.iv_128) + cipher.encrypt(pt, output=output) + self.assertEqual(ct, output) + + cipher = AES.new(b'4'*16, self.aes_mode, iv=self.iv_128) + cipher.decrypt(ct, output=output) + self.assertEqual(pt, output) + + def test_output_param_neg(self): + LEN_PT = 128 + + pt = b'5' * LEN_PT + cipher = AES.new(b'4'*16, self.aes_mode, iv=self.iv_128) + ct = cipher.encrypt(pt) + + cipher = AES.new(b'4'*16, self.aes_mode, iv=self.iv_128) + self.assertRaises(TypeError, cipher.encrypt, pt, output=b'0' * LEN_PT) + + cipher = AES.new(b'4'*16, self.aes_mode, iv=self.iv_128) + self.assertRaises(TypeError, cipher.decrypt, ct, output=b'0' * LEN_PT) + + shorter_output = bytearray(LEN_PT - 1) + cipher = AES.new(b'4'*16, self.aes_mode, iv=self.iv_128) + self.assertRaises(ValueError, cipher.encrypt, pt, output=shorter_output) + cipher = AES.new(b'4'*16, self.aes_mode, iv=self.iv_128) + self.assertRaises(ValueError, cipher.decrypt, ct, output=shorter_output) + + +class CbcTests(BlockChainingTests): + aes_mode = AES.MODE_CBC + des3_mode = DES3.MODE_CBC + + +class NistBlockChainingVectors(unittest.TestCase): + + def _do_kat_aes_test(self, file_name): + + test_vectors = load_test_vectors(("Cipher", "AES"), + file_name, + "AES CBC KAT", + { "count" : lambda x: int(x) } ) + if test_vectors is None: + return + + direction = None + for tv in test_vectors: + + # The test vector file contains some directive lines + if is_string(tv): + direction = tv + continue + + self.description = tv.desc + + cipher = AES.new(tv.key, self.aes_mode, tv.iv) + if direction == "[ENCRYPT]": + self.assertEqual(cipher.encrypt(tv.plaintext), tv.ciphertext) + elif direction == "[DECRYPT]": + self.assertEqual(cipher.decrypt(tv.ciphertext), tv.plaintext) + else: + assert False + + # See Section 6.4.2 in AESAVS + def _do_mct_aes_test(self, file_name): + + test_vectors = load_test_vectors(("Cipher", "AES"), + file_name, + "AES CBC Montecarlo", + { "count" : lambda x: int(x) } ) + if test_vectors is None: + return + + direction = None + for tv in test_vectors: + + # The test vector file contains some directive lines + if is_string(tv): + direction = tv + continue + + self.description = tv.desc + cipher = AES.new(tv.key, self.aes_mode, tv.iv) + + if direction == '[ENCRYPT]': + cts = [ tv.iv ] + for count in range(1000): + cts.append(cipher.encrypt(tv.plaintext)) + tv.plaintext = cts[-2] + self.assertEqual(cts[-1], tv.ciphertext) + elif direction == '[DECRYPT]': + pts = [ tv.iv] + for count in range(1000): + pts.append(cipher.decrypt(tv.ciphertext)) + tv.ciphertext = pts[-2] + self.assertEqual(pts[-1], tv.plaintext) + else: + assert False + + def _do_tdes_test(self, file_name): + + test_vectors = load_test_vectors(("Cipher", "TDES"), + file_name, + "TDES CBC KAT", + { "count" : lambda x: int(x) } ) + if test_vectors is None: + return + + direction = None + for tv in test_vectors: + + # The test vector file contains some directive lines + if is_string(tv): + direction = tv + continue + + self.description = tv.desc + if hasattr(tv, "keys"): + cipher = DES.new(tv.keys, self.des_mode, tv.iv) + else: + if tv.key1 != tv.key3: + key = tv.key1 + tv.key2 + tv.key3 # Option 3 + else: + key = tv.key1 + tv.key2 # Option 2 + cipher = DES3.new(key, self.des3_mode, tv.iv) + + if direction == "[ENCRYPT]": + self.assertEqual(cipher.encrypt(tv.plaintext), tv.ciphertext) + elif direction == "[DECRYPT]": + self.assertEqual(cipher.decrypt(tv.ciphertext), tv.plaintext) + else: + assert False + + +class NistCbcVectors(NistBlockChainingVectors): + aes_mode = AES.MODE_CBC + des_mode = DES.MODE_CBC + des3_mode = DES3.MODE_CBC + + +# Create one test method per file +nist_aes_kat_mmt_files = ( + # KAT + "CBCGFSbox128.rsp", + "CBCGFSbox192.rsp", + "CBCGFSbox256.rsp", + "CBCKeySbox128.rsp", + "CBCKeySbox192.rsp", + "CBCKeySbox256.rsp", + "CBCVarKey128.rsp", + "CBCVarKey192.rsp", + "CBCVarKey256.rsp", + "CBCVarTxt128.rsp", + "CBCVarTxt192.rsp", + "CBCVarTxt256.rsp", + # MMT + "CBCMMT128.rsp", + "CBCMMT192.rsp", + "CBCMMT256.rsp", + ) +nist_aes_mct_files = ( + "CBCMCT128.rsp", + "CBCMCT192.rsp", + "CBCMCT256.rsp", + ) + +for file_name in nist_aes_kat_mmt_files: + def new_func(self, file_name=file_name): + self._do_kat_aes_test(file_name) + setattr(NistCbcVectors, "test_AES_" + file_name, new_func) + +for file_name in nist_aes_mct_files: + def new_func(self, file_name=file_name): + self._do_mct_aes_test(file_name) + setattr(NistCbcVectors, "test_AES_" + file_name, new_func) +del file_name, new_func + +nist_tdes_files = ( + "TCBCMMT2.rsp", # 2TDES + "TCBCMMT3.rsp", # 3TDES + "TCBCinvperm.rsp", # Single DES + "TCBCpermop.rsp", + "TCBCsubtab.rsp", + "TCBCvarkey.rsp", + "TCBCvartext.rsp", + ) + +for file_name in nist_tdes_files: + def new_func(self, file_name=file_name): + self._do_tdes_test(file_name) + setattr(NistCbcVectors, "test_TDES_" + file_name, new_func) + +# END OF NIST CBC TEST VECTORS + + +class SP800TestVectors(unittest.TestCase): + """Class exercising the CBC test vectors found in Section F.2 + of NIST SP 800-3A""" + + def test_aes_128(self): + key = '2b7e151628aed2a6abf7158809cf4f3c' + iv = '000102030405060708090a0b0c0d0e0f' + plaintext = '6bc1bee22e409f96e93d7e117393172a' +\ + 'ae2d8a571e03ac9c9eb76fac45af8e51' +\ + '30c81c46a35ce411e5fbc1191a0a52ef' +\ + 'f69f2445df4f9b17ad2b417be66c3710' + ciphertext = '7649abac8119b246cee98e9b12e9197d' +\ + '5086cb9b507219ee95db113a917678b2' +\ + '73bed6b8e3c1743b7116e69e22229516' +\ + '3ff1caa1681fac09120eca307586e1a7' + + key = unhexlify(key) + iv = unhexlify(iv) + plaintext = unhexlify(plaintext) + ciphertext = unhexlify(ciphertext) + + cipher = AES.new(key, AES.MODE_CBC, iv) + self.assertEqual(cipher.encrypt(plaintext), ciphertext) + cipher = AES.new(key, AES.MODE_CBC, iv) + self.assertEqual(cipher.decrypt(ciphertext), plaintext) + + def test_aes_192(self): + key = '8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b' + iv = '000102030405060708090a0b0c0d0e0f' + plaintext = '6bc1bee22e409f96e93d7e117393172a' +\ + 'ae2d8a571e03ac9c9eb76fac45af8e51' +\ + '30c81c46a35ce411e5fbc1191a0a52ef' +\ + 'f69f2445df4f9b17ad2b417be66c3710' + ciphertext = '4f021db243bc633d7178183a9fa071e8' +\ + 'b4d9ada9ad7dedf4e5e738763f69145a' +\ + '571b242012fb7ae07fa9baac3df102e0' +\ + '08b0e27988598881d920a9e64f5615cd' + + key = unhexlify(key) + iv = unhexlify(iv) + plaintext = unhexlify(plaintext) + ciphertext = unhexlify(ciphertext) + + cipher = AES.new(key, AES.MODE_CBC, iv) + self.assertEqual(cipher.encrypt(plaintext), ciphertext) + cipher = AES.new(key, AES.MODE_CBC, iv) + self.assertEqual(cipher.decrypt(ciphertext), plaintext) + + def test_aes_256(self): + key = '603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4' + iv = '000102030405060708090a0b0c0d0e0f' + plaintext = '6bc1bee22e409f96e93d7e117393172a' +\ + 'ae2d8a571e03ac9c9eb76fac45af8e51' +\ + '30c81c46a35ce411e5fbc1191a0a52ef' +\ + 'f69f2445df4f9b17ad2b417be66c3710' + ciphertext = 'f58c4c04d6e5f1ba779eabfb5f7bfbd6' +\ + '9cfc4e967edb808d679f777bc6702c7d' +\ + '39f23369a9d9bacfa530e26304231461' +\ + 'b2eb05e2c39be9fcda6c19078c6a9d1b' + + key = unhexlify(key) + iv = unhexlify(iv) + plaintext = unhexlify(plaintext) + ciphertext = unhexlify(ciphertext) + + cipher = AES.new(key, AES.MODE_CBC, iv) + self.assertEqual(cipher.encrypt(plaintext), ciphertext) + cipher = AES.new(key, AES.MODE_CBC, iv) + self.assertEqual(cipher.decrypt(ciphertext), plaintext) + + +def get_tests(config={}): + tests = [] + tests += list_test_cases(CbcTests) + if config.get('slow_tests'): + tests += list_test_cases(NistCbcVectors) + tests += list_test_cases(SP800TestVectors) + return tests + + +if __name__ == '__main__': + suite = lambda: unittest.TestSuite(get_tests()) + unittest.main(defaultTest='suite') diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/test_CCM.py b/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/test_CCM.py new file mode 100644 index 0000000..c179f16 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/test_CCM.py @@ -0,0 +1,970 @@ +# =================================================================== +# +# Copyright (c) 2015, Legrandin +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# =================================================================== + +import unittest +from binascii import unhexlify + +from Cryptodome.SelfTest.st_common import list_test_cases +from Cryptodome.SelfTest.loader import load_test_vectors_wycheproof +from Cryptodome.Util.py3compat import tobytes, bchr +from Cryptodome.Cipher import AES +from Cryptodome.Hash import SHAKE128 + +from Cryptodome.Util.strxor import strxor + +from Cryptodome.Cipher._mode_ccm import CCMMessageTooLongError + + +def get_tag_random(tag, length): + return SHAKE128.new(data=tobytes(tag)).read(length) + + +class CcmTests(unittest.TestCase): + + key_128 = get_tag_random("key_128", 16) + nonce_96 = get_tag_random("nonce_128", 12) + data = get_tag_random("data", 128) + + def test_loopback_128(self): + cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) + pt = get_tag_random("plaintext", 16 * 100) + ct = cipher.encrypt(pt) + + cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) + pt2 = cipher.decrypt(ct) + self.assertEqual(pt, pt2) + + def test_nonce(self): + # If not passed, the nonce is created randomly + cipher = AES.new(self.key_128, AES.MODE_CCM) + nonce1 = cipher.nonce + cipher = AES.new(self.key_128, AES.MODE_CCM) + nonce2 = cipher.nonce + self.assertEqual(len(nonce1), 11) + self.assertNotEqual(nonce1, nonce2) + + cipher = AES.new(self.key_128, AES.MODE_CCM, self.nonce_96) + ct = cipher.encrypt(self.data) + + cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) + self.assertEqual(ct, cipher.encrypt(self.data)) + + def test_nonce_must_be_bytes(self): + self.assertRaises(TypeError, AES.new, self.key_128, AES.MODE_CCM, + nonce=u'test12345678') + + def test_nonce_length(self): + self.assertRaises(ValueError, AES.new, self.key_128, AES.MODE_CCM, + nonce=b"") + self.assertRaises(ValueError, AES.new, self.key_128, AES.MODE_CCM, + nonce=bchr(1) * 6) + self.assertRaises(ValueError, AES.new, self.key_128, AES.MODE_CCM, + nonce=bchr(1) * 14) + for x in range(7, 13 + 1): + AES.new(self.key_128, AES.MODE_CCM, nonce=bchr(1) * x) + + def test_block_size(self): + cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) + self.assertEqual(cipher.block_size, AES.block_size) + + def test_nonce_attribute(self): + cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) + self.assertEqual(cipher.nonce, self.nonce_96) + + # By default, a 11 bytes long nonce is randomly generated + nonce1 = AES.new(self.key_128, AES.MODE_CCM).nonce + nonce2 = AES.new(self.key_128, AES.MODE_CCM).nonce + self.assertEqual(len(nonce1), 11) + self.assertNotEqual(nonce1, nonce2) + + def test_unknown_parameters(self): + self.assertRaises(TypeError, AES.new, self.key_128, AES.MODE_CCM, + self.nonce_96, 7) + self.assertRaises(TypeError, AES.new, self.key_128, AES.MODE_CCM, + nonce=self.nonce_96, unknown=7) + + # But some are only known by the base cipher + # (e.g. use_aesni consumed by the AES module) + AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96, + use_aesni=False) + + def test_null_encryption_decryption(self): + for func in "encrypt", "decrypt": + cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) + result = getattr(cipher, func)(b"") + self.assertEqual(result, b"") + + def test_either_encrypt_or_decrypt(self): + cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) + cipher.encrypt(b"") + self.assertRaises(TypeError, cipher.decrypt, b"") + + cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) + cipher.decrypt(b"") + self.assertRaises(TypeError, cipher.encrypt, b"") + + def test_data_must_be_bytes(self): + cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) + self.assertRaises(TypeError, cipher.encrypt, u'test1234567890-*') + + cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) + self.assertRaises(TypeError, cipher.decrypt, u'test1234567890-*') + + def test_mac_len(self): + # Invalid MAC length + for mac_len in range(3, 17 + 1, 2): + self.assertRaises(ValueError, AES.new, self.key_128, AES.MODE_CCM, + nonce=self.nonce_96, mac_len=mac_len) + + # Valid MAC length + for mac_len in range(4, 16 + 1, 2): + cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96, + mac_len=mac_len) + _, mac = cipher.encrypt_and_digest(self.data) + self.assertEqual(len(mac), mac_len) + + # Default MAC length + cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) + _, mac = cipher.encrypt_and_digest(self.data) + self.assertEqual(len(mac), 16) + + def test_invalid_mac(self): + from Cryptodome.Util.strxor import strxor_c + cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) + ct, mac = cipher.encrypt_and_digest(self.data) + + invalid_mac = strxor_c(mac, 0x01) + + cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) + self.assertRaises(ValueError, cipher.decrypt_and_verify, ct, + invalid_mac) + + def test_hex_mac(self): + cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) + mac_hex = cipher.hexdigest() + self.assertEqual(cipher.digest(), unhexlify(mac_hex)) + + cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) + cipher.hexverify(mac_hex) + + def test_longer_assoc_data_than_declared(self): + # More than zero + cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96, + assoc_len=0) + self.assertRaises(ValueError, cipher.update, b"1") + + # Too large + cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96, + assoc_len=15) + self.assertRaises(ValueError, cipher.update, self.data) + + def test_shorter_assoc_data_than_expected(self): + DATA_LEN = len(self.data) + + # With plaintext + cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96, + assoc_len=DATA_LEN + 1) + cipher.update(self.data) + self.assertRaises(ValueError, cipher.encrypt, self.data) + + # With empty plaintext + cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96, + assoc_len=DATA_LEN + 1) + cipher.update(self.data) + self.assertRaises(ValueError, cipher.digest) + + # With ciphertext + cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96, + assoc_len=DATA_LEN + 1) + cipher.update(self.data) + self.assertRaises(ValueError, cipher.decrypt, self.data) + + # With empty ciphertext + cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) + cipher.update(self.data) + mac = cipher.digest() + + cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96, + assoc_len=DATA_LEN + 1) + cipher.update(self.data) + self.assertRaises(ValueError, cipher.verify, mac) + + def test_shorter_and_longer_plaintext_than_declared(self): + DATA_LEN = len(self.data) + + cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96, + msg_len=DATA_LEN + 1) + cipher.encrypt(self.data) + self.assertRaises(ValueError, cipher.digest) + + cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96, + msg_len=DATA_LEN - 1) + self.assertRaises(ValueError, cipher.encrypt, self.data) + + def test_shorter_ciphertext_than_declared(self): + DATA_LEN = len(self.data) + + cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) + ct, mac = cipher.encrypt_and_digest(self.data) + + cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96, + msg_len=DATA_LEN + 1) + cipher.decrypt(ct) + self.assertRaises(ValueError, cipher.verify, mac) + + cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96, + msg_len=DATA_LEN - 1) + self.assertRaises(ValueError, cipher.decrypt, ct) + + def test_message_chunks(self): + # Validate that both associated data and plaintext/ciphertext + # can be broken up in chunks of arbitrary length + + auth_data = get_tag_random("authenticated data", 127) + plaintext = get_tag_random("plaintext", 127) + + cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) + cipher.update(auth_data) + ciphertext, ref_mac = cipher.encrypt_and_digest(plaintext) + + def break_up(data, chunk_length): + return [data[i:i+chunk_length] for i in range(0, len(data), + chunk_length)] + + # Encryption + for chunk_length in 1, 2, 3, 7, 10, 13, 16, 40, 80, 128: + + cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96, + msg_len=127, assoc_len=127) + + for chunk in break_up(auth_data, chunk_length): + cipher.update(chunk) + pt2 = b"" + for chunk in break_up(ciphertext, chunk_length): + pt2 += cipher.decrypt(chunk) + self.assertEqual(plaintext, pt2) + cipher.verify(ref_mac) + + # Decryption + for chunk_length in 1, 2, 3, 7, 10, 13, 16, 40, 80, 128: + + cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96, + msg_len=127, assoc_len=127) + + for chunk in break_up(auth_data, chunk_length): + cipher.update(chunk) + ct2 = b"" + for chunk in break_up(plaintext, chunk_length): + ct2 += cipher.encrypt(chunk) + self.assertEqual(ciphertext, ct2) + self.assertEqual(cipher.digest(), ref_mac) + + def test_bytearray(self): + + # Encrypt + key_ba = bytearray(self.key_128) + nonce_ba = bytearray(self.nonce_96) + header_ba = bytearray(self.data) + data_ba = bytearray(self.data) + + cipher1 = AES.new(self.key_128, + AES.MODE_CCM, + nonce=self.nonce_96) + cipher1.update(self.data) + ct = cipher1.encrypt(self.data) + tag = cipher1.digest() + + cipher2 = AES.new(key_ba, + AES.MODE_CCM, + nonce=nonce_ba) + key_ba[:3] = b"\xFF\xFF\xFF" + nonce_ba[:3] = b"\xFF\xFF\xFF" + cipher2.update(header_ba) + header_ba[:3] = b"\xFF\xFF\xFF" + ct_test = cipher2.encrypt(data_ba) + data_ba[:3] = b"\xFF\xFF\xFF" + tag_test = cipher2.digest() + + self.assertEqual(ct, ct_test) + self.assertEqual(tag, tag_test) + self.assertEqual(cipher1.nonce, cipher2.nonce) + + # Decrypt + key_ba = bytearray(self.key_128) + nonce_ba = bytearray(self.nonce_96) + header_ba = bytearray(self.data) + del data_ba + + cipher4 = AES.new(key_ba, + AES.MODE_CCM, + nonce=nonce_ba) + key_ba[:3] = b"\xFF\xFF\xFF" + nonce_ba[:3] = b"\xFF\xFF\xFF" + cipher4.update(header_ba) + header_ba[:3] = b"\xFF\xFF\xFF" + pt_test = cipher4.decrypt_and_verify(bytearray(ct_test), bytearray(tag_test)) + + self.assertEqual(self.data, pt_test) + + def test_memoryview(self): + + # Encrypt + key_mv = memoryview(bytearray(self.key_128)) + nonce_mv = memoryview(bytearray(self.nonce_96)) + header_mv = memoryview(bytearray(self.data)) + data_mv = memoryview(bytearray(self.data)) + + cipher1 = AES.new(self.key_128, + AES.MODE_CCM, + nonce=self.nonce_96) + cipher1.update(self.data) + ct = cipher1.encrypt(self.data) + tag = cipher1.digest() + + cipher2 = AES.new(key_mv, + AES.MODE_CCM, + nonce=nonce_mv) + key_mv[:3] = b"\xFF\xFF\xFF" + nonce_mv[:3] = b"\xFF\xFF\xFF" + cipher2.update(header_mv) + header_mv[:3] = b"\xFF\xFF\xFF" + ct_test = cipher2.encrypt(data_mv) + data_mv[:3] = b"\xFF\xFF\xFF" + tag_test = cipher2.digest() + + self.assertEqual(ct, ct_test) + self.assertEqual(tag, tag_test) + self.assertEqual(cipher1.nonce, cipher2.nonce) + + # Decrypt + key_mv = memoryview(bytearray(self.key_128)) + nonce_mv = memoryview(bytearray(self.nonce_96)) + header_mv = memoryview(bytearray(self.data)) + del data_mv + + cipher4 = AES.new(key_mv, + AES.MODE_CCM, + nonce=nonce_mv) + key_mv[:3] = b"\xFF\xFF\xFF" + nonce_mv[:3] = b"\xFF\xFF\xFF" + cipher4.update(header_mv) + header_mv[:3] = b"\xFF\xFF\xFF" + pt_test = cipher4.decrypt_and_verify(memoryview(ct_test), memoryview(tag_test)) + + self.assertEqual(self.data, pt_test) + + def test_output_param(self): + + pt = b'5' * 128 + cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) + ct = cipher.encrypt(pt) + tag = cipher.digest() + + output = bytearray(128) + cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) + res = cipher.encrypt(pt, output=output) + self.assertEqual(ct, output) + self.assertEqual(res, None) + + cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) + res = cipher.decrypt(ct, output=output) + self.assertEqual(pt, output) + self.assertEqual(res, None) + + cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) + res, tag_out = cipher.encrypt_and_digest(pt, output=output) + self.assertEqual(ct, output) + self.assertEqual(res, None) + self.assertEqual(tag, tag_out) + + cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) + res = cipher.decrypt_and_verify(ct, tag, output=output) + self.assertEqual(pt, output) + self.assertEqual(res, None) + + def test_output_param_memoryview(self): + + pt = b'5' * 128 + cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) + ct = cipher.encrypt(pt) + + output = memoryview(bytearray(128)) + cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) + cipher.encrypt(pt, output=output) + self.assertEqual(ct, output) + + cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) + cipher.decrypt(ct, output=output) + self.assertEqual(pt, output) + + def test_output_param_neg(self): + + pt = b'5' * 16 + cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) + ct = cipher.encrypt(pt) + + cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) + self.assertRaises(TypeError, cipher.encrypt, pt, output=b'0'*16) + + cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) + self.assertRaises(TypeError, cipher.decrypt, ct, output=b'0'*16) + + shorter_output = bytearray(15) + cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) + self.assertRaises(ValueError, cipher.encrypt, pt, output=shorter_output) + cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) + self.assertRaises(ValueError, cipher.decrypt, ct, output=shorter_output) + + def test_message_too_long(self): + + nonce = b'N' * 13 + self.assertRaises(CCMMessageTooLongError, + AES.new, + self.key_128, + AES.MODE_CCM, + nonce=nonce, + assoc_len=20, + msg_len=0x10000) + + nonce = b'N' * 7 + self.assertRaises(CCMMessageTooLongError, + AES.new, + self.key_128, + AES.MODE_CCM, + nonce=nonce, + assoc_len=20, + msg_len=2**64) + + nonce = b'N' * 13 + cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=nonce) + self.assertRaises(CCMMessageTooLongError, + cipher.encrypt, + b'C' * 0x10000) + + nonce = b'N' * 13 + cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=nonce) + self.assertRaises(CCMMessageTooLongError, + cipher.decrypt, + b'C' * 0x10000) + + +class CcmFSMTests(unittest.TestCase): + + key_128 = get_tag_random("key_128", 16) + nonce_96 = get_tag_random("nonce_128", 12) + data = get_tag_random("data", 16) + + def test_valid_init_encrypt_decrypt_digest_verify(self): + # No authenticated data, fixed plaintext + for assoc_len in (None, 0): + for msg_len in (None, len(self.data)): + # Verify path INIT->ENCRYPT->DIGEST + cipher = AES.new(self.key_128, AES.MODE_CCM, + nonce=self.nonce_96, + assoc_len=assoc_len, + msg_len=msg_len) + ct = cipher.encrypt(self.data) + mac = cipher.digest() + + # Verify path INIT->DECRYPT->VERIFY + cipher = AES.new(self.key_128, AES.MODE_CCM, + nonce=self.nonce_96, + assoc_len=assoc_len, + msg_len=msg_len) + cipher.decrypt(ct) + cipher.verify(mac) + + def test_valid_init_update_digest_verify(self): + # No plaintext, fixed authenticated data + for assoc_len in (None, len(self.data)): + for msg_len in (None, 0): + # Verify path INIT->UPDATE->DIGEST + cipher = AES.new(self.key_128, AES.MODE_CCM, + nonce=self.nonce_96, + assoc_len=assoc_len, + msg_len=msg_len) + cipher.update(self.data) + mac = cipher.digest() + + # Verify path INIT->UPDATE->VERIFY + cipher = AES.new(self.key_128, AES.MODE_CCM, + nonce=self.nonce_96, + assoc_len=assoc_len, + msg_len=msg_len) + cipher.update(self.data) + cipher.verify(mac) + + def test_valid_full_path(self): + # Fixed authenticated data, fixed plaintext + for assoc_len in (None, len(self.data)): + for msg_len in (None, len(self.data)): + # Verify path INIT->UPDATE->ENCRYPT->DIGEST + cipher = AES.new(self.key_128, AES.MODE_CCM, + nonce=self.nonce_96, + assoc_len=assoc_len, + msg_len=msg_len) + cipher.update(self.data) + ct = cipher.encrypt(self.data) + mac = cipher.digest() + + # Verify path INIT->UPDATE->DECRYPT->VERIFY + cipher = AES.new(self.key_128, AES.MODE_CCM, + nonce=self.nonce_96, + assoc_len=assoc_len, + msg_len=msg_len) + cipher.update(self.data) + cipher.decrypt(ct) + cipher.verify(mac) + + def test_valid_init_digest(self): + # Verify path INIT->DIGEST + cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) + cipher.digest() + + def test_valid_init_verify(self): + # Verify path INIT->VERIFY + cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) + mac = cipher.digest() + + cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) + cipher.verify(mac) + + def test_valid_multiple_encrypt_or_decrypt(self): + # Only possible if msg_len is declared in advance + for method_name in "encrypt", "decrypt": + for auth_data in (None, b"333", self.data, + self.data + b"3"): + if auth_data is None: + assoc_len = None + else: + assoc_len = len(auth_data) + cipher = AES.new(self.key_128, AES.MODE_CCM, + nonce=self.nonce_96, + msg_len=64, + assoc_len=assoc_len) + if auth_data is not None: + cipher.update(auth_data) + method = getattr(cipher, method_name) + method(self.data) + method(self.data) + method(self.data) + method(self.data) + + def test_valid_multiple_digest_or_verify(self): + # Multiple calls to digest + cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) + cipher.update(self.data) + first_mac = cipher.digest() + for x in range(4): + self.assertEqual(first_mac, cipher.digest()) + + # Multiple calls to verify + cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) + cipher.update(self.data) + for x in range(5): + cipher.verify(first_mac) + + def test_valid_encrypt_and_digest_decrypt_and_verify(self): + # encrypt_and_digest + cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) + cipher.update(self.data) + ct, mac = cipher.encrypt_and_digest(self.data) + + # decrypt_and_verify + cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) + cipher.update(self.data) + pt = cipher.decrypt_and_verify(ct, mac) + self.assertEqual(self.data, pt) + + def test_invalid_multiple_encrypt_decrypt_without_msg_len(self): + # Once per method, with or without assoc. data + for method_name in "encrypt", "decrypt": + for assoc_data_present in (True, False): + cipher = AES.new(self.key_128, AES.MODE_CCM, + nonce=self.nonce_96) + if assoc_data_present: + cipher.update(self.data) + method = getattr(cipher, method_name) + method(self.data) + self.assertRaises(TypeError, method, self.data) + + def test_invalid_mixing_encrypt_decrypt(self): + # Once per method, with or without assoc. data + for method1_name, method2_name in (("encrypt", "decrypt"), + ("decrypt", "encrypt")): + for assoc_data_present in (True, False): + cipher = AES.new(self.key_128, AES.MODE_CCM, + nonce=self.nonce_96, + msg_len=32) + if assoc_data_present: + cipher.update(self.data) + getattr(cipher, method1_name)(self.data) + self.assertRaises(TypeError, getattr(cipher, method2_name), + self.data) + + def test_invalid_encrypt_or_update_after_digest(self): + for method_name in "encrypt", "update": + cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) + cipher.encrypt(self.data) + cipher.digest() + self.assertRaises(TypeError, getattr(cipher, method_name), + self.data) + + cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) + cipher.encrypt_and_digest(self.data) + + def test_invalid_decrypt_or_update_after_verify(self): + cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) + ct = cipher.encrypt(self.data) + mac = cipher.digest() + + for method_name in "decrypt", "update": + cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) + cipher.decrypt(ct) + cipher.verify(mac) + self.assertRaises(TypeError, getattr(cipher, method_name), + self.data) + + cipher = AES.new(self.key_128, AES.MODE_CCM, nonce=self.nonce_96) + cipher.decrypt_and_verify(ct, mac) + self.assertRaises(TypeError, getattr(cipher, method_name), + self.data) + + +class TestVectors(unittest.TestCase): + """Class exercising the CCM test vectors found in Appendix C + of NIST SP 800-38C and in RFC 3610""" + + # List of test vectors, each made up of: + # - authenticated data + # - plaintext + # - ciphertext + # - MAC + # - AES key + # - nonce + test_vectors_hex = [ + # NIST SP 800 38C + ( '0001020304050607', + '20212223', + '7162015b', + '4dac255d', + '404142434445464748494a4b4c4d4e4f', + '10111213141516'), + ( '000102030405060708090a0b0c0d0e0f', + '202122232425262728292a2b2c2d2e2f', + 'd2a1f0e051ea5f62081a7792073d593d', + '1fc64fbfaccd', + '404142434445464748494a4b4c4d4e4f', + '1011121314151617'), + ( '000102030405060708090a0b0c0d0e0f10111213', + '202122232425262728292a2b2c2d2e2f3031323334353637', + 'e3b201a9f5b71a7a9b1ceaeccd97e70b6176aad9a4428aa5', + '484392fbc1b09951', + '404142434445464748494a4b4c4d4e4f', + '101112131415161718191a1b'), + ( (''.join(["%02X" % (x*16+y) for x in range(0,16) for y in range(0,16)]))*256, + '202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f', + '69915dad1e84c6376a68c2967e4dab615ae0fd1faec44cc484828529463ccf72', + 'b4ac6bec93e8598e7f0dadbcea5b', + '404142434445464748494a4b4c4d4e4f', + '101112131415161718191a1b1c'), + # RFC3610 + ( '0001020304050607', + '08090a0b0c0d0e0f101112131415161718191a1b1c1d1e', + '588c979a61c663d2f066d0c2c0f989806d5f6b61dac384', + '17e8d12cfdf926e0', + 'c0c1c2c3c4c5c6c7c8c9cacbcccdcecf', + '00000003020100a0a1a2a3a4a5'), + ( + '0001020304050607', + '08090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f', + '72c91a36e135f8cf291ca894085c87e3cc15c439c9e43a3b', + 'a091d56e10400916', + 'c0c1c2c3c4c5c6c7c8c9cacbcccdcecf', + '00000004030201a0a1a2a3a4a5'), + ( '0001020304050607', + '08090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20', + '51b1e5f44a197d1da46b0f8e2d282ae871e838bb64da859657', + '4adaa76fbd9fb0c5', + 'c0c1c2c3c4c5c6c7c8c9cacbcccdcecf', + '00000005040302A0A1A2A3A4A5'), + ( '000102030405060708090a0b', + '0c0d0e0f101112131415161718191a1b1c1d1e', + 'a28c6865939a9a79faaa5c4c2a9d4a91cdac8c', + '96c861b9c9e61ef1', + 'c0c1c2c3c4c5c6c7c8c9cacbcccdcecf', + '00000006050403a0a1a2a3a4a5'), + ( '000102030405060708090a0b', + '0c0d0e0f101112131415161718191a1b1c1d1e1f', + 'dcf1fb7b5d9e23fb9d4e131253658ad86ebdca3e', + '51e83f077d9c2d93', + 'c0c1c2c3c4c5c6c7c8c9cacbcccdcecf', + '00000007060504a0a1a2a3a4a5'), + ( '000102030405060708090a0b', + '0c0d0e0f101112131415161718191a1b1c1d1e1f20', + '6fc1b011f006568b5171a42d953d469b2570a4bd87', + '405a0443ac91cb94', + 'c0c1c2c3c4c5c6c7c8c9cacbcccdcecf', + '00000008070605a0a1a2a3a4a5'), + ( '0001020304050607', + '08090a0b0c0d0e0f101112131415161718191a1b1c1d1e', + '0135d1b2c95f41d5d1d4fec185d166b8094e999dfed96c', + '048c56602c97acbb7490', + 'c0c1c2c3c4c5c6c7c8c9cacbcccdcecf', + '00000009080706a0a1a2a3a4a5'), + ( '0001020304050607', + '08090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f', + '7b75399ac0831dd2f0bbd75879a2fd8f6cae6b6cd9b7db24', + 'c17b4433f434963f34b4', + 'c0c1c2c3c4c5c6c7c8c9cacbcccdcecf', + '0000000a090807a0a1a2a3a4a5'), + ( '0001020304050607', + '08090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20', + '82531a60cc24945a4b8279181ab5c84df21ce7f9b73f42e197', + 'ea9c07e56b5eb17e5f4e', + 'c0c1c2c3c4c5c6c7c8c9cacbcccdcecf', + '0000000b0a0908a0a1a2a3a4a5'), + ( '000102030405060708090a0b', + '0c0d0e0f101112131415161718191a1b1c1d1e', + '07342594157785152b074098330abb141b947b', + '566aa9406b4d999988dd', + 'c0c1c2c3c4c5c6c7c8c9cacbcccdcecf', + '0000000c0b0a09a0a1a2a3a4a5'), + ( '000102030405060708090a0b', + '0c0d0e0f101112131415161718191a1b1c1d1e1f', + '676bb20380b0e301e8ab79590a396da78b834934', + 'f53aa2e9107a8b6c022c', + 'c0c1c2c3c4c5c6c7c8c9cacbcccdcecf', + '0000000d0c0b0aa0a1a2a3a4a5'), + ( '000102030405060708090a0b', + '0c0d0e0f101112131415161718191a1b1c1d1e1f20', + 'c0ffa0d6f05bdb67f24d43a4338d2aa4bed7b20e43', + 'cd1aa31662e7ad65d6db', + 'c0c1c2c3c4c5c6c7c8c9cacbcccdcecf', + '0000000e0d0c0ba0a1a2a3a4a5'), + ( '0be1a88bace018b1', + '08e8cf97d820ea258460e96ad9cf5289054d895ceac47c', + '4cb97f86a2a4689a877947ab8091ef5386a6ffbdd080f8', + 'e78cf7cb0cddd7b3', + 'd7828d13b2b0bdc325a76236df93cc6b', + '00412b4ea9cdbe3c9696766cfa'), + ( '63018f76dc8a1bcb', + '9020ea6f91bdd85afa0039ba4baff9bfb79c7028949cd0ec', + '4ccb1e7ca981befaa0726c55d378061298c85c92814abc33', + 'c52ee81d7d77c08a', + 'd7828d13b2b0bdc325a76236df93cc6b', + '0033568ef7b2633c9696766cfa'), + ( 'aa6cfa36cae86b40', + 'b916e0eacc1c00d7dcec68ec0b3bbb1a02de8a2d1aa346132e', + 'b1d23a2220ddc0ac900d9aa03c61fcf4a559a4417767089708', + 'a776796edb723506', + 'd7828d13b2b0bdc325a76236df93cc6b', + '00103fe41336713c9696766cfa'), + ( 'd0d0735c531e1becf049c244', + '12daac5630efa5396f770ce1a66b21f7b2101c', + '14d253c3967b70609b7cbb7c49916028324526', + '9a6f49975bcadeaf', + 'd7828d13b2b0bdc325a76236df93cc6b', + '00764c63b8058e3c9696766cfa'), + ( '77b60f011c03e1525899bcae', + 'e88b6a46c78d63e52eb8c546efb5de6f75e9cc0d', + '5545ff1a085ee2efbf52b2e04bee1e2336c73e3f', + '762c0c7744fe7e3c', + 'd7828d13b2b0bdc325a76236df93cc6b', + '00f8b678094e3b3c9696766cfa'), + ( 'cd9044d2b71fdb8120ea60c0', + '6435acbafb11a82e2f071d7ca4a5ebd93a803ba87f', + '009769ecabdf48625594c59251e6035722675e04c8', + '47099e5ae0704551', + 'd7828d13b2b0bdc325a76236df93cc6b', + '00d560912d3f703c9696766cfa'), + ( 'd85bc7e69f944fb8', + '8a19b950bcf71a018e5e6701c91787659809d67dbedd18', + 'bc218daa947427b6db386a99ac1aef23ade0b52939cb6a', + '637cf9bec2408897c6ba', + 'd7828d13b2b0bdc325a76236df93cc6b', + '0042fff8f1951c3c9696766cfa'), + ( '74a0ebc9069f5b37', + '1761433c37c5a35fc1f39f406302eb907c6163be38c98437', + '5810e6fd25874022e80361a478e3e9cf484ab04f447efff6', + 'f0a477cc2fc9bf548944', + 'd7828d13b2b0bdc325a76236df93cc6b', + '00920f40e56cdc3c9696766cfa'), + ( '44a3aa3aae6475ca', + 'a434a8e58500c6e41530538862d686ea9e81301b5ae4226bfa', + 'f2beed7bc5098e83feb5b31608f8e29c38819a89c8e776f154', + '4d4151a4ed3a8b87b9ce', + 'd7828d13b2b0bdc325a76236df93cc6b', + '0027ca0c7120bc3c9696766cfa'), + ( 'ec46bb63b02520c33c49fd70', + 'b96b49e21d621741632875db7f6c9243d2d7c2', + '31d750a09da3ed7fddd49a2032aabf17ec8ebf', + '7d22c8088c666be5c197', + 'd7828d13b2b0bdc325a76236df93cc6b', + '005b8ccbcd9af83c9696766cfa'), + ( '47a65ac78b3d594227e85e71', + 'e2fcfbb880442c731bf95167c8ffd7895e337076', + 'e882f1dbd38ce3eda7c23f04dd65071eb41342ac', + 'df7e00dccec7ae52987d', + 'd7828d13b2b0bdc325a76236df93cc6b', + '003ebe94044b9a3c9696766cfa'), + ( '6e37a6ef546d955d34ab6059', + 'abf21c0b02feb88f856df4a37381bce3cc128517d4', + 'f32905b88a641b04b9c9ffb58cc390900f3da12ab1', + '6dce9e82efa16da62059', + 'd7828d13b2b0bdc325a76236df93cc6b', + '008d493b30ae8b3c9696766cfa'), + ] + + test_vectors = [[unhexlify(x) for x in tv] for tv in test_vectors_hex] + + def runTest(self): + for assoc_data, pt, ct, mac, key, nonce in self.test_vectors: + # Encrypt + cipher = AES.new(key, AES.MODE_CCM, nonce, mac_len=len(mac)) + cipher.update(assoc_data) + ct2, mac2 = cipher.encrypt_and_digest(pt) + self.assertEqual(ct, ct2) + self.assertEqual(mac, mac2) + + # Decrypt + cipher = AES.new(key, AES.MODE_CCM, nonce, mac_len=len(mac)) + cipher.update(assoc_data) + pt2 = cipher.decrypt_and_verify(ct, mac) + self.assertEqual(pt, pt2) + + +class TestVectorsWycheproof(unittest.TestCase): + + def __init__(self, wycheproof_warnings, **extra_params): + unittest.TestCase.__init__(self) + self._wycheproof_warnings = wycheproof_warnings + self._extra_params = extra_params + self._id = "None" + + def setUp(self): + + def filter_tag(group): + return group['tagSize'] // 8 + + self.tv = load_test_vectors_wycheproof(("Cipher", "wycheproof"), + "aes_ccm_test.json", + "Wycheproof AES CCM", + group_tag={'tag_size': filter_tag}) + + def shortDescription(self): + return self._id + + def warn(self, tv): + if tv.warning and self._wycheproof_warnings: + import warnings + warnings.warn("Wycheproof warning: %s (%s)" % (self._id, tv.comment)) + + def test_encrypt(self, tv): + self._id = "Wycheproof Encrypt CCM Test #" + str(tv.id) + + try: + cipher = AES.new(tv.key, AES.MODE_CCM, tv.iv, mac_len=tv.tag_size, + **self._extra_params) + except ValueError as e: + if len(tv.iv) not in range(7, 13 + 1, 2) and "Length of parameter 'nonce'" in str(e): + assert not tv.valid + return + if tv.tag_size not in range(4, 16 + 1, 2) and "Parameter 'mac_len'" in str(e): + assert not tv.valid + return + raise e + + cipher.update(tv.aad) + ct, tag = cipher.encrypt_and_digest(tv.msg) + if tv.valid: + self.assertEqual(ct, tv.ct) + self.assertEqual(tag, tv.tag) + self.warn(tv) + + def test_decrypt(self, tv): + self._id = "Wycheproof Decrypt CCM Test #" + str(tv.id) + + try: + cipher = AES.new(tv.key, AES.MODE_CCM, tv.iv, mac_len=tv.tag_size, + **self._extra_params) + except ValueError as e: + if len(tv.iv) not in range(7, 13 + 1, 2) and "Length of parameter 'nonce'" in str(e): + assert not tv.valid + return + if tv.tag_size not in range(4, 16 + 1, 2) and "Parameter 'mac_len'" in str(e): + assert not tv.valid + return + raise e + + cipher.update(tv.aad) + try: + pt = cipher.decrypt_and_verify(tv.ct, tv.tag) + except ValueError: + assert not tv.valid + else: + assert tv.valid + self.assertEqual(pt, tv.msg) + self.warn(tv) + + def test_corrupt_decrypt(self, tv): + self._id = "Wycheproof Corrupt Decrypt CCM Test #" + str(tv.id) + if len(tv.iv) not in range(7, 13 + 1, 2) or len(tv.ct) == 0: + return + cipher = AES.new(tv.key, AES.MODE_CCM, tv.iv, mac_len=tv.tag_size, + **self._extra_params) + cipher.update(tv.aad) + ct_corrupt = strxor(tv.ct, b"\x00" * (len(tv.ct) - 1) + b"\x01") + self.assertRaises(ValueError, cipher.decrypt_and_verify, ct_corrupt, tv.tag) + + def runTest(self): + + for tv in self.tv: + self.test_encrypt(tv) + self.test_decrypt(tv) + self.test_corrupt_decrypt(tv) + + +def get_tests(config={}): + wycheproof_warnings = config.get('wycheproof_warnings') + + tests = [] + tests += list_test_cases(CcmTests) + tests += list_test_cases(CcmFSMTests) + tests += [TestVectors()] + tests += [TestVectorsWycheproof(wycheproof_warnings)] + + return tests + + +if __name__ == '__main__': + def suite(): + unittest.TestSuite(get_tests()) + unittest.main(defaultTest='suite') diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/test_CFB.py b/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/test_CFB.py new file mode 100644 index 0000000..673bf8e --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/test_CFB.py @@ -0,0 +1,411 @@ +# =================================================================== +# +# Copyright (c) 2014, Legrandin +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# =================================================================== + +import unittest +from binascii import unhexlify + +from Cryptodome.SelfTest.loader import load_test_vectors +from Cryptodome.SelfTest.st_common import list_test_cases +from Cryptodome.Util.py3compat import tobytes, is_string +from Cryptodome.Cipher import AES, DES3, DES +from Cryptodome.Hash import SHAKE128 + +from Cryptodome.SelfTest.Cipher.test_CBC import BlockChainingTests + + +def get_tag_random(tag, length): + return SHAKE128.new(data=tobytes(tag)).read(length) + + +class CfbTests(BlockChainingTests): + + aes_mode = AES.MODE_CFB + des3_mode = DES3.MODE_CFB + + # Redefine test_unaligned_data_128/64 + + def test_unaligned_data_128(self): + plaintexts = [ b"7777777" ] * 100 + + cipher = AES.new(self.key_128, AES.MODE_CFB, self.iv_128, segment_size=8) + ciphertexts = [ cipher.encrypt(x) for x in plaintexts ] + cipher = AES.new(self.key_128, AES.MODE_CFB, self.iv_128, segment_size=8) + self.assertEqual(b"".join(ciphertexts), cipher.encrypt(b"".join(plaintexts))) + + cipher = AES.new(self.key_128, AES.MODE_CFB, self.iv_128, segment_size=128) + ciphertexts = [ cipher.encrypt(x) for x in plaintexts ] + cipher = AES.new(self.key_128, AES.MODE_CFB, self.iv_128, segment_size=128) + self.assertEqual(b"".join(ciphertexts), cipher.encrypt(b"".join(plaintexts))) + + def test_unaligned_data_64(self): + plaintexts = [ b"7777777" ] * 100 + cipher = DES3.new(self.key_192, DES3.MODE_CFB, self.iv_64, segment_size=8) + ciphertexts = [ cipher.encrypt(x) for x in plaintexts ] + cipher = DES3.new(self.key_192, DES3.MODE_CFB, self.iv_64, segment_size=8) + self.assertEqual(b"".join(ciphertexts), cipher.encrypt(b"".join(plaintexts))) + + cipher = DES3.new(self.key_192, DES3.MODE_CFB, self.iv_64, segment_size=64) + ciphertexts = [ cipher.encrypt(x) for x in plaintexts ] + cipher = DES3.new(self.key_192, DES3.MODE_CFB, self.iv_64, segment_size=64) + self.assertEqual(b"".join(ciphertexts), cipher.encrypt(b"".join(plaintexts))) + + # Extra + + def test_segment_size_128(self): + for bits in range(8, 129, 8): + cipher = AES.new(self.key_128, AES.MODE_CFB, self.iv_128, + segment_size=bits) + + for bits in 0, 7, 9, 127, 129: + self.assertRaises(ValueError, AES.new, self.key_128, AES.MODE_CFB, + self.iv_128, + segment_size=bits) + + def test_segment_size_64(self): + for bits in range(8, 65, 8): + cipher = DES3.new(self.key_192, DES3.MODE_CFB, self.iv_64, + segment_size=bits) + + for bits in 0, 7, 9, 63, 65: + self.assertRaises(ValueError, DES3.new, self.key_192, AES.MODE_CFB, + self.iv_64, + segment_size=bits) + + +class NistCfbVectors(unittest.TestCase): + + def _do_kat_aes_test(self, file_name, segment_size): + + test_vectors = load_test_vectors(("Cipher", "AES"), + file_name, + "AES CFB%d KAT" % segment_size, + { "count" : lambda x: int(x) } ) + if test_vectors is None: + return + + direction = None + for tv in test_vectors: + + # The test vector file contains some directive lines + if is_string(tv): + direction = tv + continue + + self.description = tv.desc + cipher = AES.new(tv.key, AES.MODE_CFB, tv.iv, + segment_size=segment_size) + if direction == "[ENCRYPT]": + self.assertEqual(cipher.encrypt(tv.plaintext), tv.ciphertext) + elif direction == "[DECRYPT]": + self.assertEqual(cipher.decrypt(tv.ciphertext), tv.plaintext) + else: + assert False + + # See Section 6.4.5 in AESAVS + def _do_mct_aes_test(self, file_name, segment_size): + + test_vectors = load_test_vectors(("Cipher", "AES"), + file_name, + "AES CFB%d Montecarlo" % segment_size, + { "count" : lambda x: int(x) } ) + if test_vectors is None: + return + + assert(segment_size in (8, 128)) + + direction = None + for tv in test_vectors: + + # The test vector file contains some directive lines + if is_string(tv): + direction = tv + continue + + self.description = tv.desc + cipher = AES.new(tv.key, AES.MODE_CFB, tv.iv, + segment_size=segment_size) + + def get_input(input_text, output_seq, j): + # CFB128 + if segment_size == 128: + if j >= 2: + return output_seq[-2] + return [input_text, tv.iv][j] + # CFB8 + if j == 0: + return input_text + elif j <= 16: + return tv.iv[j - 1:j] + return output_seq[j - 17] + + if direction == '[ENCRYPT]': + cts = [] + for j in range(1000): + plaintext = get_input(tv.plaintext, cts, j) + cts.append(cipher.encrypt(plaintext)) + self.assertEqual(cts[-1], tv.ciphertext) + elif direction == '[DECRYPT]': + pts = [] + for j in range(1000): + ciphertext = get_input(tv.ciphertext, pts, j) + pts.append(cipher.decrypt(ciphertext)) + self.assertEqual(pts[-1], tv.plaintext) + else: + assert False + + def _do_tdes_test(self, file_name, segment_size): + + test_vectors = load_test_vectors(("Cipher", "TDES"), + file_name, + "TDES CFB%d KAT" % segment_size, + { "count" : lambda x: int(x) } ) + if test_vectors is None: + return + + direction = None + for tv in test_vectors: + + # The test vector file contains some directive lines + if is_string(tv): + direction = tv + continue + + self.description = tv.desc + if hasattr(tv, "keys"): + cipher = DES.new(tv.keys, DES.MODE_CFB, tv.iv, + segment_size=segment_size) + else: + if tv.key1 != tv.key3: + key = tv.key1 + tv.key2 + tv.key3 # Option 3 + else: + key = tv.key1 + tv.key2 # Option 2 + cipher = DES3.new(key, DES3.MODE_CFB, tv.iv, + segment_size=segment_size) + if direction == "[ENCRYPT]": + self.assertEqual(cipher.encrypt(tv.plaintext), tv.ciphertext) + elif direction == "[DECRYPT]": + self.assertEqual(cipher.decrypt(tv.ciphertext), tv.plaintext) + else: + assert False + + +# Create one test method per file +nist_aes_kat_mmt_files = ( + # KAT + "CFB?GFSbox128.rsp", + "CFB?GFSbox192.rsp", + "CFB?GFSbox256.rsp", + "CFB?KeySbox128.rsp", + "CFB?KeySbox192.rsp", + "CFB?KeySbox256.rsp", + "CFB?VarKey128.rsp", + "CFB?VarKey192.rsp", + "CFB?VarKey256.rsp", + "CFB?VarTxt128.rsp", + "CFB?VarTxt192.rsp", + "CFB?VarTxt256.rsp", + # MMT + "CFB?MMT128.rsp", + "CFB?MMT192.rsp", + "CFB?MMT256.rsp", + ) +nist_aes_mct_files = ( + "CFB?MCT128.rsp", + "CFB?MCT192.rsp", + "CFB?MCT256.rsp", + ) + +for file_gen_name in nist_aes_kat_mmt_files: + for bits in "8", "128": + file_name = file_gen_name.replace("?", bits) + def new_func(self, file_name=file_name, bits=bits): + self._do_kat_aes_test(file_name, int(bits)) + setattr(NistCfbVectors, "test_AES_" + file_name, new_func) + +for file_gen_name in nist_aes_mct_files: + for bits in "8", "128": + file_name = file_gen_name.replace("?", bits) + def new_func(self, file_name=file_name, bits=bits): + self._do_mct_aes_test(file_name, int(bits)) + setattr(NistCfbVectors, "test_AES_" + file_name, new_func) +del file_name, new_func + +nist_tdes_files = ( + "TCFB?MMT2.rsp", # 2TDES + "TCFB?MMT3.rsp", # 3TDES + "TCFB?invperm.rsp", # Single DES + "TCFB?permop.rsp", + "TCFB?subtab.rsp", + "TCFB?varkey.rsp", + "TCFB?vartext.rsp", + ) + +for file_gen_name in nist_tdes_files: + for bits in "8", "64": + file_name = file_gen_name.replace("?", bits) + def new_func(self, file_name=file_name, bits=bits): + self._do_tdes_test(file_name, int(bits)) + setattr(NistCfbVectors, "test_TDES_" + file_name, new_func) + +# END OF NIST CBC TEST VECTORS + + +class SP800TestVectors(unittest.TestCase): + """Class exercising the CFB test vectors found in Section F.3 + of NIST SP 800-3A""" + + def test_aes_128_cfb8(self): + plaintext = '6bc1bee22e409f96e93d7e117393172aae2d' + ciphertext = '3b79424c9c0dd436bace9e0ed4586a4f32b9' + key = '2b7e151628aed2a6abf7158809cf4f3c' + iv = '000102030405060708090a0b0c0d0e0f' + + key = unhexlify(key) + iv = unhexlify(iv) + plaintext = unhexlify(plaintext) + ciphertext = unhexlify(ciphertext) + + cipher = AES.new(key, AES.MODE_CFB, iv, segment_size=8) + self.assertEqual(cipher.encrypt(plaintext), ciphertext) + cipher = AES.new(key, AES.MODE_CFB, iv, segment_size=8) + self.assertEqual(cipher.decrypt(ciphertext), plaintext) + + def test_aes_192_cfb8(self): + plaintext = '6bc1bee22e409f96e93d7e117393172aae2d' + ciphertext = 'cda2521ef0a905ca44cd057cbf0d47a0678a' + key = '8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b' + iv = '000102030405060708090a0b0c0d0e0f' + + key = unhexlify(key) + iv = unhexlify(iv) + plaintext = unhexlify(plaintext) + ciphertext = unhexlify(ciphertext) + + cipher = AES.new(key, AES.MODE_CFB, iv, segment_size=8) + self.assertEqual(cipher.encrypt(plaintext), ciphertext) + cipher = AES.new(key, AES.MODE_CFB, iv, segment_size=8) + self.assertEqual(cipher.decrypt(ciphertext), plaintext) + + def test_aes_256_cfb8(self): + plaintext = '6bc1bee22e409f96e93d7e117393172aae2d' + ciphertext = 'dc1f1a8520a64db55fcc8ac554844e889700' + key = '603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4' + iv = '000102030405060708090a0b0c0d0e0f' + + key = unhexlify(key) + iv = unhexlify(iv) + plaintext = unhexlify(plaintext) + ciphertext = unhexlify(ciphertext) + + cipher = AES.new(key, AES.MODE_CFB, iv, segment_size=8) + self.assertEqual(cipher.encrypt(plaintext), ciphertext) + cipher = AES.new(key, AES.MODE_CFB, iv, segment_size=8) + self.assertEqual(cipher.decrypt(ciphertext), plaintext) + + def test_aes_128_cfb128(self): + plaintext = '6bc1bee22e409f96e93d7e117393172a' +\ + 'ae2d8a571e03ac9c9eb76fac45af8e51' +\ + '30c81c46a35ce411e5fbc1191a0a52ef' +\ + 'f69f2445df4f9b17ad2b417be66c3710' + ciphertext = '3b3fd92eb72dad20333449f8e83cfb4a' +\ + 'c8a64537a0b3a93fcde3cdad9f1ce58b' +\ + '26751f67a3cbb140b1808cf187a4f4df' +\ + 'c04b05357c5d1c0eeac4c66f9ff7f2e6' + key = '2b7e151628aed2a6abf7158809cf4f3c' + iv = '000102030405060708090a0b0c0d0e0f' + + key = unhexlify(key) + iv = unhexlify(iv) + plaintext = unhexlify(plaintext) + ciphertext = unhexlify(ciphertext) + + cipher = AES.new(key, AES.MODE_CFB, iv, segment_size=128) + self.assertEqual(cipher.encrypt(plaintext), ciphertext) + cipher = AES.new(key, AES.MODE_CFB, iv, segment_size=128) + self.assertEqual(cipher.decrypt(ciphertext), plaintext) + + def test_aes_192_cfb128(self): + plaintext = '6bc1bee22e409f96e93d7e117393172a' +\ + 'ae2d8a571e03ac9c9eb76fac45af8e51' +\ + '30c81c46a35ce411e5fbc1191a0a52ef' +\ + 'f69f2445df4f9b17ad2b417be66c3710' + ciphertext = 'cdc80d6fddf18cab34c25909c99a4174' +\ + '67ce7f7f81173621961a2b70171d3d7a' +\ + '2e1e8a1dd59b88b1c8e60fed1efac4c9' +\ + 'c05f9f9ca9834fa042ae8fba584b09ff' + key = '8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b' + iv = '000102030405060708090a0b0c0d0e0f' + + key = unhexlify(key) + iv = unhexlify(iv) + plaintext = unhexlify(plaintext) + ciphertext = unhexlify(ciphertext) + + cipher = AES.new(key, AES.MODE_CFB, iv, segment_size=128) + self.assertEqual(cipher.encrypt(plaintext), ciphertext) + cipher = AES.new(key, AES.MODE_CFB, iv, segment_size=128) + self.assertEqual(cipher.decrypt(ciphertext), plaintext) + + def test_aes_256_cfb128(self): + plaintext = '6bc1bee22e409f96e93d7e117393172a' +\ + 'ae2d8a571e03ac9c9eb76fac45af8e51' +\ + '30c81c46a35ce411e5fbc1191a0a52ef' +\ + 'f69f2445df4f9b17ad2b417be66c3710' + + ciphertext = 'dc7e84bfda79164b7ecd8486985d3860' +\ + '39ffed143b28b1c832113c6331e5407b' +\ + 'df10132415e54b92a13ed0a8267ae2f9' +\ + '75a385741ab9cef82031623d55b1e471' + key = '603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4' + iv = '000102030405060708090a0b0c0d0e0f' + + key = unhexlify(key) + iv = unhexlify(iv) + plaintext = unhexlify(plaintext) + ciphertext = unhexlify(ciphertext) + + cipher = AES.new(key, AES.MODE_CFB, iv, segment_size=128) + self.assertEqual(cipher.encrypt(plaintext), ciphertext) + cipher = AES.new(key, AES.MODE_CFB, iv, segment_size=128) + self.assertEqual(cipher.decrypt(ciphertext), plaintext) + + +def get_tests(config={}): + tests = [] + tests += list_test_cases(CfbTests) + if config.get('slow_tests'): + tests += list_test_cases(NistCfbVectors) + tests += list_test_cases(SP800TestVectors) + return tests + + +if __name__ == '__main__': + suite = lambda: unittest.TestSuite(get_tests()) + unittest.main(defaultTest='suite') diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/test_CTR.py b/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/test_CTR.py new file mode 100644 index 0000000..ef5be5d --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/test_CTR.py @@ -0,0 +1,472 @@ +# =================================================================== +# +# Copyright (c) 2015, Legrandin +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# =================================================================== + +import unittest +from binascii import hexlify, unhexlify + +from Cryptodome.SelfTest.st_common import list_test_cases +from Cryptodome.Util.py3compat import tobytes, bchr +from Cryptodome.Cipher import AES, DES3 +from Cryptodome.Hash import SHAKE128, SHA256 +from Cryptodome.Util import Counter + +def get_tag_random(tag, length): + return SHAKE128.new(data=tobytes(tag)).read(length) + +class CtrTests(unittest.TestCase): + + key_128 = get_tag_random("key_128", 16) + key_192 = get_tag_random("key_192", 24) + nonce_32 = get_tag_random("nonce_32", 4) + nonce_64 = get_tag_random("nonce_64", 8) + ctr_64 = Counter.new(32, prefix=nonce_32) + ctr_128 = Counter.new(64, prefix=nonce_64) + + def test_loopback_128(self): + cipher = AES.new(self.key_128, AES.MODE_CTR, counter=self.ctr_128) + pt = get_tag_random("plaintext", 16 * 100) + ct = cipher.encrypt(pt) + + cipher = AES.new(self.key_128, AES.MODE_CTR, counter=self.ctr_128) + pt2 = cipher.decrypt(ct) + self.assertEqual(pt, pt2) + + def test_loopback_64(self): + cipher = DES3.new(self.key_192, DES3.MODE_CTR, counter=self.ctr_64) + pt = get_tag_random("plaintext", 8 * 100) + ct = cipher.encrypt(pt) + + cipher = DES3.new(self.key_192, DES3.MODE_CTR, counter=self.ctr_64) + pt2 = cipher.decrypt(ct) + self.assertEqual(pt, pt2) + + def test_invalid_counter_parameter(self): + # Counter object is required for ciphers with short block size + self.assertRaises(TypeError, DES3.new, self.key_192, AES.MODE_CTR) + # Positional arguments are not allowed (Counter must be passed as + # keyword) + self.assertRaises(TypeError, AES.new, self.key_128, AES.MODE_CTR, self.ctr_128) + + def test_nonce_attribute(self): + # Nonce attribute is the prefix passed to Counter (DES3) + cipher = DES3.new(self.key_192, DES3.MODE_CTR, counter=self.ctr_64) + self.assertEqual(cipher.nonce, self.nonce_32) + + # Nonce attribute is the prefix passed to Counter (AES) + cipher = AES.new(self.key_128, AES.MODE_CTR, counter=self.ctr_128) + self.assertEqual(cipher.nonce, self.nonce_64) + + # Nonce attribute is not defined if suffix is used in Counter + counter = Counter.new(64, prefix=self.nonce_32, suffix=self.nonce_32) + cipher = AES.new(self.key_128, AES.MODE_CTR, counter=counter) + self.assertFalse(hasattr(cipher, "nonce")) + + def test_nonce_parameter(self): + # Nonce parameter becomes nonce attribute + cipher1 = AES.new(self.key_128, AES.MODE_CTR, nonce=self.nonce_64) + self.assertEqual(cipher1.nonce, self.nonce_64) + + counter = Counter.new(64, prefix=self.nonce_64, initial_value=0) + cipher2 = AES.new(self.key_128, AES.MODE_CTR, counter=counter) + self.assertEqual(cipher1.nonce, cipher2.nonce) + + pt = get_tag_random("plaintext", 65536) + self.assertEqual(cipher1.encrypt(pt), cipher2.encrypt(pt)) + + # Nonce is implicitly created (for AES) when no parameters are passed + nonce1 = AES.new(self.key_128, AES.MODE_CTR).nonce + nonce2 = AES.new(self.key_128, AES.MODE_CTR).nonce + self.assertNotEqual(nonce1, nonce2) + self.assertEqual(len(nonce1), 8) + + # Nonce can be zero-length + cipher = AES.new(self.key_128, AES.MODE_CTR, nonce=b"") + self.assertEqual(b"", cipher.nonce) + cipher.encrypt(b'0'*300) + + # Nonce and Counter are mutually exclusive + self.assertRaises(TypeError, AES.new, self.key_128, AES.MODE_CTR, + counter=self.ctr_128, nonce=self.nonce_64) + + def test_initial_value_parameter(self): + # Test with nonce parameter + cipher1 = AES.new(self.key_128, AES.MODE_CTR, + nonce=self.nonce_64, initial_value=0xFFFF) + counter = Counter.new(64, prefix=self.nonce_64, initial_value=0xFFFF) + cipher2 = AES.new(self.key_128, AES.MODE_CTR, counter=counter) + pt = get_tag_random("plaintext", 65536) + self.assertEqual(cipher1.encrypt(pt), cipher2.encrypt(pt)) + + # Test without nonce parameter + cipher1 = AES.new(self.key_128, AES.MODE_CTR, + initial_value=0xFFFF) + counter = Counter.new(64, prefix=cipher1.nonce, initial_value=0xFFFF) + cipher2 = AES.new(self.key_128, AES.MODE_CTR, counter=counter) + pt = get_tag_random("plaintext", 65536) + self.assertEqual(cipher1.encrypt(pt), cipher2.encrypt(pt)) + + # Initial_value and Counter are mutually exclusive + self.assertRaises(TypeError, AES.new, self.key_128, AES.MODE_CTR, + counter=self.ctr_128, initial_value=0) + + def test_initial_value_bytes_parameter(self): + # Same result as when passing an integer + cipher1 = AES.new(self.key_128, AES.MODE_CTR, + nonce=self.nonce_64, + initial_value=b"\x00"*6+b"\xFF\xFF") + cipher2 = AES.new(self.key_128, AES.MODE_CTR, + nonce=self.nonce_64, initial_value=0xFFFF) + pt = get_tag_random("plaintext", 65536) + self.assertEqual(cipher1.encrypt(pt), cipher2.encrypt(pt)) + + # Fail if the iv is too large + self.assertRaises(ValueError, AES.new, self.key_128, AES.MODE_CTR, + initial_value=b"5"*17) + self.assertRaises(ValueError, AES.new, self.key_128, AES.MODE_CTR, + nonce=self.nonce_64, initial_value=b"5"*9) + + # Fail if the iv is too short + self.assertRaises(ValueError, AES.new, self.key_128, AES.MODE_CTR, + initial_value=b"5"*15) + self.assertRaises(ValueError, AES.new, self.key_128, AES.MODE_CTR, + nonce=self.nonce_64, initial_value=b"5"*7) + + def test_iv_with_matching_length(self): + self.assertRaises(ValueError, AES.new, self.key_128, AES.MODE_CTR, + counter=Counter.new(120)) + self.assertRaises(ValueError, AES.new, self.key_128, AES.MODE_CTR, + counter=Counter.new(136)) + + def test_block_size_128(self): + cipher = AES.new(self.key_128, AES.MODE_CTR, counter=self.ctr_128) + self.assertEqual(cipher.block_size, AES.block_size) + + def test_block_size_64(self): + cipher = DES3.new(self.key_192, DES3.MODE_CTR, counter=self.ctr_64) + self.assertEqual(cipher.block_size, DES3.block_size) + + def test_unaligned_data_128(self): + plaintexts = [ b"7777777" ] * 100 + + cipher = AES.new(self.key_128, AES.MODE_CTR, counter=self.ctr_128) + ciphertexts = [ cipher.encrypt(x) for x in plaintexts ] + cipher = AES.new(self.key_128, AES.MODE_CTR, counter=self.ctr_128) + self.assertEqual(b"".join(ciphertexts), cipher.encrypt(b"".join(plaintexts))) + + cipher = AES.new(self.key_128, AES.MODE_CTR, counter=self.ctr_128) + ciphertexts = [ cipher.encrypt(x) for x in plaintexts ] + cipher = AES.new(self.key_128, AES.MODE_CTR, counter=self.ctr_128) + self.assertEqual(b"".join(ciphertexts), cipher.encrypt(b"".join(plaintexts))) + + def test_unaligned_data_64(self): + plaintexts = [ b"7777777" ] * 100 + cipher = DES3.new(self.key_192, AES.MODE_CTR, counter=self.ctr_64) + ciphertexts = [ cipher.encrypt(x) for x in plaintexts ] + cipher = DES3.new(self.key_192, AES.MODE_CTR, counter=self.ctr_64) + self.assertEqual(b"".join(ciphertexts), cipher.encrypt(b"".join(plaintexts))) + + cipher = DES3.new(self.key_192, AES.MODE_CTR, counter=self.ctr_64) + ciphertexts = [ cipher.encrypt(x) for x in plaintexts ] + cipher = DES3.new(self.key_192, AES.MODE_CTR, counter=self.ctr_64) + self.assertEqual(b"".join(ciphertexts), cipher.encrypt(b"".join(plaintexts))) + + def test_unknown_parameters(self): + self.assertRaises(TypeError, AES.new, self.key_128, AES.MODE_CTR, + 7, counter=self.ctr_128) + self.assertRaises(TypeError, AES.new, self.key_128, AES.MODE_CTR, + counter=self.ctr_128, unknown=7) + # But some are only known by the base cipher (e.g. use_aesni consumed by the AES module) + AES.new(self.key_128, AES.MODE_CTR, counter=self.ctr_128, use_aesni=False) + + def test_null_encryption_decryption(self): + for func in "encrypt", "decrypt": + cipher = AES.new(self.key_128, AES.MODE_CTR, counter=self.ctr_128) + result = getattr(cipher, func)(b"") + self.assertEqual(result, b"") + + def test_either_encrypt_or_decrypt(self): + cipher = AES.new(self.key_128, AES.MODE_CTR, counter=self.ctr_128) + cipher.encrypt(b"") + self.assertRaises(TypeError, cipher.decrypt, b"") + + cipher = AES.new(self.key_128, AES.MODE_CTR, counter=self.ctr_128) + cipher.decrypt(b"") + self.assertRaises(TypeError, cipher.encrypt, b"") + + def test_wrap_around(self): + # Counter is only 8 bits, so we can only encrypt/decrypt 256 blocks (=4096 bytes) + counter = Counter.new(8, prefix=bchr(9) * 15) + max_bytes = 4096 + + cipher = AES.new(self.key_128, AES.MODE_CTR, counter=counter) + cipher.encrypt(b'9' * max_bytes) + self.assertRaises(OverflowError, cipher.encrypt, b'9') + + cipher = AES.new(self.key_128, AES.MODE_CTR, counter=counter) + self.assertRaises(OverflowError, cipher.encrypt, b'9' * (max_bytes + 1)) + + cipher = AES.new(self.key_128, AES.MODE_CTR, counter=counter) + cipher.decrypt(b'9' * max_bytes) + self.assertRaises(OverflowError, cipher.decrypt, b'9') + + cipher = AES.new(self.key_128, AES.MODE_CTR, counter=counter) + self.assertRaises(OverflowError, cipher.decrypt, b'9' * (max_bytes + 1)) + + def test_bytearray(self): + data = b"1" * 16 + iv = b"\x00" * 6 + b"\xFF\xFF" + + # Encrypt + cipher1 = AES.new(self.key_128, AES.MODE_CTR, + nonce=self.nonce_64, + initial_value=iv) + ref1 = cipher1.encrypt(data) + + cipher2 = AES.new(self.key_128, AES.MODE_CTR, + nonce=bytearray(self.nonce_64), + initial_value=bytearray(iv)) + ref2 = cipher2.encrypt(bytearray(data)) + + self.assertEqual(ref1, ref2) + self.assertEqual(cipher1.nonce, cipher2.nonce) + + # Decrypt + cipher3 = AES.new(self.key_128, AES.MODE_CTR, + nonce=self.nonce_64, + initial_value=iv) + ref3 = cipher3.decrypt(data) + + cipher4 = AES.new(self.key_128, AES.MODE_CTR, + nonce=bytearray(self.nonce_64), + initial_value=bytearray(iv)) + ref4 = cipher4.decrypt(bytearray(data)) + + self.assertEqual(ref3, ref4) + + def test_very_long_data(self): + cipher = AES.new(b'A' * 32, AES.MODE_CTR, nonce=b'') + ct = cipher.encrypt(b'B' * 1000000) + digest = SHA256.new(ct).hexdigest() + self.assertEqual(digest, "96204fc470476561a3a8f3b6fe6d24be85c87510b638142d1d0fb90989f8a6a6") + + def test_output_param(self): + + pt = b'5' * 128 + cipher = AES.new(b'4'*16, AES.MODE_CTR, nonce=self.nonce_64) + ct = cipher.encrypt(pt) + + output = bytearray(128) + cipher = AES.new(b'4'*16, AES.MODE_CTR, nonce=self.nonce_64) + res = cipher.encrypt(pt, output=output) + self.assertEqual(ct, output) + self.assertEqual(res, None) + + cipher = AES.new(b'4'*16, AES.MODE_CTR, nonce=self.nonce_64) + res = cipher.decrypt(ct, output=output) + self.assertEqual(pt, output) + self.assertEqual(res, None) + + def test_output_param_memoryview(self): + + pt = b'5' * 128 + cipher = AES.new(b'4'*16, AES.MODE_CTR, nonce=self.nonce_64) + ct = cipher.encrypt(pt) + + output = memoryview(bytearray(128)) + cipher = AES.new(b'4'*16, AES.MODE_CTR, nonce=self.nonce_64) + cipher.encrypt(pt, output=output) + self.assertEqual(ct, output) + + cipher = AES.new(b'4'*16, AES.MODE_CTR, nonce=self.nonce_64) + cipher.decrypt(ct, output=output) + self.assertEqual(pt, output) + + def test_output_param_neg(self): + LEN_PT = 128 + + pt = b'5' * LEN_PT + cipher = AES.new(b'4'*16, AES.MODE_CTR, nonce=self.nonce_64) + ct = cipher.encrypt(pt) + + cipher = AES.new(b'4'*16, AES.MODE_CTR, nonce=self.nonce_64) + self.assertRaises(TypeError, cipher.encrypt, pt, output=b'0' * LEN_PT) + + cipher = AES.new(b'4'*16, AES.MODE_CTR, nonce=self.nonce_64) + self.assertRaises(TypeError, cipher.decrypt, ct, output=b'0' * LEN_PT) + + shorter_output = bytearray(LEN_PT - 1) + cipher = AES.new(b'4'*16, AES.MODE_CTR, nonce=self.nonce_64) + self.assertRaises(ValueError, cipher.encrypt, pt, output=shorter_output) + cipher = AES.new(b'4'*16, AES.MODE_CTR, nonce=self.nonce_64) + self.assertRaises(ValueError, cipher.decrypt, ct, output=shorter_output) + + +class SP800TestVectors(unittest.TestCase): + """Class exercising the CTR test vectors found in Section F.5 + of NIST SP 800-38A""" + + def test_aes_128(self): + plaintext = '6bc1bee22e409f96e93d7e117393172a' +\ + 'ae2d8a571e03ac9c9eb76fac45af8e51' +\ + '30c81c46a35ce411e5fbc1191a0a52ef' +\ + 'f69f2445df4f9b17ad2b417be66c3710' + ciphertext = '874d6191b620e3261bef6864990db6ce' +\ + '9806f66b7970fdff8617187bb9fffdff' +\ + '5ae4df3edbd5d35e5b4f09020db03eab' +\ + '1e031dda2fbe03d1792170a0f3009cee' + key = '2b7e151628aed2a6abf7158809cf4f3c' + counter = Counter.new(nbits=16, + prefix=unhexlify('f0f1f2f3f4f5f6f7f8f9fafbfcfd'), + initial_value=0xfeff) + + key = unhexlify(key) + plaintext = unhexlify(plaintext) + ciphertext = unhexlify(ciphertext) + + cipher = AES.new(key, AES.MODE_CTR, counter=counter) + self.assertEqual(cipher.encrypt(plaintext), ciphertext) + cipher = AES.new(key, AES.MODE_CTR, counter=counter) + self.assertEqual(cipher.decrypt(ciphertext), plaintext) + + def test_aes_192(self): + plaintext = '6bc1bee22e409f96e93d7e117393172a' +\ + 'ae2d8a571e03ac9c9eb76fac45af8e51' +\ + '30c81c46a35ce411e5fbc1191a0a52ef' +\ + 'f69f2445df4f9b17ad2b417be66c3710' + ciphertext = '1abc932417521ca24f2b0459fe7e6e0b' +\ + '090339ec0aa6faefd5ccc2c6f4ce8e94' +\ + '1e36b26bd1ebc670d1bd1d665620abf7' +\ + '4f78a7f6d29809585a97daec58c6b050' + key = '8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b' + counter = Counter.new(nbits=16, + prefix=unhexlify('f0f1f2f3f4f5f6f7f8f9fafbfcfd'), + initial_value=0xfeff) + + key = unhexlify(key) + plaintext = unhexlify(plaintext) + ciphertext = unhexlify(ciphertext) + + cipher = AES.new(key, AES.MODE_CTR, counter=counter) + self.assertEqual(cipher.encrypt(plaintext), ciphertext) + cipher = AES.new(key, AES.MODE_CTR, counter=counter) + self.assertEqual(cipher.decrypt(ciphertext), plaintext) + + def test_aes_256(self): + plaintext = '6bc1bee22e409f96e93d7e117393172a' +\ + 'ae2d8a571e03ac9c9eb76fac45af8e51' +\ + '30c81c46a35ce411e5fbc1191a0a52ef' +\ + 'f69f2445df4f9b17ad2b417be66c3710' + ciphertext = '601ec313775789a5b7a7f504bbf3d228' +\ + 'f443e3ca4d62b59aca84e990cacaf5c5' +\ + '2b0930daa23de94ce87017ba2d84988d' +\ + 'dfc9c58db67aada613c2dd08457941a6' + key = '603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4' + counter = Counter.new(nbits=16, + prefix=unhexlify('f0f1f2f3f4f5f6f7f8f9fafbfcfd'), + initial_value=0xfeff) + key = unhexlify(key) + plaintext = unhexlify(plaintext) + ciphertext = unhexlify(ciphertext) + + cipher = AES.new(key, AES.MODE_CTR, counter=counter) + self.assertEqual(cipher.encrypt(plaintext), ciphertext) + cipher = AES.new(key, AES.MODE_CTR, counter=counter) + self.assertEqual(cipher.decrypt(ciphertext), plaintext) + + +class RFC3686TestVectors(unittest.TestCase): + + # Each item is a test vector with: + # - plaintext + # - ciphertext + # - key (AES 128, 192 or 256 bits) + # - counter prefix (4 byte nonce + 8 byte nonce) + data = ( + ('53696e676c6520626c6f636b206d7367', + 'e4095d4fb7a7b3792d6175a3261311b8', + 'ae6852f8121067cc4bf7a5765577f39e', + '000000300000000000000000'), + ('000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f', + '5104a106168a72d9790d41ee8edad388eb2e1efc46da57c8fce630df9141be28', + '7e24067817fae0d743d6ce1f32539163', + '006cb6dbc0543b59da48d90b'), + ('000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20212223', + 'c1cf48a89f2ffdd9cf4652e9efdb72d74540a42bde6d7836d59a5ceaaef3105325b2072f', + '7691be035e5020a8ac6e618529f9a0dc', + '00e0017b27777f3f4a1786f0'), + ('53696e676c6520626c6f636b206d7367', + '4b55384fe259c9c84e7935a003cbe928', + '16af5b145fc9f579c175f93e3bfb0eed863d06ccfdb78515', + '0000004836733c147d6d93cb'), + ('000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f', + '453243fc609b23327edfaafa7131cd9f8490701c5ad4a79cfc1fe0ff42f4fb00', + '7c5cb2401b3dc33c19e7340819e0f69c678c3db8e6f6a91a', + '0096b03b020c6eadc2cb500d'), + ('000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20212223', + '96893fc55e5c722f540b7dd1ddf7e758d288bc95c69165884536c811662f2188abee0935', + '02bf391ee8ecb159b959617b0965279bf59b60a786d3e0fe', + '0007bdfd5cbd60278dcc0912'), + ('53696e676c6520626c6f636b206d7367', + '145ad01dbf824ec7560863dc71e3e0c0', + '776beff2851db06f4c8a0542c8696f6c6a81af1eec96b4d37fc1d689e6c1c104', + '00000060db5672c97aa8f0b2'), + ('000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f', + 'f05e231b3894612c49ee000b804eb2a9b8306b508f839d6a5530831d9344af1c', + 'f6d66d6bd52d59bb0796365879eff886c66dd51a5b6a99744b50590c87a23884', + '00faac24c1585ef15a43d875'), + ('000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20212223', + 'eb6c52821d0bbbf7ce7594462aca4faab407df866569fd07f48cc0b583d6071f1ec0e6b8', + 'ff7a617ce69148e4f1726e2f43581de2aa62d9f805532edff1eed687fb54153d', + '001cc5b751a51d70a1c11148') + ) + + bindata = [] + for tv in data: + bindata.append([unhexlify(x) for x in tv]) + + def runTest(self): + for pt, ct, key, prefix in self.bindata: + counter = Counter.new(32, prefix=prefix) + cipher = AES.new(key, AES.MODE_CTR, counter=counter) + result = cipher.encrypt(pt) + self.assertEqual(hexlify(ct), hexlify(result)) + + +def get_tests(config={}): + tests = [] + tests += list_test_cases(CtrTests) + tests += list_test_cases(SP800TestVectors) + tests += [ RFC3686TestVectors() ] + return tests + + +if __name__ == '__main__': + suite = lambda: unittest.TestSuite(get_tests()) + unittest.main(defaultTest='suite') diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/test_ChaCha20.py b/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/test_ChaCha20.py new file mode 100644 index 0000000..92c6f3c --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/test_ChaCha20.py @@ -0,0 +1,529 @@ +# =================================================================== +# +# Copyright (c) 2014, Legrandin +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# =================================================================== + +import os +import re +import unittest +from binascii import hexlify, unhexlify + +from Cryptodome.Util.py3compat import b, tobytes, bchr +from Cryptodome.Util.strxor import strxor_c +from Cryptodome.SelfTest.st_common import list_test_cases + +from Cryptodome.Cipher import ChaCha20 + + +class ChaCha20Test(unittest.TestCase): + + def test_new_positive(self): + cipher = ChaCha20.new(key=b("0")*32, nonce=b"0"*8) + self.assertEqual(cipher.nonce, b"0" * 8) + cipher = ChaCha20.new(key=b("0")*32, nonce=b"0"*12) + self.assertEqual(cipher.nonce, b"0" * 12) + + def test_new_negative(self): + new = ChaCha20.new + self.assertRaises(TypeError, new) + self.assertRaises(TypeError, new, nonce=b("0")) + self.assertRaises(ValueError, new, nonce=b("0")*8, key=b("0")) + self.assertRaises(ValueError, new, nonce=b("0"), key=b("0")*32) + + def test_default_nonce(self): + cipher1 = ChaCha20.new(key=bchr(1) * 32) + cipher2 = ChaCha20.new(key=bchr(1) * 32) + self.assertEqual(len(cipher1.nonce), 8) + self.assertNotEqual(cipher1.nonce, cipher2.nonce) + + def test_nonce(self): + key = b'A' * 32 + + nonce1 = b'P' * 8 + cipher1 = ChaCha20.new(key=key, nonce=nonce1) + self.assertEqual(nonce1, cipher1.nonce) + + nonce2 = b'Q' * 12 + cipher2 = ChaCha20.new(key=key, nonce=nonce2) + self.assertEqual(nonce2, cipher2.nonce) + + def test_eiter_encrypt_or_decrypt(self): + """Verify that a cipher cannot be used for both decrypting and encrypting""" + + c1 = ChaCha20.new(key=b("5") * 32, nonce=b("6") * 8) + c1.encrypt(b("8")) + self.assertRaises(TypeError, c1.decrypt, b("9")) + + c2 = ChaCha20.new(key=b("5") * 32, nonce=b("6") * 8) + c2.decrypt(b("8")) + self.assertRaises(TypeError, c2.encrypt, b("9")) + + def test_round_trip(self): + pt = b("A") * 1024 + c1 = ChaCha20.new(key=b("5") * 32, nonce=b("6") * 8) + c2 = ChaCha20.new(key=b("5") * 32, nonce=b("6") * 8) + ct = c1.encrypt(pt) + self.assertEqual(c2.decrypt(ct), pt) + + self.assertEqual(c1.encrypt(b("")), b("")) + self.assertEqual(c2.decrypt(b("")), b("")) + + def test_streaming(self): + """Verify that an arbitrary number of bytes can be encrypted/decrypted""" + from Cryptodome.Hash import SHA1 + + segments = (1, 3, 5, 7, 11, 17, 23) + total = sum(segments) + + pt = b("") + while len(pt) < total: + pt += SHA1.new(pt).digest() + + cipher1 = ChaCha20.new(key=b("7") * 32, nonce=b("t") * 8) + ct = cipher1.encrypt(pt) + + cipher2 = ChaCha20.new(key=b("7") * 32, nonce=b("t") * 8) + cipher3 = ChaCha20.new(key=b("7") * 32, nonce=b("t") * 8) + idx = 0 + for segment in segments: + self.assertEqual(cipher2.decrypt(ct[idx:idx+segment]), pt[idx:idx+segment]) + self.assertEqual(cipher3.encrypt(pt[idx:idx+segment]), ct[idx:idx+segment]) + idx += segment + + def test_seek(self): + cipher1 = ChaCha20.new(key=b("9") * 32, nonce=b("e") * 8) + + offset = 64 * 900 + 7 + pt = b("1") * 64 + + cipher1.encrypt(b("0") * offset) + ct1 = cipher1.encrypt(pt) + + cipher2 = ChaCha20.new(key=b("9") * 32, nonce=b("e") * 8) + cipher2.seek(offset) + ct2 = cipher2.encrypt(pt) + + self.assertEqual(ct1, ct2) + + def test_seek_tv(self): + # Test Vector #4, A.1 from + # http://tools.ietf.org/html/draft-nir-cfrg-chacha20-poly1305-04 + key = bchr(0) + bchr(255) + bchr(0) * 30 + nonce = bchr(0) * 8 + cipher = ChaCha20.new(key=key, nonce=nonce) + cipher.seek(64 * 2) + expected_key_stream = unhexlify(b( + "72d54dfbf12ec44b362692df94137f32" + "8fea8da73990265ec1bbbea1ae9af0ca" + "13b25aa26cb4a648cb9b9d1be65b2c09" + "24a66c54d545ec1b7374f4872e99f096" + )) + ct = cipher.encrypt(bchr(0) * len(expected_key_stream)) + self.assertEqual(expected_key_stream, ct) + + def test_rfc7539(self): + # from https://tools.ietf.org/html/rfc7539 Annex A.1 + # Each item is: key, nonce, block #, plaintext, ciphertext + tvs = [ + # Test Vector #1 + ( + "00"*32, + "00"*12, + 0, + "00"*16*4, + "76b8e0ada0f13d90405d6ae55386bd28" + "bdd219b8a08ded1aa836efcc8b770dc7" + "da41597c5157488d7724e03fb8d84a37" + "6a43b8f41518a11cc387b669b2ee6586" + ), + # Test Vector #2 + ( + "00"*31 + "01", + "00"*11 + "02", + 1, + "416e79207375626d697373696f6e2074" + "6f20746865204945544620696e74656e" + "6465642062792074686520436f6e7472" + "696275746f7220666f72207075626c69" + "636174696f6e20617320616c6c206f72" + "2070617274206f6620616e2049455446" + "20496e7465726e65742d447261667420" + "6f722052464320616e6420616e792073" + "746174656d656e74206d616465207769" + "7468696e2074686520636f6e74657874" + "206f6620616e20494554462061637469" + "7669747920697320636f6e7369646572" + "656420616e20224945544620436f6e74" + "7269627574696f6e222e205375636820" + "73746174656d656e747320696e636c75" + "6465206f72616c2073746174656d656e" + "747320696e2049455446207365737369" + "6f6e732c2061732077656c6c20617320" + "7772697474656e20616e6420656c6563" + "74726f6e696320636f6d6d756e696361" + "74696f6e73206d61646520617420616e" + "792074696d65206f7220706c6163652c" + "20776869636820617265206164647265" + "7373656420746f", + "a3fbf07df3fa2fde4f376ca23e827370" + "41605d9f4f4f57bd8cff2c1d4b7955ec" + "2a97948bd3722915c8f3d337f7d37005" + "0e9e96d647b7c39f56e031ca5eb6250d" + "4042e02785ececfa4b4bb5e8ead0440e" + "20b6e8db09d881a7c6132f420e527950" + "42bdfa7773d8a9051447b3291ce1411c" + "680465552aa6c405b7764d5e87bea85a" + "d00f8449ed8f72d0d662ab052691ca66" + "424bc86d2df80ea41f43abf937d3259d" + "c4b2d0dfb48a6c9139ddd7f76966e928" + "e635553ba76c5c879d7b35d49eb2e62b" + "0871cdac638939e25e8a1e0ef9d5280f" + "a8ca328b351c3c765989cbcf3daa8b6c" + "cc3aaf9f3979c92b3720fc88dc95ed84" + "a1be059c6499b9fda236e7e818b04b0b" + "c39c1e876b193bfe5569753f88128cc0" + "8aaa9b63d1a16f80ef2554d7189c411f" + "5869ca52c5b83fa36ff216b9c1d30062" + "bebcfd2dc5bce0911934fda79a86f6e6" + "98ced759c3ff9b6477338f3da4f9cd85" + "14ea9982ccafb341b2384dd902f3d1ab" + "7ac61dd29c6f21ba5b862f3730e37cfd" + "c4fd806c22f221" + ), + # Test Vector #3 + ( + "1c9240a5eb55d38af333888604f6b5f0" + "473917c1402b80099dca5cbc207075c0", + "00"*11 + "02", + 42, + "2754776173206272696c6c69672c2061" + "6e642074686520736c6974687920746f" + "7665730a446964206779726520616e64" + "2067696d626c6520696e207468652077" + "6162653a0a416c6c206d696d73792077" + "6572652074686520626f726f676f7665" + "732c0a416e6420746865206d6f6d6520" + "7261746873206f757467726162652e", + "62e6347f95ed87a45ffae7426f27a1df" + "5fb69110044c0d73118effa95b01e5cf" + "166d3df2d721caf9b21e5fb14c616871" + "fd84c54f9d65b283196c7fe4f60553eb" + "f39c6402c42234e32a356b3e764312a6" + "1a5532055716ead6962568f87d3f3f77" + "04c6a8d1bcd1bf4d50d6154b6da731b1" + "87b58dfd728afa36757a797ac188d1" + ) + ] + + for tv in tvs: + key = unhexlify(tv[0]) + nonce = unhexlify(tv[1]) + offset = tv[2] * 64 + pt = unhexlify(tv[3]) + ct_expect = unhexlify(tv[4]) + + cipher = ChaCha20.new(key=key, nonce=nonce) + if offset != 0: + cipher.seek(offset) + ct = cipher.encrypt(pt) + assert(ct == ct_expect) + + +class XChaCha20Test(unittest.TestCase): + + # From https://tools.ietf.org/html/draft-arciszewski-xchacha-03 + + def test_hchacha20(self): + # Section 2.2.1 + + from Cryptodome.Cipher.ChaCha20 import _HChaCha20 + + key = b"00:01:02:03:04:05:06:07:08:09:0a:0b:0c:0d:0e:0f:10:11:12:13:14:15:16:17:18:19:1a:1b:1c:1d:1e:1f" + key = unhexlify(key.replace(b":", b"")) + + nonce = b"00:00:00:09:00:00:00:4a:00:00:00:00:31:41:59:27" + nonce = unhexlify(nonce.replace(b":", b"")) + + subkey = _HChaCha20(key, nonce) + + expected = b"82413b42 27b27bfe d30e4250 8a877d73 a0f9e4d5 8a74a853 c12ec413 26d3ecdc" + expected = unhexlify(expected.replace(b" ", b"")) + + self.assertEqual(subkey, expected) + + def test_nonce(self): + key = b'A' * 32 + nonce = b'P' * 24 + cipher = ChaCha20.new(key=key, nonce=nonce) + self.assertEqual(nonce, cipher.nonce) + + def test_encrypt(self): + # Section A.3.2 + + pt = b""" + 5468652064686f6c65202870726f6e6f756e6365642022646f6c652229206973 + 20616c736f206b6e6f776e2061732074686520417369617469632077696c6420 + 646f672c2072656420646f672c20616e642077686973746c696e6720646f672e + 2049742069732061626f7574207468652073697a65206f662061204765726d61 + 6e20736865706865726420627574206c6f6f6b73206d6f7265206c696b652061 + 206c6f6e672d6c656767656420666f782e205468697320686967686c7920656c + 757369766520616e6420736b696c6c6564206a756d70657220697320636c6173 + 736966696564207769746820776f6c7665732c20636f796f7465732c206a6163 + 6b616c732c20616e6420666f78657320696e20746865207461786f6e6f6d6963 + 2066616d696c792043616e696461652e""" + pt = unhexlify(pt.replace(b"\n", b"").replace(b" ", b"")) + + key = unhexlify(b"808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f") + iv = unhexlify(b"404142434445464748494a4b4c4d4e4f5051525354555658") + + ct = b""" + 7d0a2e6b7f7c65a236542630294e063b7ab9b555a5d5149aa21e4ae1e4fbce87 + ecc8e08a8b5e350abe622b2ffa617b202cfad72032a3037e76ffdcdc4376ee05 + 3a190d7e46ca1de04144850381b9cb29f051915386b8a710b8ac4d027b8b050f + 7cba5854e028d564e453b8a968824173fc16488b8970cac828f11ae53cabd201 + 12f87107df24ee6183d2274fe4c8b1485534ef2c5fbc1ec24bfc3663efaa08bc + 047d29d25043532db8391a8a3d776bf4372a6955827ccb0cdd4af403a7ce4c63 + d595c75a43e045f0cce1f29c8b93bd65afc5974922f214a40b7c402cdb91ae73 + c0b63615cdad0480680f16515a7ace9d39236464328a37743ffc28f4ddb324f4 + d0f5bbdc270c65b1749a6efff1fbaa09536175ccd29fb9e6057b307320d31683 + 8a9c71f70b5b5907a66f7ea49aadc409""" + ct = unhexlify(ct.replace(b"\n", b"").replace(b" ", b"")) + + cipher = ChaCha20.new(key=key, nonce=iv) + cipher.seek(64) # Counter = 1 + ct_test = cipher.encrypt(pt) + self.assertEqual(ct, ct_test) + + +class ByteArrayTest(unittest.TestCase): + """Verify we can encrypt or decrypt bytearrays""" + + def runTest(self): + + data = b"0123" + key = b"9" * 32 + nonce = b"t" * 8 + + # Encryption + data_ba = bytearray(data) + key_ba = bytearray(key) + nonce_ba = bytearray(nonce) + + cipher1 = ChaCha20.new(key=key, nonce=nonce) + ct = cipher1.encrypt(data) + + cipher2 = ChaCha20.new(key=key_ba, nonce=nonce_ba) + key_ba[:1] = b'\xFF' + nonce_ba[:1] = b'\xFF' + ct_test = cipher2.encrypt(data_ba) + + self.assertEqual(ct, ct_test) + self.assertEqual(cipher1.nonce, cipher2.nonce) + + # Decryption + key_ba = bytearray(key) + nonce_ba = bytearray(nonce) + ct_ba = bytearray(ct) + + cipher3 = ChaCha20.new(key=key_ba, nonce=nonce_ba) + key_ba[:1] = b'\xFF' + nonce_ba[:1] = b'\xFF' + pt_test = cipher3.decrypt(ct_ba) + + self.assertEqual(data, pt_test) + + +class MemoryviewTest(unittest.TestCase): + """Verify we can encrypt or decrypt bytearrays""" + + def runTest(self): + + data = b"0123" + key = b"9" * 32 + nonce = b"t" * 8 + + # Encryption + data_mv = memoryview(bytearray(data)) + key_mv = memoryview(bytearray(key)) + nonce_mv = memoryview(bytearray(nonce)) + + cipher1 = ChaCha20.new(key=key, nonce=nonce) + ct = cipher1.encrypt(data) + + cipher2 = ChaCha20.new(key=key_mv, nonce=nonce_mv) + key_mv[:1] = b'\xFF' + nonce_mv[:1] = b'\xFF' + ct_test = cipher2.encrypt(data_mv) + + self.assertEqual(ct, ct_test) + self.assertEqual(cipher1.nonce, cipher2.nonce) + + # Decryption + key_mv = memoryview(bytearray(key)) + nonce_mv = memoryview(bytearray(nonce)) + ct_mv = memoryview(bytearray(ct)) + + cipher3 = ChaCha20.new(key=key_mv, nonce=nonce_mv) + key_mv[:1] = b'\xFF' + nonce_mv[:1] = b'\xFF' + pt_test = cipher3.decrypt(ct_mv) + + self.assertEqual(data, pt_test) + + +class ChaCha20_AGL_NIR(unittest.TestCase): + + # From http://tools.ietf.org/html/draft-agl-tls-chacha20poly1305-04 + # and http://tools.ietf.org/html/draft-nir-cfrg-chacha20-poly1305-04 + tv = [ + ( "00" * 32, + "00" * 8, + "76b8e0ada0f13d90405d6ae55386bd28bdd219b8a08ded1aa836efcc" + "8b770dc7da41597c5157488d7724e03fb8d84a376a43b8f41518a11c" + "c387b669b2ee6586" + "9f07e7be5551387a98ba977c732d080d" + "cb0f29a048e3656912c6533e32ee7aed" + "29b721769ce64e43d57133b074d839d5" + "31ed1f28510afb45ace10a1f4b794d6f" + ), + ( "00" * 31 + "01", + "00" * 8, + "4540f05a9f1fb296d7736e7b208e3c96eb4fe1834688d2604f450952" + "ed432d41bbe2a0b6ea7566d2a5d1e7e20d42af2c53d792b1c43fea81" + "7e9ad275ae546963" + "3aeb5224ecf849929b9d828db1ced4dd" + "832025e8018b8160b82284f3c949aa5a" + "8eca00bbb4a73bdad192b5c42f73f2fd" + "4e273644c8b36125a64addeb006c13a0" + ), + ( "00" * 32, + "00" * 7 + "01", + "de9cba7bf3d69ef5e786dc63973f653a0b49e015adbff7134fcb7df1" + "37821031e85a050278a7084527214f73efc7fa5b5277062eb7a0433e" + "445f41e3" + ), + ( "00" * 32, + "01" + "00" * 7, + "ef3fdfd6c61578fbf5cf35bd3dd33b8009631634d21e42ac33960bd1" + "38e50d32111e4caf237ee53ca8ad6426194a88545ddc497a0b466e7d" + "6bbdb0041b2f586b" + ), + ( "000102030405060708090a0b0c0d0e0f101112131415161718191a1b" + "1c1d1e1f", + "0001020304050607", + "f798a189f195e66982105ffb640bb7757f579da31602fc93ec01ac56" + "f85ac3c134a4547b733b46413042c9440049176905d3be59ea1c53f1" + "5916155c2be8241a38008b9a26bc35941e2444177c8ade6689de9526" + "4986d95889fb60e84629c9bd9a5acb1cc118be563eb9b3a4a472f82e" + "09a7e778492b562ef7130e88dfe031c79db9d4f7c7a899151b9a4750" + "32b63fc385245fe054e3dd5a97a5f576fe064025d3ce042c566ab2c5" + "07b138db853e3d6959660996546cc9c4a6eafdc777c040d70eaf46f7" + "6dad3979e5c5360c3317166a1c894c94a371876a94df7628fe4eaaf2" + "ccb27d5aaae0ad7ad0f9d4b6ad3b54098746d4524d38407a6deb3ab7" + "8fab78c9" + ), + ( "00" * 32, + "00" * 7 + "02", + "c2c64d378cd536374ae204b9ef933fcd" + "1a8b2288b3dfa49672ab765b54ee27c7" + "8a970e0e955c14f3a88e741b97c286f7" + "5f8fc299e8148362fa198a39531bed6d" + ), + ] + + def runTest(self): + for (key, nonce, stream) in self.tv: + c = ChaCha20.new(key=unhexlify(b(key)), nonce=unhexlify(b(nonce))) + ct = unhexlify(b(stream)) + pt = b("\x00") * len(ct) + self.assertEqual(c.encrypt(pt), ct) + + +class TestOutput(unittest.TestCase): + + def runTest(self): + # Encrypt/Decrypt data and test output parameter + + key = b'4' * 32 + nonce = b'5' * 8 + cipher = ChaCha20.new(key=key, nonce=nonce) + + pt = b'5' * 300 + ct = cipher.encrypt(pt) + + output = bytearray(len(pt)) + cipher = ChaCha20.new(key=key, nonce=nonce) + res = cipher.encrypt(pt, output=output) + self.assertEqual(ct, output) + self.assertEqual(res, None) + + cipher = ChaCha20.new(key=key, nonce=nonce) + res = cipher.decrypt(ct, output=output) + self.assertEqual(pt, output) + self.assertEqual(res, None) + + output = memoryview(bytearray(len(pt))) + cipher = ChaCha20.new(key=key, nonce=nonce) + cipher.encrypt(pt, output=output) + self.assertEqual(ct, output) + + cipher = ChaCha20.new(key=key, nonce=nonce) + cipher.decrypt(ct, output=output) + self.assertEqual(pt, output) + + cipher = ChaCha20.new(key=key, nonce=nonce) + self.assertRaises(TypeError, cipher.encrypt, pt, output=b'0'*len(pt)) + + cipher = ChaCha20.new(key=key, nonce=nonce) + self.assertRaises(TypeError, cipher.decrypt, ct, output=b'0'*len(pt)) + + shorter_output = bytearray(len(pt) - 1) + + cipher = ChaCha20.new(key=key, nonce=nonce) + self.assertRaises(ValueError, cipher.encrypt, pt, output=shorter_output) + + cipher = ChaCha20.new(key=key, nonce=nonce) + self.assertRaises(ValueError, cipher.decrypt, ct, output=shorter_output) + + +def get_tests(config={}): + tests = [] + tests += list_test_cases(ChaCha20Test) + tests += list_test_cases(XChaCha20Test) + tests.append(ChaCha20_AGL_NIR()) + tests.append(ByteArrayTest()) + tests.append(MemoryviewTest()) + tests.append(TestOutput()) + + return tests + + +if __name__ == '__main__': + import unittest + suite = lambda: unittest.TestSuite(get_tests()) + unittest.main(defaultTest='suite') diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/test_ChaCha20_Poly1305.py b/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/test_ChaCha20_Poly1305.py new file mode 100644 index 0000000..495028a --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/test_ChaCha20_Poly1305.py @@ -0,0 +1,776 @@ +# =================================================================== +# +# Copyright (c) 2018, Helder Eijs +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# =================================================================== + +import unittest +from binascii import unhexlify + +from Cryptodome.SelfTest.st_common import list_test_cases +from Cryptodome.SelfTest.loader import load_test_vectors_wycheproof +from Cryptodome.Util.py3compat import tobytes +from Cryptodome.Cipher import ChaCha20_Poly1305 +from Cryptodome.Hash import SHAKE128 + +from Cryptodome.Util.strxor import strxor + + +def get_tag_random(tag, length): + return SHAKE128.new(data=tobytes(tag)).read(length) + + +class ChaCha20Poly1305Tests(unittest.TestCase): + + key_256 = get_tag_random("key_256", 32) + nonce_96 = get_tag_random("nonce_96", 12) + data_128 = get_tag_random("data_128", 16) + + def test_loopback(self): + cipher = ChaCha20_Poly1305.new(key=self.key_256, + nonce=self.nonce_96) + pt = get_tag_random("plaintext", 16 * 100) + ct = cipher.encrypt(pt) + + cipher = ChaCha20_Poly1305.new(key=self.key_256, + nonce=self.nonce_96) + pt2 = cipher.decrypt(ct) + self.assertEqual(pt, pt2) + + def test_nonce(self): + # Nonce can only be 8 or 12 bytes + cipher = ChaCha20_Poly1305.new(key=self.key_256, + nonce=b'H' * 8) + self.assertEqual(len(cipher.nonce), 8) + cipher = ChaCha20_Poly1305.new(key=self.key_256, + nonce=b'H' * 12) + self.assertEqual(len(cipher.nonce), 12) + + # If not passed, the nonce is created randomly + cipher = ChaCha20_Poly1305.new(key=self.key_256) + nonce1 = cipher.nonce + cipher = ChaCha20_Poly1305.new(key=self.key_256) + nonce2 = cipher.nonce + self.assertEqual(len(nonce1), 12) + self.assertNotEqual(nonce1, nonce2) + + cipher = ChaCha20_Poly1305.new(key=self.key_256, + nonce=self.nonce_96) + ct = cipher.encrypt(self.data_128) + + cipher = ChaCha20_Poly1305.new(key=self.key_256, + nonce=self.nonce_96) + self.assertEqual(ct, cipher.encrypt(self.data_128)) + + def test_nonce_must_be_bytes(self): + self.assertRaises(TypeError, + ChaCha20_Poly1305.new, + key=self.key_256, + nonce=u'test12345678') + + def test_nonce_length(self): + # nonce can only be 8 or 12 bytes long + self.assertRaises(ValueError, + ChaCha20_Poly1305.new, + key=self.key_256, + nonce=b'0' * 7) + self.assertRaises(ValueError, + ChaCha20_Poly1305.new, + key=self.key_256, + nonce=b'') + + def test_block_size(self): + # Not based on block ciphers + cipher = ChaCha20_Poly1305.new(key=self.key_256, + nonce=self.nonce_96) + self.assertFalse(hasattr(cipher, 'block_size')) + + def test_nonce_attribute(self): + cipher = ChaCha20_Poly1305.new(key=self.key_256, + nonce=self.nonce_96) + self.assertEqual(cipher.nonce, self.nonce_96) + + # By default, a 12 bytes long nonce is randomly generated + nonce1 = ChaCha20_Poly1305.new(key=self.key_256).nonce + nonce2 = ChaCha20_Poly1305.new(key=self.key_256).nonce + self.assertEqual(len(nonce1), 12) + self.assertNotEqual(nonce1, nonce2) + + def test_unknown_parameters(self): + self.assertRaises(TypeError, + ChaCha20_Poly1305.new, + key=self.key_256, + param=9) + + def test_null_encryption_decryption(self): + for func in "encrypt", "decrypt": + cipher = ChaCha20_Poly1305.new(key=self.key_256, + nonce=self.nonce_96) + result = getattr(cipher, func)(b"") + self.assertEqual(result, b"") + + def test_either_encrypt_or_decrypt(self): + cipher = ChaCha20_Poly1305.new(key=self.key_256, + nonce=self.nonce_96) + cipher.encrypt(b"") + self.assertRaises(TypeError, cipher.decrypt, b"") + + cipher = ChaCha20_Poly1305.new(key=self.key_256, + nonce=self.nonce_96) + cipher.decrypt(b"") + self.assertRaises(TypeError, cipher.encrypt, b"") + + def test_data_must_be_bytes(self): + cipher = ChaCha20_Poly1305.new(key=self.key_256, + nonce=self.nonce_96) + self.assertRaises(TypeError, cipher.encrypt, u'test1234567890-*') + + cipher = ChaCha20_Poly1305.new(key=self.key_256, + nonce=self.nonce_96) + self.assertRaises(TypeError, cipher.decrypt, u'test1234567890-*') + + def test_mac_len(self): + cipher = ChaCha20_Poly1305.new(key=self.key_256, + nonce=self.nonce_96) + _, mac = cipher.encrypt_and_digest(self.data_128) + self.assertEqual(len(mac), 16) + + def test_invalid_mac(self): + from Cryptodome.Util.strxor import strxor_c + cipher = ChaCha20_Poly1305.new(key=self.key_256, + nonce=self.nonce_96) + ct, mac = cipher.encrypt_and_digest(self.data_128) + + invalid_mac = strxor_c(mac, 0x01) + + cipher = ChaCha20_Poly1305.new(key=self.key_256, + nonce=self.nonce_96) + self.assertRaises(ValueError, cipher.decrypt_and_verify, ct, + invalid_mac) + + def test_hex_mac(self): + cipher = ChaCha20_Poly1305.new(key=self.key_256, + nonce=self.nonce_96) + mac_hex = cipher.hexdigest() + self.assertEqual(cipher.digest(), unhexlify(mac_hex)) + + cipher = ChaCha20_Poly1305.new(key=self.key_256, + nonce=self.nonce_96) + cipher.hexverify(mac_hex) + + def test_message_chunks(self): + # Validate that both associated data and plaintext/ciphertext + # can be broken up in chunks of arbitrary length + + auth_data = get_tag_random("authenticated data", 127) + plaintext = get_tag_random("plaintext", 127) + + cipher = ChaCha20_Poly1305.new(key=self.key_256, + nonce=self.nonce_96) + cipher.update(auth_data) + ciphertext, ref_mac = cipher.encrypt_and_digest(plaintext) + + def break_up(data, chunk_length): + return [data[i:i+chunk_length] for i in range(0, len(data), + chunk_length)] + + # Encryption + for chunk_length in 1, 2, 3, 7, 10, 13, 16, 40, 80, 128: + + cipher = ChaCha20_Poly1305.new(key=self.key_256, + nonce=self.nonce_96) + + for chunk in break_up(auth_data, chunk_length): + cipher.update(chunk) + pt2 = b"" + for chunk in break_up(ciphertext, chunk_length): + pt2 += cipher.decrypt(chunk) + self.assertEqual(plaintext, pt2) + cipher.verify(ref_mac) + + # Decryption + for chunk_length in 1, 2, 3, 7, 10, 13, 16, 40, 80, 128: + + cipher = ChaCha20_Poly1305.new(key=self.key_256, + nonce=self.nonce_96) + + for chunk in break_up(auth_data, chunk_length): + cipher.update(chunk) + ct2 = b"" + for chunk in break_up(plaintext, chunk_length): + ct2 += cipher.encrypt(chunk) + self.assertEqual(ciphertext, ct2) + self.assertEqual(cipher.digest(), ref_mac) + + def test_bytearray(self): + + # Encrypt + key_ba = bytearray(self.key_256) + nonce_ba = bytearray(self.nonce_96) + header_ba = bytearray(self.data_128) + data_ba = bytearray(self.data_128) + + cipher1 = ChaCha20_Poly1305.new(key=self.key_256, + nonce=self.nonce_96) + cipher1.update(self.data_128) + ct = cipher1.encrypt(self.data_128) + tag = cipher1.digest() + + cipher2 = ChaCha20_Poly1305.new(key=self.key_256, + nonce=self.nonce_96) + key_ba[:3] = b'\xFF\xFF\xFF' + nonce_ba[:3] = b'\xFF\xFF\xFF' + cipher2.update(header_ba) + header_ba[:3] = b'\xFF\xFF\xFF' + ct_test = cipher2.encrypt(data_ba) + data_ba[:3] = b'\x99\x99\x99' + tag_test = cipher2.digest() + + self.assertEqual(ct, ct_test) + self.assertEqual(tag, tag_test) + self.assertEqual(cipher1.nonce, cipher2.nonce) + + # Decrypt + key_ba = bytearray(self.key_256) + nonce_ba = bytearray(self.nonce_96) + header_ba = bytearray(self.data_128) + ct_ba = bytearray(ct) + tag_ba = bytearray(tag) + del data_ba + + cipher3 = ChaCha20_Poly1305.new(key=self.key_256, + nonce=self.nonce_96) + key_ba[:3] = b'\xFF\xFF\xFF' + nonce_ba[:3] = b'\xFF\xFF\xFF' + cipher3.update(header_ba) + header_ba[:3] = b'\xFF\xFF\xFF' + pt_test = cipher3.decrypt(ct_ba) + ct_ba[:3] = b'\xFF\xFF\xFF' + cipher3.verify(tag_ba) + + self.assertEqual(pt_test, self.data_128) + + def test_memoryview(self): + + # Encrypt + key_mv = memoryview(bytearray(self.key_256)) + nonce_mv = memoryview(bytearray(self.nonce_96)) + header_mv = memoryview(bytearray(self.data_128)) + data_mv = memoryview(bytearray(self.data_128)) + + cipher1 = ChaCha20_Poly1305.new(key=self.key_256, + nonce=self.nonce_96) + cipher1.update(self.data_128) + ct = cipher1.encrypt(self.data_128) + tag = cipher1.digest() + + cipher2 = ChaCha20_Poly1305.new(key=self.key_256, + nonce=self.nonce_96) + key_mv[:3] = b'\xFF\xFF\xFF' + nonce_mv[:3] = b'\xFF\xFF\xFF' + cipher2.update(header_mv) + header_mv[:3] = b'\xFF\xFF\xFF' + ct_test = cipher2.encrypt(data_mv) + data_mv[:3] = b'\x99\x99\x99' + tag_test = cipher2.digest() + + self.assertEqual(ct, ct_test) + self.assertEqual(tag, tag_test) + self.assertEqual(cipher1.nonce, cipher2.nonce) + + # Decrypt + key_mv = memoryview(bytearray(self.key_256)) + nonce_mv = memoryview(bytearray(self.nonce_96)) + header_mv = memoryview(bytearray(self.data_128)) + ct_mv = memoryview(bytearray(ct)) + tag_mv = memoryview(bytearray(tag)) + del data_mv + + cipher3 = ChaCha20_Poly1305.new(key=self.key_256, + nonce=self.nonce_96) + key_mv[:3] = b'\xFF\xFF\xFF' + nonce_mv[:3] = b'\xFF\xFF\xFF' + cipher3.update(header_mv) + header_mv[:3] = b'\xFF\xFF\xFF' + pt_test = cipher3.decrypt(ct_mv) + ct_mv[:3] = b'\x99\x99\x99' + cipher3.verify(tag_mv) + + self.assertEqual(pt_test, self.data_128) + + +class XChaCha20Poly1305Tests(unittest.TestCase): + + def test_nonce(self): + # Nonce can only be 24 bytes + cipher = ChaCha20_Poly1305.new(key=b'Y' * 32, + nonce=b'H' * 24) + self.assertEqual(len(cipher.nonce), 24) + self.assertEqual(cipher.nonce, b'H' * 24) + + def test_encrypt(self): + # From https://tools.ietf.org/html/draft-arciszewski-xchacha-03 + # Section A.3.1 + + pt = b""" + 4c616469657320616e642047656e746c656d656e206f662074686520636c6173 + 73206f66202739393a204966204920636f756c64206f6666657220796f75206f + 6e6c79206f6e652074697020666f7220746865206675747572652c2073756e73 + 637265656e20776f756c642062652069742e""" + pt = unhexlify(pt.replace(b"\n", b"").replace(b" ", b"")) + + aad = unhexlify(b"50515253c0c1c2c3c4c5c6c7") + key = unhexlify(b"808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f") + iv = unhexlify(b"404142434445464748494a4b4c4d4e4f5051525354555657") + + ct = b""" + bd6d179d3e83d43b9576579493c0e939572a1700252bfaccbed2902c21396cbb + 731c7f1b0b4aa6440bf3a82f4eda7e39ae64c6708c54c216cb96b72e1213b452 + 2f8c9ba40db5d945b11b69b982c1bb9e3f3fac2bc369488f76b2383565d3fff9 + 21f9664c97637da9768812f615c68b13b52e""" + ct = unhexlify(ct.replace(b"\n", b"").replace(b" ", b"")) + + tag = unhexlify(b"c0875924c1c7987947deafd8780acf49") + + cipher = ChaCha20_Poly1305.new(key=key, nonce=iv) + cipher.update(aad) + ct_test, tag_test = cipher.encrypt_and_digest(pt) + + self.assertEqual(ct, ct_test) + self.assertEqual(tag, tag_test) + + cipher = ChaCha20_Poly1305.new(key=key, nonce=iv) + cipher.update(aad) + cipher.decrypt_and_verify(ct, tag) + + +class ChaCha20Poly1305FSMTests(unittest.TestCase): + + key_256 = get_tag_random("key_256", 32) + nonce_96 = get_tag_random("nonce_96", 12) + data_128 = get_tag_random("data_128", 16) + + def test_valid_init_encrypt_decrypt_digest_verify(self): + # No authenticated data, fixed plaintext + # Verify path INIT->ENCRYPT->DIGEST + cipher = ChaCha20_Poly1305.new(key=self.key_256, + nonce=self.nonce_96) + ct = cipher.encrypt(self.data_128) + mac = cipher.digest() + + # Verify path INIT->DECRYPT->VERIFY + cipher = ChaCha20_Poly1305.new(key=self.key_256, + nonce=self.nonce_96) + cipher.decrypt(ct) + cipher.verify(mac) + + def test_valid_init_update_digest_verify(self): + # No plaintext, fixed authenticated data + # Verify path INIT->UPDATE->DIGEST + cipher = ChaCha20_Poly1305.new(key=self.key_256, + nonce=self.nonce_96) + cipher.update(self.data_128) + mac = cipher.digest() + + # Verify path INIT->UPDATE->VERIFY + cipher = ChaCha20_Poly1305.new(key=self.key_256, + nonce=self.nonce_96) + cipher.update(self.data_128) + cipher.verify(mac) + + def test_valid_full_path(self): + # Fixed authenticated data, fixed plaintext + # Verify path INIT->UPDATE->ENCRYPT->DIGEST + cipher = ChaCha20_Poly1305.new(key=self.key_256, + nonce=self.nonce_96) + cipher.update(self.data_128) + ct = cipher.encrypt(self.data_128) + mac = cipher.digest() + + # Verify path INIT->UPDATE->DECRYPT->VERIFY + cipher = ChaCha20_Poly1305.new(key=self.key_256, + nonce=self.nonce_96) + cipher.update(self.data_128) + cipher.decrypt(ct) + cipher.verify(mac) + + def test_valid_init_digest(self): + # Verify path INIT->DIGEST + cipher = ChaCha20_Poly1305.new(key=self.key_256, + nonce=self.nonce_96) + cipher.digest() + + def test_valid_init_verify(self): + # Verify path INIT->VERIFY + cipher = ChaCha20_Poly1305.new(key=self.key_256, + nonce=self.nonce_96) + mac = cipher.digest() + + cipher = ChaCha20_Poly1305.new(key=self.key_256, + nonce=self.nonce_96) + cipher.verify(mac) + + def test_valid_multiple_encrypt_or_decrypt(self): + for method_name in "encrypt", "decrypt": + for auth_data in (None, b"333", self.data_128, + self.data_128 + b"3"): + cipher = ChaCha20_Poly1305.new(key=self.key_256, + nonce=self.nonce_96) + if auth_data is not None: + cipher.update(auth_data) + method = getattr(cipher, method_name) + method(self.data_128) + method(self.data_128) + method(self.data_128) + method(self.data_128) + + def test_valid_multiple_digest_or_verify(self): + # Multiple calls to digest + cipher = ChaCha20_Poly1305.new(key=self.key_256, + nonce=self.nonce_96) + cipher.update(self.data_128) + first_mac = cipher.digest() + for x in range(4): + self.assertEqual(first_mac, cipher.digest()) + + # Multiple calls to verify + cipher = ChaCha20_Poly1305.new(key=self.key_256, + nonce=self.nonce_96) + cipher.update(self.data_128) + for x in range(5): + cipher.verify(first_mac) + + def test_valid_encrypt_and_digest_decrypt_and_verify(self): + # encrypt_and_digest + cipher = ChaCha20_Poly1305.new(key=self.key_256, + nonce=self.nonce_96) + cipher.update(self.data_128) + ct, mac = cipher.encrypt_and_digest(self.data_128) + + # decrypt_and_verify + cipher = ChaCha20_Poly1305.new(key=self.key_256, + nonce=self.nonce_96) + cipher.update(self.data_128) + pt = cipher.decrypt_and_verify(ct, mac) + self.assertEqual(self.data_128, pt) + + def test_invalid_mixing_encrypt_decrypt(self): + # Once per method, with or without assoc. data + for method1_name, method2_name in (("encrypt", "decrypt"), + ("decrypt", "encrypt")): + for assoc_data_present in (True, False): + cipher = ChaCha20_Poly1305.new(key=self.key_256, + nonce=self.nonce_96) + if assoc_data_present: + cipher.update(self.data_128) + getattr(cipher, method1_name)(self.data_128) + self.assertRaises(TypeError, getattr(cipher, method2_name), + self.data_128) + + def test_invalid_encrypt_or_update_after_digest(self): + for method_name in "encrypt", "update": + cipher = ChaCha20_Poly1305.new(key=self.key_256, + nonce=self.nonce_96) + cipher.encrypt(self.data_128) + cipher.digest() + self.assertRaises(TypeError, getattr(cipher, method_name), + self.data_128) + + cipher = ChaCha20_Poly1305.new(key=self.key_256, + nonce=self.nonce_96) + cipher.encrypt_and_digest(self.data_128) + + def test_invalid_decrypt_or_update_after_verify(self): + cipher = ChaCha20_Poly1305.new(key=self.key_256, + nonce=self.nonce_96) + ct = cipher.encrypt(self.data_128) + mac = cipher.digest() + + for method_name in "decrypt", "update": + cipher = ChaCha20_Poly1305.new(key=self.key_256, + nonce=self.nonce_96) + cipher.decrypt(ct) + cipher.verify(mac) + self.assertRaises(TypeError, getattr(cipher, method_name), + self.data_128) + + cipher = ChaCha20_Poly1305.new(key=self.key_256, + nonce=self.nonce_96) + cipher.decrypt(ct) + cipher.verify(mac) + self.assertRaises(TypeError, getattr(cipher, method_name), + self.data_128) + + cipher = ChaCha20_Poly1305.new(key=self.key_256, + nonce=self.nonce_96) + cipher.decrypt_and_verify(ct, mac) + self.assertRaises(TypeError, getattr(cipher, method_name), + self.data_128) + + +def compact(x): + return unhexlify(x.replace(" ", "").replace(":", "")) + + +class TestVectorsRFC(unittest.TestCase): + """Test cases from RFC7539""" + + # AAD, PT, CT, MAC, KEY, NONCE + test_vectors_hex = [ + ( '50 51 52 53 c0 c1 c2 c3 c4 c5 c6 c7', + '4c 61 64 69 65 73 20 61 6e 64 20 47 65 6e 74 6c' + '65 6d 65 6e 20 6f 66 20 74 68 65 20 63 6c 61 73' + '73 20 6f 66 20 27 39 39 3a 20 49 66 20 49 20 63' + '6f 75 6c 64 20 6f 66 66 65 72 20 79 6f 75 20 6f' + '6e 6c 79 20 6f 6e 65 20 74 69 70 20 66 6f 72 20' + '74 68 65 20 66 75 74 75 72 65 2c 20 73 75 6e 73' + '63 72 65 65 6e 20 77 6f 75 6c 64 20 62 65 20 69' + '74 2e', + 'd3 1a 8d 34 64 8e 60 db 7b 86 af bc 53 ef 7e c2' + 'a4 ad ed 51 29 6e 08 fe a9 e2 b5 a7 36 ee 62 d6' + '3d be a4 5e 8c a9 67 12 82 fa fb 69 da 92 72 8b' + '1a 71 de 0a 9e 06 0b 29 05 d6 a5 b6 7e cd 3b 36' + '92 dd bd 7f 2d 77 8b 8c 98 03 ae e3 28 09 1b 58' + 'fa b3 24 e4 fa d6 75 94 55 85 80 8b 48 31 d7 bc' + '3f f4 de f0 8e 4b 7a 9d e5 76 d2 65 86 ce c6 4b' + '61 16', + '1a:e1:0b:59:4f:09:e2:6a:7e:90:2e:cb:d0:60:06:91', + '80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f' + '90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f', + '07 00 00 00' + '40 41 42 43 44 45 46 47', + ), + ( 'f3 33 88 86 00 00 00 00 00 00 4e 91', + '49 6e 74 65 72 6e 65 74 2d 44 72 61 66 74 73 20' + '61 72 65 20 64 72 61 66 74 20 64 6f 63 75 6d 65' + '6e 74 73 20 76 61 6c 69 64 20 66 6f 72 20 61 20' + '6d 61 78 69 6d 75 6d 20 6f 66 20 73 69 78 20 6d' + '6f 6e 74 68 73 20 61 6e 64 20 6d 61 79 20 62 65' + '20 75 70 64 61 74 65 64 2c 20 72 65 70 6c 61 63' + '65 64 2c 20 6f 72 20 6f 62 73 6f 6c 65 74 65 64' + '20 62 79 20 6f 74 68 65 72 20 64 6f 63 75 6d 65' + '6e 74 73 20 61 74 20 61 6e 79 20 74 69 6d 65 2e' + '20 49 74 20 69 73 20 69 6e 61 70 70 72 6f 70 72' + '69 61 74 65 20 74 6f 20 75 73 65 20 49 6e 74 65' + '72 6e 65 74 2d 44 72 61 66 74 73 20 61 73 20 72' + '65 66 65 72 65 6e 63 65 20 6d 61 74 65 72 69 61' + '6c 20 6f 72 20 74 6f 20 63 69 74 65 20 74 68 65' + '6d 20 6f 74 68 65 72 20 74 68 61 6e 20 61 73 20' + '2f e2 80 9c 77 6f 72 6b 20 69 6e 20 70 72 6f 67' + '72 65 73 73 2e 2f e2 80 9d', + '64 a0 86 15 75 86 1a f4 60 f0 62 c7 9b e6 43 bd' + '5e 80 5c fd 34 5c f3 89 f1 08 67 0a c7 6c 8c b2' + '4c 6c fc 18 75 5d 43 ee a0 9e e9 4e 38 2d 26 b0' + 'bd b7 b7 3c 32 1b 01 00 d4 f0 3b 7f 35 58 94 cf' + '33 2f 83 0e 71 0b 97 ce 98 c8 a8 4a bd 0b 94 81' + '14 ad 17 6e 00 8d 33 bd 60 f9 82 b1 ff 37 c8 55' + '97 97 a0 6e f4 f0 ef 61 c1 86 32 4e 2b 35 06 38' + '36 06 90 7b 6a 7c 02 b0 f9 f6 15 7b 53 c8 67 e4' + 'b9 16 6c 76 7b 80 4d 46 a5 9b 52 16 cd e7 a4 e9' + '90 40 c5 a4 04 33 22 5e e2 82 a1 b0 a0 6c 52 3e' + 'af 45 34 d7 f8 3f a1 15 5b 00 47 71 8c bc 54 6a' + '0d 07 2b 04 b3 56 4e ea 1b 42 22 73 f5 48 27 1a' + '0b b2 31 60 53 fa 76 99 19 55 eb d6 31 59 43 4e' + 'ce bb 4e 46 6d ae 5a 10 73 a6 72 76 27 09 7a 10' + '49 e6 17 d9 1d 36 10 94 fa 68 f0 ff 77 98 71 30' + '30 5b ea ba 2e da 04 df 99 7b 71 4d 6c 6f 2c 29' + 'a6 ad 5c b4 02 2b 02 70 9b', + 'ee ad 9d 67 89 0c bb 22 39 23 36 fe a1 85 1f 38', + '1c 92 40 a5 eb 55 d3 8a f3 33 88 86 04 f6 b5 f0' + '47 39 17 c1 40 2b 80 09 9d ca 5c bc 20 70 75 c0', + '00 00 00 00 01 02 03 04 05 06 07 08', + ) + ] + + test_vectors = [[unhexlify(x.replace(" ", "").replace(":", "")) for x in tv] for tv in test_vectors_hex] + + def runTest(self): + for assoc_data, pt, ct, mac, key, nonce in self.test_vectors: + # Encrypt + cipher = ChaCha20_Poly1305.new(key=key, nonce=nonce) + cipher.update(assoc_data) + ct2, mac2 = cipher.encrypt_and_digest(pt) + self.assertEqual(ct, ct2) + self.assertEqual(mac, mac2) + + # Decrypt + cipher = ChaCha20_Poly1305.new(key=key, nonce=nonce) + cipher.update(assoc_data) + pt2 = cipher.decrypt_and_verify(ct, mac) + self.assertEqual(pt, pt2) + + +class TestVectorsWycheproof(unittest.TestCase): + + def __init__(self, wycheproof_warnings): + unittest.TestCase.__init__(self) + self._wycheproof_warnings = wycheproof_warnings + self._id = "None" + + def load_tests(self, filename): + + def filter_tag(group): + return group['tagSize'] // 8 + + def filter_algo(root): + return root['algorithm'] + + result = load_test_vectors_wycheproof(("Cipher", "wycheproof"), + filename, + "Wycheproof ChaCha20-Poly1305", + root_tag={'algo': filter_algo}, + group_tag={'tag_size': filter_tag}) + return result + + def setUp(self): + self.tv = [] + self.tv.extend(self.load_tests("chacha20_poly1305_test.json")) + self.tv.extend(self.load_tests("xchacha20_poly1305_test.json")) + + def shortDescription(self): + return self._id + + def warn(self, tv): + if tv.warning and self._wycheproof_warnings: + import warnings + warnings.warn("Wycheproof warning: %s (%s)" % (self._id, tv.comment)) + + def test_encrypt(self, tv): + self._id = "Wycheproof Encrypt %s Test #%s" % (tv.algo, tv.id) + + try: + cipher = ChaCha20_Poly1305.new(key=tv.key, nonce=tv.iv) + except ValueError as e: + assert len(tv.iv) not in (8, 12) and "Nonce must be" in str(e) + return + + cipher.update(tv.aad) + ct, tag = cipher.encrypt_and_digest(tv.msg) + if tv.valid: + self.assertEqual(ct, tv.ct) + self.assertEqual(tag, tv.tag) + self.warn(tv) + + def test_decrypt(self, tv): + self._id = "Wycheproof Decrypt %s Test #%s" % (tv.algo, tv.id) + + try: + cipher = ChaCha20_Poly1305.new(key=tv.key, nonce=tv.iv) + except ValueError as e: + assert len(tv.iv) not in (8, 12) and "Nonce must be" in str(e) + return + + cipher.update(tv.aad) + try: + pt = cipher.decrypt_and_verify(tv.ct, tv.tag) + except ValueError: + assert not tv.valid + else: + assert tv.valid + self.assertEqual(pt, tv.msg) + self.warn(tv) + + def test_corrupt_decrypt(self, tv): + self._id = "Wycheproof Corrupt Decrypt ChaCha20-Poly1305 Test #" + str(tv.id) + if len(tv.iv) == 0 or len(tv.ct) < 1: + return + cipher = ChaCha20_Poly1305.new(key=tv.key, nonce=tv.iv) + cipher.update(tv.aad) + ct_corrupt = strxor(tv.ct, b"\x00" * (len(tv.ct) - 1) + b"\x01") + self.assertRaises(ValueError, cipher.decrypt_and_verify, ct_corrupt, tv.tag) + + def runTest(self): + + for tv in self.tv: + self.test_encrypt(tv) + self.test_decrypt(tv) + self.test_corrupt_decrypt(tv) + + +class TestOutput(unittest.TestCase): + + def runTest(self): + # Encrypt/Decrypt data and test output parameter + + key = b'4' * 32 + nonce = b'5' * 12 + cipher = ChaCha20_Poly1305.new(key=key, nonce=nonce) + + pt = b'5' * 16 + ct = cipher.encrypt(pt) + + output = bytearray(16) + cipher = ChaCha20_Poly1305.new(key=key, nonce=nonce) + res = cipher.encrypt(pt, output=output) + self.assertEqual(ct, output) + self.assertEqual(res, None) + + cipher = ChaCha20_Poly1305.new(key=key, nonce=nonce) + res = cipher.decrypt(ct, output=output) + self.assertEqual(pt, output) + self.assertEqual(res, None) + + output = memoryview(bytearray(16)) + cipher = ChaCha20_Poly1305.new(key=key, nonce=nonce) + cipher.encrypt(pt, output=output) + self.assertEqual(ct, output) + + cipher = ChaCha20_Poly1305.new(key=key, nonce=nonce) + cipher.decrypt(ct, output=output) + self.assertEqual(pt, output) + + cipher = ChaCha20_Poly1305.new(key=key, nonce=nonce) + self.assertRaises(TypeError, cipher.encrypt, pt, output=b'0'*16) + + cipher = ChaCha20_Poly1305.new(key=key, nonce=nonce) + self.assertRaises(TypeError, cipher.decrypt, ct, output=b'0'*16) + + shorter_output = bytearray(7) + + cipher = ChaCha20_Poly1305.new(key=key, nonce=nonce) + self.assertRaises(ValueError, cipher.encrypt, pt, output=shorter_output) + + cipher = ChaCha20_Poly1305.new(key=key, nonce=nonce) + self.assertRaises(ValueError, cipher.decrypt, ct, output=shorter_output) + + +def get_tests(config={}): + wycheproof_warnings = config.get('wycheproof_warnings') + + tests = [] + tests += list_test_cases(ChaCha20Poly1305Tests) + tests += list_test_cases(XChaCha20Poly1305Tests) + tests += list_test_cases(ChaCha20Poly1305FSMTests) + tests += [TestVectorsRFC()] + tests += [TestVectorsWycheproof(wycheproof_warnings)] + tests += [TestOutput()] + return tests + + +if __name__ == '__main__': + def suite(): + unittest.TestSuite(get_tests()) + unittest.main(defaultTest='suite') diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/test_DES.py b/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/test_DES.py new file mode 100644 index 0000000..df1313a --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/test_DES.py @@ -0,0 +1,374 @@ +# -*- coding: utf-8 -*- +# +# SelfTest/Cipher/DES.py: Self-test for the (Single) DES cipher +# +# Written in 2008 by Dwayne C. Litzenberger +# +# =================================================================== +# The contents of this file are dedicated to the public domain. To +# the extent that dedication to the public domain is not available, +# everyone is granted a worldwide, perpetual, royalty-free, +# non-exclusive license to exercise all rights associated with the +# contents of this file for any purpose whatsoever. +# No rights are reserved. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# =================================================================== + +"""Self-test suite for Cryptodome.Cipher.DES""" + +import unittest + +from Cryptodome.Cipher import DES + +# This is a list of (plaintext, ciphertext, key, description) tuples. +SP800_17_B1_KEY = '01' * 8 +SP800_17_B2_PT = '00' * 8 +test_data = [ + # Test vectors from Appendix A of NIST SP 800-17 + # "Modes of Operation Validation System (MOVS): Requirements and Procedures" + # http://csrc.nist.gov/publications/nistpubs/800-17/800-17.pdf + + # Appendix A - "Sample Round Outputs for the DES" + ('0000000000000000', '82dcbafbdeab6602', '10316e028c8f3b4a', + "NIST SP800-17 A"), + + # Table B.1 - Variable Plaintext Known Answer Test + ('8000000000000000', '95f8a5e5dd31d900', SP800_17_B1_KEY, + 'NIST SP800-17 B.1 #0'), + ('4000000000000000', 'dd7f121ca5015619', SP800_17_B1_KEY, + 'NIST SP800-17 B.1 #1'), + ('2000000000000000', '2e8653104f3834ea', SP800_17_B1_KEY, + 'NIST SP800-17 B.1 #2'), + ('1000000000000000', '4bd388ff6cd81d4f', SP800_17_B1_KEY, + 'NIST SP800-17 B.1 #3'), + ('0800000000000000', '20b9e767b2fb1456', SP800_17_B1_KEY, + 'NIST SP800-17 B.1 #4'), + ('0400000000000000', '55579380d77138ef', SP800_17_B1_KEY, + 'NIST SP800-17 B.1 #5'), + ('0200000000000000', '6cc5defaaf04512f', SP800_17_B1_KEY, + 'NIST SP800-17 B.1 #6'), + ('0100000000000000', '0d9f279ba5d87260', SP800_17_B1_KEY, + 'NIST SP800-17 B.1 #7'), + ('0080000000000000', 'd9031b0271bd5a0a', SP800_17_B1_KEY, + 'NIST SP800-17 B.1 #8'), + ('0040000000000000', '424250b37c3dd951', SP800_17_B1_KEY, + 'NIST SP800-17 B.1 #9'), + ('0020000000000000', 'b8061b7ecd9a21e5', SP800_17_B1_KEY, + 'NIST SP800-17 B.1 #10'), + ('0010000000000000', 'f15d0f286b65bd28', SP800_17_B1_KEY, + 'NIST SP800-17 B.1 #11'), + ('0008000000000000', 'add0cc8d6e5deba1', SP800_17_B1_KEY, + 'NIST SP800-17 B.1 #12'), + ('0004000000000000', 'e6d5f82752ad63d1', SP800_17_B1_KEY, + 'NIST SP800-17 B.1 #13'), + ('0002000000000000', 'ecbfe3bd3f591a5e', SP800_17_B1_KEY, + 'NIST SP800-17 B.1 #14'), + ('0001000000000000', 'f356834379d165cd', SP800_17_B1_KEY, + 'NIST SP800-17 B.1 #15'), + ('0000800000000000', '2b9f982f20037fa9', SP800_17_B1_KEY, + 'NIST SP800-17 B.1 #16'), + ('0000400000000000', '889de068a16f0be6', SP800_17_B1_KEY, + 'NIST SP800-17 B.1 #17'), + ('0000200000000000', 'e19e275d846a1298', SP800_17_B1_KEY, + 'NIST SP800-17 B.1 #18'), + ('0000100000000000', '329a8ed523d71aec', SP800_17_B1_KEY, + 'NIST SP800-17 B.1 #19'), + ('0000080000000000', 'e7fce22557d23c97', SP800_17_B1_KEY, + 'NIST SP800-17 B.1 #20'), + ('0000040000000000', '12a9f5817ff2d65d', SP800_17_B1_KEY, + 'NIST SP800-17 B.1 #21'), + ('0000020000000000', 'a484c3ad38dc9c19', SP800_17_B1_KEY, + 'NIST SP800-17 B.1 #22'), + ('0000010000000000', 'fbe00a8a1ef8ad72', SP800_17_B1_KEY, + 'NIST SP800-17 B.1 #23'), + ('0000008000000000', '750d079407521363', SP800_17_B1_KEY, + 'NIST SP800-17 B.1 #24'), + ('0000004000000000', '64feed9c724c2faf', SP800_17_B1_KEY, + 'NIST SP800-17 B.1 #25'), + ('0000002000000000', 'f02b263b328e2b60', SP800_17_B1_KEY, + 'NIST SP800-17 B.1 #26'), + ('0000001000000000', '9d64555a9a10b852', SP800_17_B1_KEY, + 'NIST SP800-17 B.1 #27'), + ('0000000800000000', 'd106ff0bed5255d7', SP800_17_B1_KEY, + 'NIST SP800-17 B.1 #28'), + ('0000000400000000', 'e1652c6b138c64a5', SP800_17_B1_KEY, + 'NIST SP800-17 B.1 #29'), + ('0000000200000000', 'e428581186ec8f46', SP800_17_B1_KEY, + 'NIST SP800-17 B.1 #30'), + ('0000000100000000', 'aeb5f5ede22d1a36', SP800_17_B1_KEY, + 'NIST SP800-17 B.1 #31'), + ('0000000080000000', 'e943d7568aec0c5c', SP800_17_B1_KEY, + 'NIST SP800-17 B.1 #32'), + ('0000000040000000', 'df98c8276f54b04b', SP800_17_B1_KEY, + 'NIST SP800-17 B.1 #33'), + ('0000000020000000', 'b160e4680f6c696f', SP800_17_B1_KEY, + 'NIST SP800-17 B.1 #34'), + ('0000000010000000', 'fa0752b07d9c4ab8', SP800_17_B1_KEY, + 'NIST SP800-17 B.1 #35'), + ('0000000008000000', 'ca3a2b036dbc8502', SP800_17_B1_KEY, + 'NIST SP800-17 B.1 #36'), + ('0000000004000000', '5e0905517bb59bcf', SP800_17_B1_KEY, + 'NIST SP800-17 B.1 #37'), + ('0000000002000000', '814eeb3b91d90726', SP800_17_B1_KEY, + 'NIST SP800-17 B.1 #38'), + ('0000000001000000', '4d49db1532919c9f', SP800_17_B1_KEY, + 'NIST SP800-17 B.1 #39'), + ('0000000000800000', '25eb5fc3f8cf0621', SP800_17_B1_KEY, + 'NIST SP800-17 B.1 #40'), + ('0000000000400000', 'ab6a20c0620d1c6f', SP800_17_B1_KEY, + 'NIST SP800-17 B.1 #41'), + ('0000000000200000', '79e90dbc98f92cca', SP800_17_B1_KEY, + 'NIST SP800-17 B.1 #42'), + ('0000000000100000', '866ecedd8072bb0e', SP800_17_B1_KEY, + 'NIST SP800-17 B.1 #43'), + ('0000000000080000', '8b54536f2f3e64a8', SP800_17_B1_KEY, + 'NIST SP800-17 B.1 #44'), + ('0000000000040000', 'ea51d3975595b86b', SP800_17_B1_KEY, + 'NIST SP800-17 B.1 #45'), + ('0000000000020000', 'caffc6ac4542de31', SP800_17_B1_KEY, + 'NIST SP800-17 B.1 #46'), + ('0000000000010000', '8dd45a2ddf90796c', SP800_17_B1_KEY, + 'NIST SP800-17 B.1 #47'), + ('0000000000008000', '1029d55e880ec2d0', SP800_17_B1_KEY, + 'NIST SP800-17 B.1 #48'), + ('0000000000004000', '5d86cb23639dbea9', SP800_17_B1_KEY, + 'NIST SP800-17 B.1 #49'), + ('0000000000002000', '1d1ca853ae7c0c5f', SP800_17_B1_KEY, + 'NIST SP800-17 B.1 #50'), + ('0000000000001000', 'ce332329248f3228', SP800_17_B1_KEY, + 'NIST SP800-17 B.1 #51'), + ('0000000000000800', '8405d1abe24fb942', SP800_17_B1_KEY, + 'NIST SP800-17 B.1 #52'), + ('0000000000000400', 'e643d78090ca4207', SP800_17_B1_KEY, + 'NIST SP800-17 B.1 #53'), + ('0000000000000200', '48221b9937748a23', SP800_17_B1_KEY, + 'NIST SP800-17 B.1 #54'), + ('0000000000000100', 'dd7c0bbd61fafd54', SP800_17_B1_KEY, + 'NIST SP800-17 B.1 #55'), + ('0000000000000080', '2fbc291a570db5c4', SP800_17_B1_KEY, + 'NIST SP800-17 B.1 #56'), + ('0000000000000040', 'e07c30d7e4e26e12', SP800_17_B1_KEY, + 'NIST SP800-17 B.1 #57'), + ('0000000000000020', '0953e2258e8e90a1', SP800_17_B1_KEY, + 'NIST SP800-17 B.1 #58'), + ('0000000000000010', '5b711bc4ceebf2ee', SP800_17_B1_KEY, + 'NIST SP800-17 B.1 #59'), + ('0000000000000008', 'cc083f1e6d9e85f6', SP800_17_B1_KEY, + 'NIST SP800-17 B.1 #60'), + ('0000000000000004', 'd2fd8867d50d2dfe', SP800_17_B1_KEY, + 'NIST SP800-17 B.1 #61'), + ('0000000000000002', '06e7ea22ce92708f', SP800_17_B1_KEY, + 'NIST SP800-17 B.1 #62'), + ('0000000000000001', '166b40b44aba4bd6', SP800_17_B1_KEY, + 'NIST SP800-17 B.1 #63'), + + # Table B.2 - Variable Key Known Answer Test + (SP800_17_B2_PT, '95a8d72813daa94d', '8001010101010101', + 'NIST SP800-17 B.2 #0'), + (SP800_17_B2_PT, '0eec1487dd8c26d5', '4001010101010101', + 'NIST SP800-17 B.2 #1'), + (SP800_17_B2_PT, '7ad16ffb79c45926', '2001010101010101', + 'NIST SP800-17 B.2 #2'), + (SP800_17_B2_PT, 'd3746294ca6a6cf3', '1001010101010101', + 'NIST SP800-17 B.2 #3'), + (SP800_17_B2_PT, '809f5f873c1fd761', '0801010101010101', + 'NIST SP800-17 B.2 #4'), + (SP800_17_B2_PT, 'c02faffec989d1fc', '0401010101010101', + 'NIST SP800-17 B.2 #5'), + (SP800_17_B2_PT, '4615aa1d33e72f10', '0201010101010101', + 'NIST SP800-17 B.2 #6'), + (SP800_17_B2_PT, '2055123350c00858', '0180010101010101', + 'NIST SP800-17 B.2 #7'), + (SP800_17_B2_PT, 'df3b99d6577397c8', '0140010101010101', + 'NIST SP800-17 B.2 #8'), + (SP800_17_B2_PT, '31fe17369b5288c9', '0120010101010101', + 'NIST SP800-17 B.2 #9'), + (SP800_17_B2_PT, 'dfdd3cc64dae1642', '0110010101010101', + 'NIST SP800-17 B.2 #10'), + (SP800_17_B2_PT, '178c83ce2b399d94', '0108010101010101', + 'NIST SP800-17 B.2 #11'), + (SP800_17_B2_PT, '50f636324a9b7f80', '0104010101010101', + 'NIST SP800-17 B.2 #12'), + (SP800_17_B2_PT, 'a8468ee3bc18f06d', '0102010101010101', + 'NIST SP800-17 B.2 #13'), + (SP800_17_B2_PT, 'a2dc9e92fd3cde92', '0101800101010101', + 'NIST SP800-17 B.2 #14'), + (SP800_17_B2_PT, 'cac09f797d031287', '0101400101010101', + 'NIST SP800-17 B.2 #15'), + (SP800_17_B2_PT, '90ba680b22aeb525', '0101200101010101', + 'NIST SP800-17 B.2 #16'), + (SP800_17_B2_PT, 'ce7a24f350e280b6', '0101100101010101', + 'NIST SP800-17 B.2 #17'), + (SP800_17_B2_PT, '882bff0aa01a0b87', '0101080101010101', + 'NIST SP800-17 B.2 #18'), + (SP800_17_B2_PT, '25610288924511c2', '0101040101010101', + 'NIST SP800-17 B.2 #19'), + (SP800_17_B2_PT, 'c71516c29c75d170', '0101020101010101', + 'NIST SP800-17 B.2 #20'), + (SP800_17_B2_PT, '5199c29a52c9f059', '0101018001010101', + 'NIST SP800-17 B.2 #21'), + (SP800_17_B2_PT, 'c22f0a294a71f29f', '0101014001010101', + 'NIST SP800-17 B.2 #22'), + (SP800_17_B2_PT, 'ee371483714c02ea', '0101012001010101', + 'NIST SP800-17 B.2 #23'), + (SP800_17_B2_PT, 'a81fbd448f9e522f', '0101011001010101', + 'NIST SP800-17 B.2 #24'), + (SP800_17_B2_PT, '4f644c92e192dfed', '0101010801010101', + 'NIST SP800-17 B.2 #25'), + (SP800_17_B2_PT, '1afa9a66a6df92ae', '0101010401010101', + 'NIST SP800-17 B.2 #26'), + (SP800_17_B2_PT, 'b3c1cc715cb879d8', '0101010201010101', + 'NIST SP800-17 B.2 #27'), + (SP800_17_B2_PT, '19d032e64ab0bd8b', '0101010180010101', + 'NIST SP800-17 B.2 #28'), + (SP800_17_B2_PT, '3cfaa7a7dc8720dc', '0101010140010101', + 'NIST SP800-17 B.2 #29'), + (SP800_17_B2_PT, 'b7265f7f447ac6f3', '0101010120010101', + 'NIST SP800-17 B.2 #30'), + (SP800_17_B2_PT, '9db73b3c0d163f54', '0101010110010101', + 'NIST SP800-17 B.2 #31'), + (SP800_17_B2_PT, '8181b65babf4a975', '0101010108010101', + 'NIST SP800-17 B.2 #32'), + (SP800_17_B2_PT, '93c9b64042eaa240', '0101010104010101', + 'NIST SP800-17 B.2 #33'), + (SP800_17_B2_PT, '5570530829705592', '0101010102010101', + 'NIST SP800-17 B.2 #34'), + (SP800_17_B2_PT, '8638809e878787a0', '0101010101800101', + 'NIST SP800-17 B.2 #35'), + (SP800_17_B2_PT, '41b9a79af79ac208', '0101010101400101', + 'NIST SP800-17 B.2 #36'), + (SP800_17_B2_PT, '7a9be42f2009a892', '0101010101200101', + 'NIST SP800-17 B.2 #37'), + (SP800_17_B2_PT, '29038d56ba6d2745', '0101010101100101', + 'NIST SP800-17 B.2 #38'), + (SP800_17_B2_PT, '5495c6abf1e5df51', '0101010101080101', + 'NIST SP800-17 B.2 #39'), + (SP800_17_B2_PT, 'ae13dbd561488933', '0101010101040101', + 'NIST SP800-17 B.2 #40'), + (SP800_17_B2_PT, '024d1ffa8904e389', '0101010101020101', + 'NIST SP800-17 B.2 #41'), + (SP800_17_B2_PT, 'd1399712f99bf02e', '0101010101018001', + 'NIST SP800-17 B.2 #42'), + (SP800_17_B2_PT, '14c1d7c1cffec79e', '0101010101014001', + 'NIST SP800-17 B.2 #43'), + (SP800_17_B2_PT, '1de5279dae3bed6f', '0101010101012001', + 'NIST SP800-17 B.2 #44'), + (SP800_17_B2_PT, 'e941a33f85501303', '0101010101011001', + 'NIST SP800-17 B.2 #45'), + (SP800_17_B2_PT, 'da99dbbc9a03f379', '0101010101010801', + 'NIST SP800-17 B.2 #46'), + (SP800_17_B2_PT, 'b7fc92f91d8e92e9', '0101010101010401', + 'NIST SP800-17 B.2 #47'), + (SP800_17_B2_PT, 'ae8e5caa3ca04e85', '0101010101010201', + 'NIST SP800-17 B.2 #48'), + (SP800_17_B2_PT, '9cc62df43b6eed74', '0101010101010180', + 'NIST SP800-17 B.2 #49'), + (SP800_17_B2_PT, 'd863dbb5c59a91a0', '0101010101010140', + 'NIST SP800-17 B.2 #50'), + (SP800_17_B2_PT, 'a1ab2190545b91d7', '0101010101010120', + 'NIST SP800-17 B.2 #51'), + (SP800_17_B2_PT, '0875041e64c570f7', '0101010101010110', + 'NIST SP800-17 B.2 #52'), + (SP800_17_B2_PT, '5a594528bebef1cc', '0101010101010108', + 'NIST SP800-17 B.2 #53'), + (SP800_17_B2_PT, 'fcdb3291de21f0c0', '0101010101010104', + 'NIST SP800-17 B.2 #54'), + (SP800_17_B2_PT, '869efd7f9f265a09', '0101010101010102', + 'NIST SP800-17 B.2 #55'), +] + +class RonRivestTest(unittest.TestCase): + """ Ronald L. Rivest's DES test, see + http://people.csail.mit.edu/rivest/Destest.txt + ABSTRACT + -------- + + We present a simple way to test the correctness of a DES implementation: + Use the recurrence relation: + + X0 = 9474B8E8C73BCA7D (hexadecimal) + + X(i+1) = IF (i is even) THEN E(Xi,Xi) ELSE D(Xi,Xi) + + to compute a sequence of 64-bit values: X0, X1, X2, ..., X16. Here + E(X,K) denotes the DES encryption of X using key K, and D(X,K) denotes + the DES decryption of X using key K. If you obtain + + X16 = 1B1A2DDB4C642438 + + your implementation does not have any of the 36,568 possible single-fault + errors described herein. + """ + def runTest(self): + from binascii import b2a_hex + + X = [] + X[0:] = [b'\x94\x74\xB8\xE8\xC7\x3B\xCA\x7D'] + + for i in range(16): + c = DES.new(X[i],DES.MODE_ECB) + if not (i&1): # (num&1) returns 1 for odd numbers + X[i+1:] = [c.encrypt(X[i])] # even + else: + X[i+1:] = [c.decrypt(X[i])] # odd + + self.assertEqual(b2a_hex(X[16]), + b2a_hex(b'\x1B\x1A\x2D\xDB\x4C\x64\x24\x38')) + + +class TestOutput(unittest.TestCase): + + def runTest(self): + # Encrypt/Decrypt data and test output parameter + + cipher = DES.new(b'4'*8, DES.MODE_ECB) + + pt = b'5' * 8 + ct = cipher.encrypt(pt) + + output = bytearray(8) + res = cipher.encrypt(pt, output=output) + self.assertEqual(ct, output) + self.assertEqual(res, None) + + res = cipher.decrypt(ct, output=output) + self.assertEqual(pt, output) + self.assertEqual(res, None) + + output = memoryview(bytearray(8)) + cipher.encrypt(pt, output=output) + self.assertEqual(ct, output) + + cipher.decrypt(ct, output=output) + self.assertEqual(pt, output) + + self.assertRaises(TypeError, cipher.encrypt, pt, output=b'0'*8) + self.assertRaises(TypeError, cipher.decrypt, ct, output=b'0'*8) + + shorter_output = bytearray(7) + self.assertRaises(ValueError, cipher.encrypt, pt, output=shorter_output) + self.assertRaises(ValueError, cipher.decrypt, ct, output=shorter_output) + + +def get_tests(config={}): + from .common import make_block_tests + tests = make_block_tests(DES, "DES", test_data) + tests += [RonRivestTest()] + tests += [TestOutput()] + return tests + + +if __name__ == '__main__': + import unittest + suite = lambda: unittest.TestSuite(get_tests()) + unittest.main(defaultTest='suite') + +# vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/test_DES3.py b/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/test_DES3.py new file mode 100644 index 0000000..8f8479b --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/test_DES3.py @@ -0,0 +1,195 @@ +# -*- coding: utf-8 -*- +# +# SelfTest/Cipher/DES3.py: Self-test for the Triple-DES cipher +# +# Written in 2008 by Dwayne C. Litzenberger +# +# =================================================================== +# The contents of this file are dedicated to the public domain. To +# the extent that dedication to the public domain is not available, +# everyone is granted a worldwide, perpetual, royalty-free, +# non-exclusive license to exercise all rights associated with the +# contents of this file for any purpose whatsoever. +# No rights are reserved. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# =================================================================== + +"""Self-test suite for Cryptodome.Cipher.DES3""" + +import unittest +from binascii import hexlify, unhexlify + +from Cryptodome.Cipher import DES3 + +from Cryptodome.Util.strxor import strxor_c +from Cryptodome.Util.py3compat import bchr, tostr +from Cryptodome.SelfTest.loader import load_test_vectors +from Cryptodome.SelfTest.st_common import list_test_cases + +# This is a list of (plaintext, ciphertext, key, description) tuples. +test_data = [ + # Test vector from Appendix B of NIST SP 800-67 + # "Recommendation for the Triple Data Encryption Algorithm (TDEA) Block + # Cipher" + # http://csrc.nist.gov/publications/nistpubs/800-67/SP800-67.pdf + ('54686520717566636b2062726f776e20666f78206a756d70', + 'a826fd8ce53b855fcce21c8112256fe668d5c05dd9b6b900', + '0123456789abcdef23456789abcdef01456789abcdef0123', + 'NIST SP800-67 B.1'), + + # This test is designed to test the DES3 API, not the correctness of the + # output. + ('21e81b7ade88a259', '5c577d4d9b20c0f8', + '9b397ebf81b1181e282f4bb8adbadc6b', 'Two-key 3DES'), +] + +# NIST CAVP test vectors + +nist_tdes_mmt_files = ("TECBMMT2.rsp", "TECBMMT3.rsp") + +for tdes_file in nist_tdes_mmt_files: + + test_vectors = load_test_vectors( + ("Cipher", "TDES"), + tdes_file, + "TDES ECB (%s)" % tdes_file, + {"count": lambda x: int(x)}) or [] + + for index, tv in enumerate(test_vectors): + + # The test vector file contains some directive lines + if isinstance(tv, str): + continue + + key = tv.key1 + tv.key2 + tv.key3 + test_data_item = (tostr(hexlify(tv.plaintext)), + tostr(hexlify(tv.ciphertext)), + tostr(hexlify(key)), + "%s (%s)" % (tdes_file, index)) + test_data.append(test_data_item) + + +class CheckParity(unittest.TestCase): + + def test_parity_option2(self): + before_2k = unhexlify("CABF326FA56734324FFCCABCDEFACABF") + after_2k = DES3.adjust_key_parity(before_2k) + self.assertEqual(after_2k, + unhexlify("CBBF326EA46734324FFDCBBCDFFBCBBF")) + + def test_parity_option3(self): + before_3k = unhexlify("AAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBCCCCCCCCCCCCCCCC") + after_3k = DES3.adjust_key_parity(before_3k) + self.assertEqual(after_3k, + unhexlify("ABABABABABABABABBABABABABABABABACDCDCDCDCDCDCDCD")) + + def test_degradation(self): + sub_key1 = bchr(1) * 8 + sub_key2 = bchr(255) * 8 + + # K1 == K2 + self.assertRaises(ValueError, DES3.adjust_key_parity, + sub_key1 * 2 + sub_key2) + + # K2 == K3 + self.assertRaises(ValueError, DES3.adjust_key_parity, + sub_key1 + sub_key2 * 2) + + # K1 == K2 == K3 + self.assertRaises(ValueError, DES3.adjust_key_parity, + sub_key1 * 3) + + # K1 == K2 (with different parity) + self.assertRaises(ValueError, DES3.adjust_key_parity, + sub_key1 + strxor_c(sub_key1, 1) + sub_key2) + + +class DegenerateToDESTest(unittest.TestCase): + + def runTest(self): + sub_key1 = bchr(1) * 8 + sub_key2 = bchr(255) * 8 + + # K1 == K2 + self.assertRaises(ValueError, DES3.new, + sub_key1 * 2 + sub_key2, + DES3.MODE_ECB) + + # K2 == K3 + self.assertRaises(ValueError, DES3.new, + sub_key1 + sub_key2 * 2, + DES3.MODE_ECB) + + # K1 == K2 == K3 + self.assertRaises(ValueError, DES3.new, + sub_key1 * 3, + DES3.MODE_ECB) + + # K2 == K3 (parity is ignored) + self.assertRaises(ValueError, DES3.new, + sub_key1 + sub_key2 + strxor_c(sub_key2, 0x1), + DES3.MODE_ECB) + + +class TestOutput(unittest.TestCase): + + def runTest(self): + # Encrypt/Decrypt data and test output parameter + + cipher = DES3.new(b'4'*8 + b'G'*8 + b'T'*8, DES3.MODE_ECB) + + pt = b'5' * 16 + ct = cipher.encrypt(pt) + + output = bytearray(16) + res = cipher.encrypt(pt, output=output) + self.assertEqual(ct, output) + self.assertEqual(res, None) + + res = cipher.decrypt(ct, output=output) + self.assertEqual(pt, output) + self.assertEqual(res, None) + + output = memoryview(bytearray(16)) + cipher.encrypt(pt, output=output) + self.assertEqual(ct, output) + + cipher.decrypt(ct, output=output) + self.assertEqual(pt, output) + + self.assertRaises(TypeError, cipher.encrypt, pt, output=b'0'*16) + self.assertRaises(TypeError, cipher.decrypt, ct, output=b'0'*16) + + shorter_output = bytearray(7) + self.assertRaises(ValueError, cipher.encrypt, pt, output=shorter_output) + self.assertRaises(ValueError, cipher.decrypt, ct, output=shorter_output) + + +def get_tests(config={}): + from .common import make_block_tests + + tests = [] + tests = make_block_tests(DES3, "DES3", test_data) + tests.append(DegenerateToDESTest()) + tests += list_test_cases(CheckParity) + tests += [TestOutput()] + return tests + + +if __name__ == '__main__': + import unittest + + def suite(): + unittest.TestSuite(get_tests()) + + unittest.main(defaultTest='suite') + +# vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/test_EAX.py b/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/test_EAX.py new file mode 100644 index 0000000..4127a88 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/test_EAX.py @@ -0,0 +1,773 @@ +# =================================================================== +# +# Copyright (c) 2015, Legrandin +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# =================================================================== + +import unittest +from binascii import unhexlify + +from Cryptodome.SelfTest.st_common import list_test_cases +from Cryptodome.SelfTest.loader import load_test_vectors_wycheproof +from Cryptodome.Util.py3compat import tobytes, bchr +from Cryptodome.Cipher import AES, DES3 +from Cryptodome.Hash import SHAKE128 + +from Cryptodome.Util.strxor import strxor + + +def get_tag_random(tag, length): + return SHAKE128.new(data=tobytes(tag)).read(length) + + +class EaxTests(unittest.TestCase): + + key_128 = get_tag_random("key_128", 16) + key_192 = get_tag_random("key_192", 16) + nonce_96 = get_tag_random("nonce_128", 12) + data_128 = get_tag_random("data_128", 16) + + def test_loopback_128(self): + cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) + pt = get_tag_random("plaintext", 16 * 100) + ct = cipher.encrypt(pt) + + cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) + pt2 = cipher.decrypt(ct) + self.assertEqual(pt, pt2) + + def test_loopback_64(self): + cipher = DES3.new(self.key_192, DES3.MODE_EAX, nonce=self.nonce_96) + pt = get_tag_random("plaintext", 8 * 100) + ct = cipher.encrypt(pt) + + cipher = DES3.new(self.key_192, DES3.MODE_EAX, nonce=self.nonce_96) + pt2 = cipher.decrypt(ct) + self.assertEqual(pt, pt2) + + def test_nonce(self): + # If not passed, the nonce is created randomly + cipher = AES.new(self.key_128, AES.MODE_EAX) + nonce1 = cipher.nonce + cipher = AES.new(self.key_128, AES.MODE_EAX) + nonce2 = cipher.nonce + self.assertEqual(len(nonce1), 16) + self.assertNotEqual(nonce1, nonce2) + + cipher = AES.new(self.key_128, AES.MODE_EAX, self.nonce_96) + ct = cipher.encrypt(self.data_128) + + cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) + self.assertEqual(ct, cipher.encrypt(self.data_128)) + + def test_nonce_must_be_bytes(self): + self.assertRaises(TypeError, AES.new, self.key_128, AES.MODE_EAX, + nonce=u'test12345678') + + def test_nonce_length(self): + # nonce can be of any length (but not empty) + self.assertRaises(ValueError, AES.new, self.key_128, AES.MODE_EAX, + nonce=b"") + + for x in range(1, 128): + cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=bchr(1) * x) + cipher.encrypt(bchr(1)) + + def test_block_size_128(self): + cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) + self.assertEqual(cipher.block_size, AES.block_size) + + def test_block_size_64(self): + cipher = DES3.new(self.key_192, AES.MODE_EAX, nonce=self.nonce_96) + self.assertEqual(cipher.block_size, DES3.block_size) + + def test_nonce_attribute(self): + cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) + self.assertEqual(cipher.nonce, self.nonce_96) + + # By default, a 16 bytes long nonce is randomly generated + nonce1 = AES.new(self.key_128, AES.MODE_EAX).nonce + nonce2 = AES.new(self.key_128, AES.MODE_EAX).nonce + self.assertEqual(len(nonce1), 16) + self.assertNotEqual(nonce1, nonce2) + + def test_unknown_parameters(self): + self.assertRaises(TypeError, AES.new, self.key_128, AES.MODE_EAX, + self.nonce_96, 7) + self.assertRaises(TypeError, AES.new, self.key_128, AES.MODE_EAX, + nonce=self.nonce_96, unknown=7) + + # But some are only known by the base cipher + # (e.g. use_aesni consumed by the AES module) + AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96, + use_aesni=False) + + def test_null_encryption_decryption(self): + for func in "encrypt", "decrypt": + cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) + result = getattr(cipher, func)(b"") + self.assertEqual(result, b"") + + def test_either_encrypt_or_decrypt(self): + cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) + cipher.encrypt(b"") + self.assertRaises(TypeError, cipher.decrypt, b"") + + cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) + cipher.decrypt(b"") + self.assertRaises(TypeError, cipher.encrypt, b"") + + def test_data_must_be_bytes(self): + cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) + self.assertRaises(TypeError, cipher.encrypt, u'test1234567890-*') + + cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) + self.assertRaises(TypeError, cipher.decrypt, u'test1234567890-*') + + def test_mac_len(self): + # Invalid MAC length + self.assertRaises(ValueError, AES.new, self.key_128, AES.MODE_EAX, + nonce=self.nonce_96, mac_len=2-1) + self.assertRaises(ValueError, AES.new, self.key_128, AES.MODE_EAX, + nonce=self.nonce_96, mac_len=16+1) + + # Valid MAC length + for mac_len in range(2, 16 + 1): + cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96, + mac_len=mac_len) + _, mac = cipher.encrypt_and_digest(self.data_128) + self.assertEqual(len(mac), mac_len) + + # Default MAC length + cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) + _, mac = cipher.encrypt_and_digest(self.data_128) + self.assertEqual(len(mac), 16) + + def test_invalid_mac(self): + from Cryptodome.Util.strxor import strxor_c + cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) + ct, mac = cipher.encrypt_and_digest(self.data_128) + + invalid_mac = strxor_c(mac, 0x01) + + cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) + self.assertRaises(ValueError, cipher.decrypt_and_verify, ct, + invalid_mac) + + def test_hex_mac(self): + cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) + mac_hex = cipher.hexdigest() + self.assertEqual(cipher.digest(), unhexlify(mac_hex)) + + cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) + cipher.hexverify(mac_hex) + + def test_message_chunks(self): + # Validate that both associated data and plaintext/ciphertext + # can be broken up in chunks of arbitrary length + + auth_data = get_tag_random("authenticated data", 127) + plaintext = get_tag_random("plaintext", 127) + + cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) + cipher.update(auth_data) + ciphertext, ref_mac = cipher.encrypt_and_digest(plaintext) + + def break_up(data, chunk_length): + return [data[i:i+chunk_length] for i in range(0, len(data), + chunk_length)] + + # Encryption + for chunk_length in 1, 2, 3, 7, 10, 13, 16, 40, 80, 128: + + cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) + + for chunk in break_up(auth_data, chunk_length): + cipher.update(chunk) + pt2 = b"" + for chunk in break_up(ciphertext, chunk_length): + pt2 += cipher.decrypt(chunk) + self.assertEqual(plaintext, pt2) + cipher.verify(ref_mac) + + # Decryption + for chunk_length in 1, 2, 3, 7, 10, 13, 16, 40, 80, 128: + + cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) + + for chunk in break_up(auth_data, chunk_length): + cipher.update(chunk) + ct2 = b"" + for chunk in break_up(plaintext, chunk_length): + ct2 += cipher.encrypt(chunk) + self.assertEqual(ciphertext, ct2) + self.assertEqual(cipher.digest(), ref_mac) + + def test_bytearray(self): + + # Encrypt + key_ba = bytearray(self.key_128) + nonce_ba = bytearray(self.nonce_96) + header_ba = bytearray(self.data_128) + data_ba = bytearray(self.data_128) + + cipher1 = AES.new(self.key_128, + AES.MODE_EAX, + nonce=self.nonce_96) + cipher1.update(self.data_128) + ct = cipher1.encrypt(self.data_128) + tag = cipher1.digest() + + cipher2 = AES.new(key_ba, + AES.MODE_EAX, + nonce=nonce_ba) + key_ba[:3] = b'\xFF\xFF\xFF' + nonce_ba[:3] = b'\xFF\xFF\xFF' + cipher2.update(header_ba) + header_ba[:3] = b'\xFF\xFF\xFF' + ct_test = cipher2.encrypt(data_ba) + data_ba[:3] = b'\x99\x99\x99' + tag_test = cipher2.digest() + + self.assertEqual(ct, ct_test) + self.assertEqual(tag, tag_test) + self.assertEqual(cipher1.nonce, cipher2.nonce) + + # Decrypt + key_ba = bytearray(self.key_128) + nonce_ba = bytearray(self.nonce_96) + header_ba = bytearray(self.data_128) + ct_ba = bytearray(ct) + tag_ba = bytearray(tag) + del data_ba + + cipher3 = AES.new(key_ba, + AES.MODE_EAX, + nonce=nonce_ba) + key_ba[:3] = b'\xFF\xFF\xFF' + nonce_ba[:3] = b'\xFF\xFF\xFF' + cipher3.update(header_ba) + header_ba[:3] = b'\xFF\xFF\xFF' + pt_test = cipher3.decrypt(ct_ba) + ct_ba[:3] = b'\xFF\xFF\xFF' + cipher3.verify(tag_ba) + + self.assertEqual(pt_test, self.data_128) + + def test_memoryview(self): + + # Encrypt + key_mv = memoryview(bytearray(self.key_128)) + nonce_mv = memoryview(bytearray(self.nonce_96)) + header_mv = memoryview(bytearray(self.data_128)) + data_mv = memoryview(bytearray(self.data_128)) + + cipher1 = AES.new(self.key_128, + AES.MODE_EAX, + nonce=self.nonce_96) + cipher1.update(self.data_128) + ct = cipher1.encrypt(self.data_128) + tag = cipher1.digest() + + cipher2 = AES.new(key_mv, + AES.MODE_EAX, + nonce=nonce_mv) + key_mv[:3] = b'\xFF\xFF\xFF' + nonce_mv[:3] = b'\xFF\xFF\xFF' + cipher2.update(header_mv) + header_mv[:3] = b'\xFF\xFF\xFF' + ct_test = cipher2.encrypt(data_mv) + data_mv[:3] = b'\x99\x99\x99' + tag_test = cipher2.digest() + + self.assertEqual(ct, ct_test) + self.assertEqual(tag, tag_test) + self.assertEqual(cipher1.nonce, cipher2.nonce) + + # Decrypt + key_mv = memoryview(bytearray(self.key_128)) + nonce_mv = memoryview(bytearray(self.nonce_96)) + header_mv = memoryview(bytearray(self.data_128)) + ct_mv = memoryview(bytearray(ct)) + tag_mv = memoryview(bytearray(tag)) + del data_mv + + cipher3 = AES.new(key_mv, + AES.MODE_EAX, + nonce=nonce_mv) + key_mv[:3] = b'\xFF\xFF\xFF' + nonce_mv[:3] = b'\xFF\xFF\xFF' + cipher3.update(header_mv) + header_mv[:3] = b'\xFF\xFF\xFF' + pt_test = cipher3.decrypt(ct_mv) + ct_mv[:3] = b'\x99\x99\x99' + cipher3.verify(tag_mv) + + self.assertEqual(pt_test, self.data_128) + + def test_output_param(self): + + pt = b'5' * 128 + cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) + ct = cipher.encrypt(pt) + tag = cipher.digest() + + output = bytearray(128) + cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) + res = cipher.encrypt(pt, output=output) + self.assertEqual(ct, output) + self.assertEqual(res, None) + + cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) + res = cipher.decrypt(ct, output=output) + self.assertEqual(pt, output) + self.assertEqual(res, None) + + cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) + res, tag_out = cipher.encrypt_and_digest(pt, output=output) + self.assertEqual(ct, output) + self.assertEqual(res, None) + self.assertEqual(tag, tag_out) + + cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) + res = cipher.decrypt_and_verify(ct, tag, output=output) + self.assertEqual(pt, output) + self.assertEqual(res, None) + + def test_output_param_memoryview(self): + + pt = b'5' * 128 + cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) + ct = cipher.encrypt(pt) + + output = memoryview(bytearray(128)) + cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) + cipher.encrypt(pt, output=output) + self.assertEqual(ct, output) + + cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) + cipher.decrypt(ct, output=output) + self.assertEqual(pt, output) + + def test_output_param_neg(self): + LEN_PT = 16 + + pt = b'5' * LEN_PT + cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) + ct = cipher.encrypt(pt) + + cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) + self.assertRaises(TypeError, cipher.encrypt, pt, output=b'0' * LEN_PT) + + cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) + self.assertRaises(TypeError, cipher.decrypt, ct, output=b'0' * LEN_PT) + + shorter_output = bytearray(LEN_PT - 1) + cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) + self.assertRaises(ValueError, cipher.encrypt, pt, output=shorter_output) + cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) + self.assertRaises(ValueError, cipher.decrypt, ct, output=shorter_output) + + +class EaxFSMTests(unittest.TestCase): + + key_128 = get_tag_random("key_128", 16) + nonce_96 = get_tag_random("nonce_128", 12) + data_128 = get_tag_random("data_128", 16) + + def test_valid_init_encrypt_decrypt_digest_verify(self): + # No authenticated data, fixed plaintext + # Verify path INIT->ENCRYPT->DIGEST + cipher = AES.new(self.key_128, AES.MODE_EAX, + nonce=self.nonce_96) + ct = cipher.encrypt(self.data_128) + mac = cipher.digest() + + # Verify path INIT->DECRYPT->VERIFY + cipher = AES.new(self.key_128, AES.MODE_EAX, + nonce=self.nonce_96) + cipher.decrypt(ct) + cipher.verify(mac) + + def test_valid_init_update_digest_verify(self): + # No plaintext, fixed authenticated data + # Verify path INIT->UPDATE->DIGEST + cipher = AES.new(self.key_128, AES.MODE_EAX, + nonce=self.nonce_96) + cipher.update(self.data_128) + mac = cipher.digest() + + # Verify path INIT->UPDATE->VERIFY + cipher = AES.new(self.key_128, AES.MODE_EAX, + nonce=self.nonce_96) + cipher.update(self.data_128) + cipher.verify(mac) + + def test_valid_full_path(self): + # Fixed authenticated data, fixed plaintext + # Verify path INIT->UPDATE->ENCRYPT->DIGEST + cipher = AES.new(self.key_128, AES.MODE_EAX, + nonce=self.nonce_96) + cipher.update(self.data_128) + ct = cipher.encrypt(self.data_128) + mac = cipher.digest() + + # Verify path INIT->UPDATE->DECRYPT->VERIFY + cipher = AES.new(self.key_128, AES.MODE_EAX, + nonce=self.nonce_96) + cipher.update(self.data_128) + cipher.decrypt(ct) + cipher.verify(mac) + + def test_valid_init_digest(self): + # Verify path INIT->DIGEST + cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) + cipher.digest() + + def test_valid_init_verify(self): + # Verify path INIT->VERIFY + cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) + mac = cipher.digest() + + cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) + cipher.verify(mac) + + def test_valid_multiple_encrypt_or_decrypt(self): + for method_name in "encrypt", "decrypt": + for auth_data in (None, b"333", self.data_128, + self.data_128 + b"3"): + if auth_data is None: + assoc_len = None + else: + assoc_len = len(auth_data) + cipher = AES.new(self.key_128, AES.MODE_EAX, + nonce=self.nonce_96) + if auth_data is not None: + cipher.update(auth_data) + method = getattr(cipher, method_name) + method(self.data_128) + method(self.data_128) + method(self.data_128) + method(self.data_128) + + def test_valid_multiple_digest_or_verify(self): + # Multiple calls to digest + cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) + cipher.update(self.data_128) + first_mac = cipher.digest() + for x in range(4): + self.assertEqual(first_mac, cipher.digest()) + + # Multiple calls to verify + cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) + cipher.update(self.data_128) + for x in range(5): + cipher.verify(first_mac) + + def test_valid_encrypt_and_digest_decrypt_and_verify(self): + # encrypt_and_digest + cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) + cipher.update(self.data_128) + ct, mac = cipher.encrypt_and_digest(self.data_128) + + # decrypt_and_verify + cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) + cipher.update(self.data_128) + pt = cipher.decrypt_and_verify(ct, mac) + self.assertEqual(self.data_128, pt) + + def test_invalid_mixing_encrypt_decrypt(self): + # Once per method, with or without assoc. data + for method1_name, method2_name in (("encrypt", "decrypt"), + ("decrypt", "encrypt")): + for assoc_data_present in (True, False): + cipher = AES.new(self.key_128, AES.MODE_EAX, + nonce=self.nonce_96) + if assoc_data_present: + cipher.update(self.data_128) + getattr(cipher, method1_name)(self.data_128) + self.assertRaises(TypeError, getattr(cipher, method2_name), + self.data_128) + + def test_invalid_encrypt_or_update_after_digest(self): + for method_name in "encrypt", "update": + cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) + cipher.encrypt(self.data_128) + cipher.digest() + self.assertRaises(TypeError, getattr(cipher, method_name), + self.data_128) + + cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) + cipher.encrypt_and_digest(self.data_128) + + def test_invalid_decrypt_or_update_after_verify(self): + cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) + ct = cipher.encrypt(self.data_128) + mac = cipher.digest() + + for method_name in "decrypt", "update": + cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) + cipher.decrypt(ct) + cipher.verify(mac) + self.assertRaises(TypeError, getattr(cipher, method_name), + self.data_128) + + cipher = AES.new(self.key_128, AES.MODE_EAX, nonce=self.nonce_96) + cipher.decrypt_and_verify(ct, mac) + self.assertRaises(TypeError, getattr(cipher, method_name), + self.data_128) + + +class TestVectorsPaper(unittest.TestCase): + """Class exercising the EAX test vectors found in + http://www.cs.ucdavis.edu/~rogaway/papers/eax.pdf""" + + test_vectors_hex = [ + ( '6bfb914fd07eae6b', + '', + '', + 'e037830e8389f27b025a2d6527e79d01', + '233952dee4d5ed5f9b9c6d6ff80ff478', + '62EC67F9C3A4A407FCB2A8C49031A8B3' + ), + ( + 'fa3bfd4806eb53fa', + 'f7fb', + '19dd', + '5c4c9331049d0bdab0277408f67967e5', + '91945d3f4dcbee0bf45ef52255f095a4', + 'BECAF043B0A23D843194BA972C66DEBD' + ), + ( '234a3463c1264ac6', + '1a47cb4933', + 'd851d5bae0', + '3a59f238a23e39199dc9266626c40f80', + '01f74ad64077f2e704c0f60ada3dd523', + '70C3DB4F0D26368400A10ED05D2BFF5E' + ), + ( + '33cce2eabff5a79d', + '481c9e39b1', + '632a9d131a', + 'd4c168a4225d8e1ff755939974a7bede', + 'd07cf6cbb7f313bdde66b727afd3c5e8', + '8408DFFF3C1A2B1292DC199E46B7D617' + ), + ( + 'aeb96eaebe2970e9', + '40d0c07da5e4', + '071dfe16c675', + 'cb0677e536f73afe6a14b74ee49844dd', + '35b6d0580005bbc12b0587124557d2c2', + 'FDB6B06676EEDC5C61D74276E1F8E816' + ), + ( + 'd4482d1ca78dce0f', + '4de3b35c3fc039245bd1fb7d', + '835bb4f15d743e350e728414', + 'abb8644fd6ccb86947c5e10590210a4f', + 'bd8e6e11475e60b268784c38c62feb22', + '6EAC5C93072D8E8513F750935E46DA1B' + ), + ( + '65d2017990d62528', + '8b0a79306c9ce7ed99dae4f87f8dd61636', + '02083e3979da014812f59f11d52630da30', + '137327d10649b0aa6e1c181db617d7f2', + '7c77d6e813bed5ac98baa417477a2e7d', + '1A8C98DCD73D38393B2BF1569DEEFC19' + ), + ( + '54b9f04e6a09189a', + '1bda122bce8a8dbaf1877d962b8592dd2d56', + '2ec47b2c4954a489afc7ba4897edcdae8cc3', + '3b60450599bd02c96382902aef7f832a', + '5fff20cafab119ca2fc73549e20f5b0d', + 'DDE59B97D722156D4D9AFF2BC7559826' + ), + ( + '899a175897561d7e', + '6cf36720872b8513f6eab1a8a44438d5ef11', + '0de18fd0fdd91e7af19f1d8ee8733938b1e8', + 'e7f6d2231618102fdb7fe55ff1991700', + 'a4a4782bcffd3ec5e7ef6d8c34a56123', + 'B781FCF2F75FA5A8DE97A9CA48E522EC' + ), + ( + '126735fcc320d25a', + 'ca40d7446e545ffaed3bd12a740a659ffbbb3ceab7', + 'cb8920f87a6c75cff39627b56e3ed197c552d295a7', + 'cfc46afc253b4652b1af3795b124ab6e', + '8395fcf1e95bebd697bd010bc766aac3', + '22E7ADD93CFC6393C57EC0B3C17D6B44' + ), + ] + + test_vectors = [[unhexlify(x) for x in tv] for tv in test_vectors_hex] + + def runTest(self): + for assoc_data, pt, ct, mac, key, nonce in self.test_vectors: + # Encrypt + cipher = AES.new(key, AES.MODE_EAX, nonce, mac_len=len(mac)) + cipher.update(assoc_data) + ct2, mac2 = cipher.encrypt_and_digest(pt) + self.assertEqual(ct, ct2) + self.assertEqual(mac, mac2) + + # Decrypt + cipher = AES.new(key, AES.MODE_EAX, nonce, mac_len=len(mac)) + cipher.update(assoc_data) + pt2 = cipher.decrypt_and_verify(ct, mac) + self.assertEqual(pt, pt2) + + +class TestVectorsWycheproof(unittest.TestCase): + + def __init__(self, wycheproof_warnings): + unittest.TestCase.__init__(self) + self._wycheproof_warnings = wycheproof_warnings + self._id = "None" + + def setUp(self): + + def filter_tag(group): + return group['tagSize'] // 8 + + self.tv = load_test_vectors_wycheproof(("Cipher", "wycheproof"), + "aes_eax_test.json", + "Wycheproof EAX", + group_tag={'tag_size': filter_tag}) + + def shortDescription(self): + return self._id + + def warn(self, tv): + if tv.warning and self._wycheproof_warnings: + import warnings + warnings.warn("Wycheproof warning: %s (%s)" % (self._id, tv.comment)) + + def test_encrypt(self, tv): + self._id = "Wycheproof Encrypt EAX Test #" + str(tv.id) + + try: + cipher = AES.new(tv.key, AES.MODE_EAX, tv.iv, mac_len=tv.tag_size) + except ValueError as e: + assert len(tv.iv) == 0 and "Nonce cannot be empty" in str(e) + return + + cipher.update(tv.aad) + ct, tag = cipher.encrypt_and_digest(tv.msg) + if tv.valid: + self.assertEqual(ct, tv.ct) + self.assertEqual(tag, tv.tag) + self.warn(tv) + + def test_decrypt(self, tv): + self._id = "Wycheproof Decrypt EAX Test #" + str(tv.id) + + try: + cipher = AES.new(tv.key, AES.MODE_EAX, tv.iv, mac_len=tv.tag_size) + except ValueError as e: + assert len(tv.iv) == 0 and "Nonce cannot be empty" in str(e) + return + + cipher.update(tv.aad) + try: + pt = cipher.decrypt_and_verify(tv.ct, tv.tag) + except ValueError: + assert not tv.valid + else: + assert tv.valid + self.assertEqual(pt, tv.msg) + self.warn(tv) + + def test_corrupt_decrypt(self, tv): + self._id = "Wycheproof Corrupt Decrypt EAX Test #" + str(tv.id) + if len(tv.iv) == 0 or len(tv.ct) < 1: + return + cipher = AES.new(tv.key, AES.MODE_EAX, tv.iv, mac_len=tv.tag_size) + cipher.update(tv.aad) + ct_corrupt = strxor(tv.ct, b"\x00" * (len(tv.ct) - 1) + b"\x01") + self.assertRaises(ValueError, cipher.decrypt_and_verify, ct_corrupt, tv.tag) + + def runTest(self): + + for tv in self.tv: + self.test_encrypt(tv) + self.test_decrypt(tv) + self.test_corrupt_decrypt(tv) + + +class TestOtherCiphers(unittest.TestCase): + + @classmethod + def create_test(cls, name, factory, key_size): + + def test_template(self, factory=factory, key_size=key_size): + cipher = factory.new(get_tag_random("cipher", key_size), + factory.MODE_EAX, + nonce=b"nonce") + ct, mac = cipher.encrypt_and_digest(b"plaintext") + + cipher = factory.new(get_tag_random("cipher", key_size), + factory.MODE_EAX, + nonce=b"nonce") + pt2 = cipher.decrypt_and_verify(ct, mac) + + self.assertEqual(b"plaintext", pt2) + + setattr(cls, "test_" + name, test_template) + + +from Cryptodome.Cipher import DES, DES3, ARC2, CAST, Blowfish + +TestOtherCiphers.create_test("DES_" + str(DES.key_size), DES, DES.key_size) +for ks in DES3.key_size: + TestOtherCiphers.create_test("DES3_" + str(ks), DES3, ks) +for ks in ARC2.key_size: + TestOtherCiphers.create_test("ARC2_" + str(ks), ARC2, ks) +for ks in CAST.key_size: + TestOtherCiphers.create_test("CAST_" + str(ks), CAST, ks) +for ks in Blowfish.key_size: + TestOtherCiphers.create_test("Blowfish_" + str(ks), Blowfish, ks) + + +def get_tests(config={}): + wycheproof_warnings = config.get('wycheproof_warnings') + + tests = [] + tests += list_test_cases(EaxTests) + tests += list_test_cases(EaxFSMTests) + tests += [ TestVectorsPaper() ] + tests += [ TestVectorsWycheproof(wycheproof_warnings) ] + tests += list_test_cases(TestOtherCiphers) + return tests + + +if __name__ == '__main__': + suite = lambda: unittest.TestSuite(get_tests()) + unittest.main(defaultTest='suite') diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/test_GCM.py b/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/test_GCM.py new file mode 100644 index 0000000..ac8e741 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/test_GCM.py @@ -0,0 +1,951 @@ +# =================================================================== +# +# Copyright (c) 2015, Legrandin +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# =================================================================== + +from __future__ import print_function + +import unittest +from binascii import unhexlify + +from Cryptodome.SelfTest.st_common import list_test_cases +from Cryptodome.SelfTest.loader import load_test_vectors, load_test_vectors_wycheproof + +from Cryptodome.Util.py3compat import tobytes, bchr +from Cryptodome.Cipher import AES +from Cryptodome.Hash import SHAKE128, SHA256 + +from Cryptodome.Util.strxor import strxor + + +def get_tag_random(tag, length): + return SHAKE128.new(data=tobytes(tag)).read(length) + + +class GcmTests(unittest.TestCase): + + key_128 = get_tag_random("key_128", 16) + nonce_96 = get_tag_random("nonce_128", 12) + data = get_tag_random("data", 128) + + def test_loopback_128(self): + cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) + pt = get_tag_random("plaintext", 16 * 100) + ct = cipher.encrypt(pt) + + cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) + pt2 = cipher.decrypt(ct) + self.assertEqual(pt, pt2) + + def test_nonce(self): + # Nonce is optional (a random one will be created) + AES.new(self.key_128, AES.MODE_GCM) + + cipher = AES.new(self.key_128, AES.MODE_GCM, self.nonce_96) + ct = cipher.encrypt(self.data) + + cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) + self.assertEqual(ct, cipher.encrypt(self.data)) + + def test_nonce_must_be_bytes(self): + self.assertRaises(TypeError, AES.new, self.key_128, AES.MODE_GCM, + nonce=u'test12345678') + + def test_nonce_length(self): + # nonce can be of any length (but not empty) + self.assertRaises(ValueError, AES.new, self.key_128, AES.MODE_GCM, + nonce=b"") + + for x in range(1, 128): + cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=bchr(1) * x) + cipher.encrypt(bchr(1)) + + def test_block_size_128(self): + cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) + self.assertEqual(cipher.block_size, AES.block_size) + + def test_nonce_attribute(self): + cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) + self.assertEqual(cipher.nonce, self.nonce_96) + + # By default, a 15 bytes long nonce is randomly generated + nonce1 = AES.new(self.key_128, AES.MODE_GCM).nonce + nonce2 = AES.new(self.key_128, AES.MODE_GCM).nonce + self.assertEqual(len(nonce1), 16) + self.assertNotEqual(nonce1, nonce2) + + def test_unknown_parameters(self): + self.assertRaises(TypeError, AES.new, self.key_128, AES.MODE_GCM, + self.nonce_96, 7) + self.assertRaises(TypeError, AES.new, self.key_128, AES.MODE_GCM, + nonce=self.nonce_96, unknown=7) + + # But some are only known by the base cipher + # (e.g. use_aesni consumed by the AES module) + AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96, + use_aesni=False) + + def test_null_encryption_decryption(self): + for func in "encrypt", "decrypt": + cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) + result = getattr(cipher, func)(b"") + self.assertEqual(result, b"") + + def test_either_encrypt_or_decrypt(self): + cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) + cipher.encrypt(b"") + self.assertRaises(TypeError, cipher.decrypt, b"") + + cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) + cipher.decrypt(b"") + self.assertRaises(TypeError, cipher.encrypt, b"") + + def test_data_must_be_bytes(self): + cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) + self.assertRaises(TypeError, cipher.encrypt, u'test1234567890-*') + + cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) + self.assertRaises(TypeError, cipher.decrypt, u'test1234567890-*') + + def test_mac_len(self): + # Invalid MAC length + self.assertRaises(ValueError, AES.new, self.key_128, AES.MODE_GCM, + nonce=self.nonce_96, mac_len=3) + self.assertRaises(ValueError, AES.new, self.key_128, AES.MODE_GCM, + nonce=self.nonce_96, mac_len=16+1) + + # Valid MAC length + for mac_len in range(5, 16 + 1): + cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96, + mac_len=mac_len) + _, mac = cipher.encrypt_and_digest(self.data) + self.assertEqual(len(mac), mac_len) + + # Default MAC length + cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) + _, mac = cipher.encrypt_and_digest(self.data) + self.assertEqual(len(mac), 16) + + def test_invalid_mac(self): + from Cryptodome.Util.strxor import strxor_c + cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) + ct, mac = cipher.encrypt_and_digest(self.data) + + invalid_mac = strxor_c(mac, 0x01) + + cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) + self.assertRaises(ValueError, cipher.decrypt_and_verify, ct, + invalid_mac) + + def test_hex_mac(self): + cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) + mac_hex = cipher.hexdigest() + self.assertEqual(cipher.digest(), unhexlify(mac_hex)) + + cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) + cipher.hexverify(mac_hex) + + def test_message_chunks(self): + # Validate that both associated data and plaintext/ciphertext + # can be broken up in chunks of arbitrary length + + auth_data = get_tag_random("authenticated data", 127) + plaintext = get_tag_random("plaintext", 127) + + cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) + cipher.update(auth_data) + ciphertext, ref_mac = cipher.encrypt_and_digest(plaintext) + + def break_up(data, chunk_length): + return [data[i:i+chunk_length] for i in range(0, len(data), + chunk_length)] + + # Encryption + for chunk_length in 1, 2, 3, 7, 10, 13, 16, 40, 80, 128: + + cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) + + for chunk in break_up(auth_data, chunk_length): + cipher.update(chunk) + pt2 = b"" + for chunk in break_up(ciphertext, chunk_length): + pt2 += cipher.decrypt(chunk) + self.assertEqual(plaintext, pt2) + cipher.verify(ref_mac) + + # Decryption + for chunk_length in 1, 2, 3, 7, 10, 13, 16, 40, 80, 128: + + cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) + + for chunk in break_up(auth_data, chunk_length): + cipher.update(chunk) + ct2 = b"" + for chunk in break_up(plaintext, chunk_length): + ct2 += cipher.encrypt(chunk) + self.assertEqual(ciphertext, ct2) + self.assertEqual(cipher.digest(), ref_mac) + + def test_bytearray(self): + + # Encrypt + key_ba = bytearray(self.key_128) + nonce_ba = bytearray(self.nonce_96) + header_ba = bytearray(self.data) + data_ba = bytearray(self.data) + + cipher1 = AES.new(self.key_128, + AES.MODE_GCM, + nonce=self.nonce_96) + cipher1.update(self.data) + ct = cipher1.encrypt(self.data) + tag = cipher1.digest() + + cipher2 = AES.new(key_ba, + AES.MODE_GCM, + nonce=nonce_ba) + key_ba[:3] = b"\xFF\xFF\xFF" + nonce_ba[:3] = b"\xFF\xFF\xFF" + cipher2.update(header_ba) + header_ba[:3] = b"\xFF\xFF\xFF" + ct_test = cipher2.encrypt(data_ba) + data_ba[:3] = b"\xFF\xFF\xFF" + tag_test = cipher2.digest() + + self.assertEqual(ct, ct_test) + self.assertEqual(tag, tag_test) + self.assertEqual(cipher1.nonce, cipher2.nonce) + + # Decrypt + key_ba = bytearray(self.key_128) + nonce_ba = bytearray(self.nonce_96) + header_ba = bytearray(self.data) + del data_ba + + cipher4 = AES.new(key_ba, + AES.MODE_GCM, + nonce=nonce_ba) + key_ba[:3] = b"\xFF\xFF\xFF" + nonce_ba[:3] = b"\xFF\xFF\xFF" + cipher4.update(header_ba) + header_ba[:3] = b"\xFF\xFF\xFF" + pt_test = cipher4.decrypt_and_verify(bytearray(ct_test), bytearray(tag_test)) + + self.assertEqual(self.data, pt_test) + + def test_memoryview(self): + + # Encrypt + key_mv = memoryview(bytearray(self.key_128)) + nonce_mv = memoryview(bytearray(self.nonce_96)) + header_mv = memoryview(bytearray(self.data)) + data_mv = memoryview(bytearray(self.data)) + + cipher1 = AES.new(self.key_128, + AES.MODE_GCM, + nonce=self.nonce_96) + cipher1.update(self.data) + ct = cipher1.encrypt(self.data) + tag = cipher1.digest() + + cipher2 = AES.new(key_mv, + AES.MODE_GCM, + nonce=nonce_mv) + key_mv[:3] = b"\xFF\xFF\xFF" + nonce_mv[:3] = b"\xFF\xFF\xFF" + cipher2.update(header_mv) + header_mv[:3] = b"\xFF\xFF\xFF" + ct_test = cipher2.encrypt(data_mv) + data_mv[:3] = b"\xFF\xFF\xFF" + tag_test = cipher2.digest() + + self.assertEqual(ct, ct_test) + self.assertEqual(tag, tag_test) + self.assertEqual(cipher1.nonce, cipher2.nonce) + + # Decrypt + key_mv = memoryview(bytearray(self.key_128)) + nonce_mv = memoryview(bytearray(self.nonce_96)) + header_mv = memoryview(bytearray(self.data)) + del data_mv + + cipher4 = AES.new(key_mv, + AES.MODE_GCM, + nonce=nonce_mv) + key_mv[:3] = b"\xFF\xFF\xFF" + nonce_mv[:3] = b"\xFF\xFF\xFF" + cipher4.update(header_mv) + header_mv[:3] = b"\xFF\xFF\xFF" + pt_test = cipher4.decrypt_and_verify(memoryview(ct_test), memoryview(tag_test)) + + self.assertEqual(self.data, pt_test) + + def test_output_param(self): + + pt = b'5' * 128 + cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) + ct = cipher.encrypt(pt) + tag = cipher.digest() + + output = bytearray(128) + cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) + res = cipher.encrypt(pt, output=output) + self.assertEqual(ct, output) + self.assertEqual(res, None) + + cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) + res = cipher.decrypt(ct, output=output) + self.assertEqual(pt, output) + self.assertEqual(res, None) + + cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) + res, tag_out = cipher.encrypt_and_digest(pt, output=output) + self.assertEqual(ct, output) + self.assertEqual(res, None) + self.assertEqual(tag, tag_out) + + cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) + res = cipher.decrypt_and_verify(ct, tag, output=output) + self.assertEqual(pt, output) + self.assertEqual(res, None) + + def test_output_param_memoryview(self): + + pt = b'5' * 128 + cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) + ct = cipher.encrypt(pt) + + output = memoryview(bytearray(128)) + cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) + cipher.encrypt(pt, output=output) + self.assertEqual(ct, output) + + cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) + cipher.decrypt(ct, output=output) + self.assertEqual(pt, output) + + def test_output_param_neg(self): + LEN_PT = 128 + + pt = b'5' * LEN_PT + cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) + ct = cipher.encrypt(pt) + + cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) + self.assertRaises(TypeError, cipher.encrypt, pt, output=b'0' * LEN_PT) + + cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) + self.assertRaises(TypeError, cipher.decrypt, ct, output=b'0' * LEN_PT) + + shorter_output = bytearray(LEN_PT - 1) + cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) + self.assertRaises(ValueError, cipher.encrypt, pt, output=shorter_output) + cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) + self.assertRaises(ValueError, cipher.decrypt, ct, output=shorter_output) + + +class GcmFSMTests(unittest.TestCase): + + key_128 = get_tag_random("key_128", 16) + nonce_96 = get_tag_random("nonce_128", 12) + data = get_tag_random("data", 128) + + def test_valid_init_encrypt_decrypt_digest_verify(self): + # No authenticated data, fixed plaintext + # Verify path INIT->ENCRYPT->DIGEST + cipher = AES.new(self.key_128, AES.MODE_GCM, + nonce=self.nonce_96) + ct = cipher.encrypt(self.data) + mac = cipher.digest() + + # Verify path INIT->DECRYPT->VERIFY + cipher = AES.new(self.key_128, AES.MODE_GCM, + nonce=self.nonce_96) + cipher.decrypt(ct) + cipher.verify(mac) + + def test_valid_init_update_digest_verify(self): + # No plaintext, fixed authenticated data + # Verify path INIT->UPDATE->DIGEST + cipher = AES.new(self.key_128, AES.MODE_GCM, + nonce=self.nonce_96) + cipher.update(self.data) + mac = cipher.digest() + + # Verify path INIT->UPDATE->VERIFY + cipher = AES.new(self.key_128, AES.MODE_GCM, + nonce=self.nonce_96) + cipher.update(self.data) + cipher.verify(mac) + + def test_valid_full_path(self): + # Fixed authenticated data, fixed plaintext + # Verify path INIT->UPDATE->ENCRYPT->DIGEST + cipher = AES.new(self.key_128, AES.MODE_GCM, + nonce=self.nonce_96) + cipher.update(self.data) + ct = cipher.encrypt(self.data) + mac = cipher.digest() + + # Verify path INIT->UPDATE->DECRYPT->VERIFY + cipher = AES.new(self.key_128, AES.MODE_GCM, + nonce=self.nonce_96) + cipher.update(self.data) + cipher.decrypt(ct) + cipher.verify(mac) + + def test_valid_init_digest(self): + # Verify path INIT->DIGEST + cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) + cipher.digest() + + def test_valid_init_verify(self): + # Verify path INIT->VERIFY + cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) + mac = cipher.digest() + + cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) + cipher.verify(mac) + + def test_valid_multiple_encrypt_or_decrypt(self): + for method_name in "encrypt", "decrypt": + for auth_data in (None, b"333", self.data, + self.data + b"3"): + if auth_data is None: + assoc_len = None + else: + assoc_len = len(auth_data) + cipher = AES.new(self.key_128, AES.MODE_GCM, + nonce=self.nonce_96) + if auth_data is not None: + cipher.update(auth_data) + method = getattr(cipher, method_name) + method(self.data) + method(self.data) + method(self.data) + method(self.data) + + def test_valid_multiple_digest_or_verify(self): + # Multiple calls to digest + cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) + cipher.update(self.data) + first_mac = cipher.digest() + for x in range(4): + self.assertEqual(first_mac, cipher.digest()) + + # Multiple calls to verify + cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) + cipher.update(self.data) + for x in range(5): + cipher.verify(first_mac) + + def test_valid_encrypt_and_digest_decrypt_and_verify(self): + # encrypt_and_digest + cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) + cipher.update(self.data) + ct, mac = cipher.encrypt_and_digest(self.data) + + # decrypt_and_verify + cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) + cipher.update(self.data) + pt = cipher.decrypt_and_verify(ct, mac) + self.assertEqual(self.data, pt) + + def test_invalid_mixing_encrypt_decrypt(self): + # Once per method, with or without assoc. data + for method1_name, method2_name in (("encrypt", "decrypt"), + ("decrypt", "encrypt")): + for assoc_data_present in (True, False): + cipher = AES.new(self.key_128, AES.MODE_GCM, + nonce=self.nonce_96) + if assoc_data_present: + cipher.update(self.data) + getattr(cipher, method1_name)(self.data) + self.assertRaises(TypeError, getattr(cipher, method2_name), + self.data) + + def test_invalid_encrypt_or_update_after_digest(self): + for method_name in "encrypt", "update": + cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) + cipher.encrypt(self.data) + cipher.digest() + self.assertRaises(TypeError, getattr(cipher, method_name), + self.data) + + cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) + cipher.encrypt_and_digest(self.data) + + def test_invalid_decrypt_or_update_after_verify(self): + cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) + ct = cipher.encrypt(self.data) + mac = cipher.digest() + + for method_name in "decrypt", "update": + cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) + cipher.decrypt(ct) + cipher.verify(mac) + self.assertRaises(TypeError, getattr(cipher, method_name), + self.data) + + cipher = AES.new(self.key_128, AES.MODE_GCM, nonce=self.nonce_96) + cipher.decrypt_and_verify(ct, mac) + self.assertRaises(TypeError, getattr(cipher, method_name), + self.data) + + +class TestVectors(unittest.TestCase): + """Class exercising the GCM test vectors found in + http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/gcm/gcm-revised-spec.pdf""" + + # List of test vectors, each made up of: + # - authenticated data + # - plaintext + # - ciphertext + # - MAC + # - AES key + # - nonce + test_vectors_hex = [ + ( + '', + '', + '', + '58e2fccefa7e3061367f1d57a4e7455a', + '00000000000000000000000000000000', + '000000000000000000000000' + ), + ( + '', + '00000000000000000000000000000000', + '0388dace60b6a392f328c2b971b2fe78', + 'ab6e47d42cec13bdf53a67b21257bddf', + '00000000000000000000000000000000', + '000000000000000000000000' + ), + ( + '', + 'd9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a72' + + '1c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255', + '42831ec2217774244b7221b784d0d49ce3aa212f2c02a4e035c17e2329aca12e' + + '21d514b25466931c7d8f6a5aac84aa051ba30b396a0aac973d58e091473f5985', + '4d5c2af327cd64a62cf35abd2ba6fab4', + 'feffe9928665731c6d6a8f9467308308', + 'cafebabefacedbaddecaf888' + ), + ( + 'feedfacedeadbeeffeedfacedeadbeefabaddad2', + 'd9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a72' + + '1c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39', + '42831ec2217774244b7221b784d0d49ce3aa212f2c02a4e035c17e2329aca12e' + + '21d514b25466931c7d8f6a5aac84aa051ba30b396a0aac973d58e091', + '5bc94fbc3221a5db94fae95ae7121a47', + 'feffe9928665731c6d6a8f9467308308', + 'cafebabefacedbaddecaf888' + ), + ( + 'feedfacedeadbeeffeedfacedeadbeefabaddad2', + 'd9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a72' + + '1c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39', + '61353b4c2806934a777ff51fa22a4755699b2a714fcdc6f83766e5f97b6c7423' + + '73806900e49f24b22b097544d4896b424989b5e1ebac0f07c23f4598', + '3612d2e79e3b0785561be14aaca2fccb', + 'feffe9928665731c6d6a8f9467308308', + 'cafebabefacedbad' + ), + ( + 'feedfacedeadbeeffeedfacedeadbeefabaddad2', + 'd9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a72' + + '1c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39', + '8ce24998625615b603a033aca13fb894be9112a5c3a211a8ba262a3cca7e2ca7' + + '01e4a9a4fba43c90ccdcb281d48c7c6fd62875d2aca417034c34aee5', + '619cc5aefffe0bfa462af43c1699d050', + 'feffe9928665731c6d6a8f9467308308', + '9313225df88406e555909c5aff5269aa' + + '6a7a9538534f7da1e4c303d2a318a728c3c0c95156809539fcf0e2429a6b5254' + + '16aedbf5a0de6a57a637b39b' + ), + ( + '', + '', + '', + 'cd33b28ac773f74ba00ed1f312572435', + '000000000000000000000000000000000000000000000000', + '000000000000000000000000' + ), + ( + '', + '00000000000000000000000000000000', + '98e7247c07f0fe411c267e4384b0f600', + '2ff58d80033927ab8ef4d4587514f0fb', + '000000000000000000000000000000000000000000000000', + '000000000000000000000000' + ), + ( + '', + 'd9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a72' + + '1c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255', + '3980ca0b3c00e841eb06fac4872a2757859e1ceaa6efd984628593b40ca1e19c' + + '7d773d00c144c525ac619d18c84a3f4718e2448b2fe324d9ccda2710acade256', + '9924a7c8587336bfb118024db8674a14', + 'feffe9928665731c6d6a8f9467308308feffe9928665731c', + 'cafebabefacedbaddecaf888' + ), + ( + 'feedfacedeadbeeffeedfacedeadbeefabaddad2', + 'd9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a72' + + '1c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39', + '3980ca0b3c00e841eb06fac4872a2757859e1ceaa6efd984628593b40ca1e19c' + + '7d773d00c144c525ac619d18c84a3f4718e2448b2fe324d9ccda2710', + '2519498e80f1478f37ba55bd6d27618c', + 'feffe9928665731c6d6a8f9467308308feffe9928665731c', + 'cafebabefacedbaddecaf888' + ), + ( + 'feedfacedeadbeeffeedfacedeadbeefabaddad2', + 'd9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a72' + + '1c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39', + '0f10f599ae14a154ed24b36e25324db8c566632ef2bbb34f8347280fc4507057' + + 'fddc29df9a471f75c66541d4d4dad1c9e93a19a58e8b473fa0f062f7', + '65dcc57fcf623a24094fcca40d3533f8', + 'feffe9928665731c6d6a8f9467308308feffe9928665731c', + 'cafebabefacedbad' + ), + ( + 'feedfacedeadbeeffeedfacedeadbeefabaddad2', + 'd9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a72' + + '1c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39', + 'd27e88681ce3243c4830165a8fdcf9ff1de9a1d8e6b447ef6ef7b79828666e45' + + '81e79012af34ddd9e2f037589b292db3e67c036745fa22e7e9b7373b', + 'dcf566ff291c25bbb8568fc3d376a6d9', + 'feffe9928665731c6d6a8f9467308308feffe9928665731c', + '9313225df88406e555909c5aff5269aa' + + '6a7a9538534f7da1e4c303d2a318a728c3c0c95156809539fcf0e2429a6b5254' + + '16aedbf5a0de6a57a637b39b' + ), + ( + '', + '', + '', + '530f8afbc74536b9a963b4f1c4cb738b', + '0000000000000000000000000000000000000000000000000000000000000000', + '000000000000000000000000' + ), + ( + '', + '00000000000000000000000000000000', + 'cea7403d4d606b6e074ec5d3baf39d18', + 'd0d1c8a799996bf0265b98b5d48ab919', + '0000000000000000000000000000000000000000000000000000000000000000', + '000000000000000000000000' + ), + ( '', + 'd9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a72' + + '1c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255', + '522dc1f099567d07f47f37a32a84427d643a8cdcbfe5c0c97598a2bd2555d1aa' + + '8cb08e48590dbb3da7b08b1056828838c5f61e6393ba7a0abcc9f662898015ad', + 'b094dac5d93471bdec1a502270e3cc6c', + 'feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308', + 'cafebabefacedbaddecaf888' + ), + ( + 'feedfacedeadbeeffeedfacedeadbeefabaddad2', + 'd9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a72' + + '1c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39', + '522dc1f099567d07f47f37a32a84427d643a8cdcbfe5c0c97598a2bd2555d1aa' + + '8cb08e48590dbb3da7b08b1056828838c5f61e6393ba7a0abcc9f662', + '76fc6ece0f4e1768cddf8853bb2d551b', + 'feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308', + 'cafebabefacedbaddecaf888' + ), + ( + 'feedfacedeadbeeffeedfacedeadbeefabaddad2', + 'd9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a72' + + '1c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39', + 'c3762df1ca787d32ae47c13bf19844cbaf1ae14d0b976afac52ff7d79bba9de0' + + 'feb582d33934a4f0954cc2363bc73f7862ac430e64abe499f47c9b1f', + '3a337dbf46a792c45e454913fe2ea8f2', + 'feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308', + 'cafebabefacedbad' + ), + ( + 'feedfacedeadbeeffeedfacedeadbeefabaddad2', + 'd9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a72' + + '1c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39', + '5a8def2f0c9e53f1f75d7853659e2a20eeb2b22aafde6419a058ab4f6f746bf4' + + '0fc0c3b780f244452da3ebf1c5d82cdea2418997200ef82e44ae7e3f', + 'a44a8266ee1c8eb0c8b5d4cf5ae9f19a', + 'feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308', + '9313225df88406e555909c5aff5269aa' + + '6a7a9538534f7da1e4c303d2a318a728c3c0c95156809539fcf0e2429a6b5254' + + '16aedbf5a0de6a57a637b39b' + ) + ] + + test_vectors = [[unhexlify(x) for x in tv] for tv in test_vectors_hex] + + def runTest(self): + for assoc_data, pt, ct, mac, key, nonce in self.test_vectors: + + # Encrypt + cipher = AES.new(key, AES.MODE_GCM, nonce, mac_len=len(mac)) + cipher.update(assoc_data) + ct2, mac2 = cipher.encrypt_and_digest(pt) + self.assertEqual(ct, ct2) + self.assertEqual(mac, mac2) + + # Decrypt + cipher = AES.new(key, AES.MODE_GCM, nonce, mac_len=len(mac)) + cipher.update(assoc_data) + pt2 = cipher.decrypt_and_verify(ct, mac) + self.assertEqual(pt, pt2) + + +class TestVectorsGueronKrasnov(unittest.TestCase): + """Class exercising the GCM test vectors found in + 'The fragility of AES-GCM authentication algorithm', Gueron, Krasnov + https://eprint.iacr.org/2013/157.pdf""" + + def test_1(self): + key = unhexlify("3da6c536d6295579c0959a7043efb503") + iv = unhexlify("2b926197d34e091ef722db94") + aad = unhexlify("00000000000000000000000000000000" + + "000102030405060708090a0b0c0d0e0f" + + "101112131415161718191a1b1c1d1e1f" + + "202122232425262728292a2b2c2d2e2f" + + "303132333435363738393a3b3c3d3e3f") + digest = unhexlify("69dd586555ce3fcc89663801a71d957b") + + cipher = AES.new(key, AES.MODE_GCM, iv).update(aad) + self.assertEqual(digest, cipher.digest()) + + def test_2(self): + key = unhexlify("843ffcf5d2b72694d19ed01d01249412") + iv = unhexlify("dbcca32ebf9b804617c3aa9e") + aad = unhexlify("00000000000000000000000000000000" + + "101112131415161718191a1b1c1d1e1f") + pt = unhexlify("000102030405060708090a0b0c0d0e0f" + + "101112131415161718191a1b1c1d1e1f" + + "202122232425262728292a2b2c2d2e2f" + + "303132333435363738393a3b3c3d3e3f" + + "404142434445464748494a4b4c4d4e4f") + ct = unhexlify("6268c6fa2a80b2d137467f092f657ac0" + + "4d89be2beaa623d61b5a868c8f03ff95" + + "d3dcee23ad2f1ab3a6c80eaf4b140eb0" + + "5de3457f0fbc111a6b43d0763aa422a3" + + "013cf1dc37fe417d1fbfc449b75d4cc5") + digest = unhexlify("3b629ccfbc1119b7319e1dce2cd6fd6d") + + cipher = AES.new(key, AES.MODE_GCM, iv).update(aad) + ct2, digest2 = cipher.encrypt_and_digest(pt) + + self.assertEqual(ct, ct2) + self.assertEqual(digest, digest2) + + +class NISTTestVectorsGCM(unittest.TestCase): + + def __init__(self, a): + self.use_clmul = True + unittest.TestCase.__init__(self, a) + + +class NISTTestVectorsGCM_no_clmul(unittest.TestCase): + + def __init__(self, a): + self.use_clmul = False + unittest.TestCase.__init__(self, a) + + +test_vectors_nist = load_test_vectors( + ("Cipher", "AES"), + "gcmDecrypt128.rsp", + "GCM decrypt", + {"count": lambda x: int(x)}) or [] + +test_vectors_nist += load_test_vectors( + ("Cipher", "AES"), + "gcmEncryptExtIV128.rsp", + "GCM encrypt", + {"count": lambda x: int(x)}) or [] + +for idx, tv in enumerate(test_vectors_nist): + + # The test vector file contains some directive lines + if isinstance(tv, str): + continue + + def single_test(self, tv=tv): + + self.description = tv.desc + cipher = AES.new(tv.key, AES.MODE_GCM, nonce=tv.iv, + mac_len=len(tv.tag), use_clmul=self.use_clmul) + cipher.update(tv.aad) + if "FAIL" in tv.others: + self.assertRaises(ValueError, cipher.decrypt_and_verify, + tv.ct, tv.tag) + else: + pt = cipher.decrypt_and_verify(tv.ct, tv.tag) + self.assertEqual(pt, tv.pt) + + setattr(NISTTestVectorsGCM, "test_%d" % idx, single_test) + setattr(NISTTestVectorsGCM_no_clmul, "test_%d" % idx, single_test) + + +class TestVectorsWycheproof(unittest.TestCase): + + def __init__(self, wycheproof_warnings, **extra_params): + unittest.TestCase.__init__(self) + self._wycheproof_warnings = wycheproof_warnings + self._extra_params = extra_params + self._id = "None" + + def setUp(self): + + def filter_tag(group): + return group['tagSize'] // 8 + + self.tv = load_test_vectors_wycheproof(("Cipher", "wycheproof"), + "aes_gcm_test.json", + "Wycheproof GCM", + group_tag={'tag_size': filter_tag}) + + def shortDescription(self): + return self._id + + def warn(self, tv): + if tv.warning and self._wycheproof_warnings: + import warnings + warnings.warn("Wycheproof warning: %s (%s)" % (self._id, tv.comment)) + + def test_encrypt(self, tv): + self._id = "Wycheproof Encrypt GCM Test #" + str(tv.id) + + try: + cipher = AES.new(tv.key, AES.MODE_GCM, tv.iv, mac_len=tv.tag_size, + **self._extra_params) + except ValueError as e: + if len(tv.iv) == 0 and "Nonce cannot be empty" in str(e): + return + raise e + + cipher.update(tv.aad) + ct, tag = cipher.encrypt_and_digest(tv.msg) + if tv.valid: + self.assertEqual(ct, tv.ct) + self.assertEqual(tag, tv.tag) + self.warn(tv) + + def test_decrypt(self, tv): + self._id = "Wycheproof Decrypt GCM Test #" + str(tv.id) + + try: + cipher = AES.new(tv.key, AES.MODE_GCM, tv.iv, mac_len=tv.tag_size, + **self._extra_params) + except ValueError as e: + if len(tv.iv) == 0 and "Nonce cannot be empty" in str(e): + return + raise e + + cipher.update(tv.aad) + try: + pt = cipher.decrypt_and_verify(tv.ct, tv.tag) + except ValueError: + assert not tv.valid + else: + assert tv.valid + self.assertEqual(pt, tv.msg) + self.warn(tv) + + def test_corrupt_decrypt(self, tv): + self._id = "Wycheproof Corrupt Decrypt GCM Test #" + str(tv.id) + if len(tv.iv) == 0 or len(tv.ct) < 1: + return + cipher = AES.new(tv.key, AES.MODE_GCM, tv.iv, mac_len=tv.tag_size, + **self._extra_params) + cipher.update(tv.aad) + ct_corrupt = strxor(tv.ct, b"\x00" * (len(tv.ct) - 1) + b"\x01") + self.assertRaises(ValueError, cipher.decrypt_and_verify, ct_corrupt, tv.tag) + + def runTest(self): + + for tv in self.tv: + self.test_encrypt(tv) + self.test_decrypt(tv) + self.test_corrupt_decrypt(tv) + + +class TestVariableLength(unittest.TestCase): + + def __init__(self, **extra_params): + unittest.TestCase.__init__(self) + self._extra_params = extra_params + + def runTest(self): + key = b'0' * 16 + h = SHA256.new() + + for length in range(160): + nonce = '{0:04d}'.format(length).encode('utf-8') + data = bchr(length) * length + cipher = AES.new(key, AES.MODE_GCM, nonce=nonce, **self._extra_params) + ct, tag = cipher.encrypt_and_digest(data) + h.update(ct) + h.update(tag) + + self.assertEqual(h.hexdigest(), "7b7eb1ffbe67a2e53a912067c0ec8e62ebc7ce4d83490ea7426941349811bdf4") + + +def get_tests(config={}): + from Cryptodome.Util import _cpu_features + + wycheproof_warnings = config.get('wycheproof_warnings') + + tests = [] + tests += list_test_cases(GcmTests) + tests += list_test_cases(GcmFSMTests) + tests += [TestVectors()] + tests += [TestVectorsWycheproof(wycheproof_warnings)] + tests += list_test_cases(TestVectorsGueronKrasnov) + tests += [TestVariableLength()] + if config.get('slow_tests'): + tests += list_test_cases(NISTTestVectorsGCM) + + if _cpu_features.have_clmul(): + tests += [TestVectorsWycheproof(wycheproof_warnings, use_clmul=False)] + tests += [TestVariableLength(use_clmul=False)] + if config.get('slow_tests'): + tests += list_test_cases(NISTTestVectorsGCM_no_clmul) + else: + print("Skipping test of PCLMULDQD in AES GCM") + + return tests + + +if __name__ == '__main__': + def suite(): + unittest.TestSuite(get_tests()) + unittest.main(defaultTest='suite') diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/test_KW.py b/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/test_KW.py new file mode 100644 index 0000000..4b530cf --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/test_KW.py @@ -0,0 +1,175 @@ +import unittest + +from Cryptodome.SelfTest.st_common import list_test_cases +from Cryptodome.SelfTest.loader import load_test_vectors_wycheproof + +from Cryptodome.Cipher import AES + + +class KW_Tests(unittest.TestCase): + + # From RFC3394 + tvs = [ + ("000102030405060708090A0B0C0D0E0F", + "00112233445566778899AABBCCDDEEFF", + "1FA68B0A8112B447AEF34BD8FB5A7B829D3E862371D2CFE5"), + ("000102030405060708090A0B0C0D0E0F1011121314151617", + "00112233445566778899AABBCCDDEEFF", + "96778B25AE6CA435F92B5B97C050AED2468AB8A17AD84E5D"), + ("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F", + "00112233445566778899AABBCCDDEEFF", + "64E8C3F9CE0F5BA263E9777905818A2A93C8191E7D6E8AE7"), + ("000102030405060708090A0B0C0D0E0F1011121314151617", + "00112233445566778899AABBCCDDEEFF0001020304050607", + "031D33264E15D33268F24EC260743EDCE1C6C7DDEE725A936BA814915C6762D2"), + ("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F", + "00112233445566778899AABBCCDDEEFF0001020304050607", + "A8F9BC1612C68B3FF6E6F4FBE30E71E4769C8B80A32CB8958CD5D17D6B254DA1"), + ("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F", + "00112233445566778899AABBCCDDEEFF000102030405060708090A0B0C0D0E0F", + "28C9F404C4B810F4CBCCB35CFB87F8263F5786E2D80ED326CBC7F0E71A99F43BFB988B9B7A02DD21"), + ] + + def test_rfc3394(self): + for tv in self.tvs: + kek, pt, ct = [bytes.fromhex(x) for x in tv] + + cipher = AES.new(kek, AES.MODE_KW) + ct2 = cipher.seal(pt) + + self.assertEqual(ct, ct2) + + cipher = AES.new(kek, AES.MODE_KW) + pt2 = cipher.unseal(ct) + self.assertEqual(pt, pt2) + + def test_neg1(self): + + cipher = AES.new(b'-' * 16, AES.MODE_KW) + + with self.assertRaises(ValueError): + cipher.seal(b'') + + with self.assertRaises(ValueError): + cipher.seal(b'8' * 17) + + def test_neg2(self): + + cipher = AES.new(b'-' * 16, AES.MODE_KW) + ct = bytearray(cipher.seal(b'7' * 16)) + + cipher = AES.new(b'-' * 16, AES.MODE_KW) + cipher.unseal(ct) + + cipher = AES.new(b'-' * 16, AES.MODE_KW) + ct[0] ^= 0xFF + with self.assertRaises(ValueError): + cipher.unseal(ct) + + +class KW_Wycheproof(unittest.TestCase): + + def setUp(self): + self.vectors = load_test_vectors_wycheproof(("Cipher", "wycheproof"), + "kw_test.json", + "Wycheproof tests for KW") + + def test_wycheproof(self): + + if not self.vectors: + self.skipTest("No test vectors available") + + for vector in self.vectors: + with self.subTest(testId=vector.id): + cipher = AES.new(vector.key, AES.MODE_KW) + + try: + cipher.seal(vector.msg) + except ValueError: + if vector.valid: + raise + continue + + cipher = AES.new(vector.key, AES.MODE_KW) + try: + pt = cipher.unseal(vector.ct) + except ValueError: + if vector.valid: + raise + continue + + self.assertEqual(pt, vector.msg) + + +class KWP_Tests(unittest.TestCase): + + tvs = [ + ("5840df6e29b02af1ab493b705bf16ea1ae8338f4dcc176a8", + "c37b7e6492584340bed12207808941155068f738", + "138bdeaa9b8fa7fc61f97742e72248ee5ae6ae5360d1ae6a5f54f373fa543b6a"), + ("5840df6e29b02af1ab493b705bf16ea1ae8338f4dcc176a8", + "466f7250617369", + "afbeb0f07dfbf5419200f2ccb50bb24f"), + ] + + def test_rfc5649(self): + for tv in self.tvs: + kek, pt, ct = [bytes.fromhex(x) for x in tv] + + cipher = AES.new(kek, AES.MODE_KWP) + ct2 = cipher.seal(pt) + + self.assertEqual(ct, ct2) + + cipher = AES.new(kek, AES.MODE_KWP) + pt2 = cipher.unseal(ct) + self.assertEqual(pt, pt2) + + +class KWP_Wycheproof(unittest.TestCase): + + def setUp(self): + self.vectors = load_test_vectors_wycheproof(("Cipher", "wycheproof"), + "kwp_test.json", + "Wycheproof tests for KWP") + + def test_wycheproof(self): + + if not self.vectors: + self.skipTest("No test vectors available") + + for vector in self.vectors: + with self.subTest(testId=vector.id): + cipher = AES.new(vector.key, AES.MODE_KWP) + + try: + cipher.seal(vector.msg) + except ValueError: + if vector.valid and not vector.warning: + raise + continue + + cipher = AES.new(vector.key, AES.MODE_KWP) + try: + pt = cipher.unseal(vector.ct) + except ValueError: + if vector.valid and not vector.warning: + raise + continue + + self.assertEqual(pt, vector.msg) + + +def get_tests(config={}): + tests = [] + tests += list_test_cases(KW_Tests) + tests += list_test_cases(KWP_Tests) + tests += list_test_cases(KW_Wycheproof) + tests += list_test_cases(KWP_Wycheproof) + return tests + + +if __name__ == '__main__': + def suite(): + return unittest.TestSuite(get_tests()) + unittest.main(defaultTest='suite') diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/test_OCB.py b/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/test_OCB.py new file mode 100644 index 0000000..1f2ffbc --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/test_OCB.py @@ -0,0 +1,845 @@ +# =================================================================== +# +# Copyright (c) 2014, Legrandin +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# =================================================================== + +import unittest +from binascii import unhexlify + +from Cryptodome.Util.py3compat import b, tobytes, bchr +from Cryptodome.Util.number import long_to_bytes +from Cryptodome.SelfTest.loader import load_test_vectors +from Cryptodome.SelfTest.st_common import list_test_cases + +from Cryptodome.Cipher import AES +from Cryptodome.Hash import SHAKE128 + + +def get_tag_random(tag, length): + return SHAKE128.new(data=tobytes(tag)).read(length) + + +class OcbTests(unittest.TestCase): + + key_128 = get_tag_random("key_128", 16) + nonce_96 = get_tag_random("nonce_128", 12) + data = get_tag_random("data", 128) + + def test_loopback_128(self): + cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96) + pt = get_tag_random("plaintext", 16 * 100) + ct, mac = cipher.encrypt_and_digest(pt) + + cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96) + pt2 = cipher.decrypt_and_verify(ct, mac) + self.assertEqual(pt, pt2) + + def test_nonce(self): + # Nonce is optional + AES.new(self.key_128, AES.MODE_OCB) + + cipher = AES.new(self.key_128, AES.MODE_OCB, self.nonce_96) + ct = cipher.encrypt(self.data) + + cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96) + self.assertEqual(ct, cipher.encrypt(self.data)) + + def test_nonce_must_be_bytes(self): + self.assertRaises(TypeError, AES.new, self.key_128, AES.MODE_OCB, + nonce=u'test12345678') + + def test_nonce_length(self): + # nonce cannot be empty + self.assertRaises(ValueError, AES.new, self.key_128, AES.MODE_OCB, + nonce=b("")) + + # nonce can be up to 15 bytes long + for length in range(1, 16): + AES.new(self.key_128, AES.MODE_OCB, nonce=self.data[:length]) + + self.assertRaises(ValueError, AES.new, self.key_128, AES.MODE_OCB, + nonce=self.data) + + def test_block_size_128(self): + cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96) + self.assertEqual(cipher.block_size, AES.block_size) + + # By default, a 15 bytes long nonce is randomly generated + nonce1 = AES.new(self.key_128, AES.MODE_OCB).nonce + nonce2 = AES.new(self.key_128, AES.MODE_OCB).nonce + self.assertEqual(len(nonce1), 15) + self.assertNotEqual(nonce1, nonce2) + + def test_nonce_attribute(self): + cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96) + self.assertEqual(cipher.nonce, self.nonce_96) + + # By default, a 15 bytes long nonce is randomly generated + nonce1 = AES.new(self.key_128, AES.MODE_OCB).nonce + nonce2 = AES.new(self.key_128, AES.MODE_OCB).nonce + self.assertEqual(len(nonce1), 15) + self.assertNotEqual(nonce1, nonce2) + + def test_unknown_parameters(self): + self.assertRaises(TypeError, AES.new, self.key_128, AES.MODE_OCB, + self.nonce_96, 7) + self.assertRaises(TypeError, AES.new, self.key_128, AES.MODE_OCB, + nonce=self.nonce_96, unknown=7) + + # But some are only known by the base cipher + # (e.g. use_aesni consumed by the AES module) + AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96, + use_aesni=False) + + def test_null_encryption_decryption(self): + for func in "encrypt", "decrypt": + cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96) + result = getattr(cipher, func)(b("")) + self.assertEqual(result, b("")) + + def test_either_encrypt_or_decrypt(self): + cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96) + cipher.encrypt(b("xyz")) + self.assertRaises(TypeError, cipher.decrypt, b("xyz")) + + cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96) + cipher.decrypt(b("xyz")) + self.assertRaises(TypeError, cipher.encrypt, b("xyz")) + + def test_data_must_be_bytes(self): + cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96) + self.assertRaises(TypeError, cipher.encrypt, u'test1234567890-*') + + cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96) + self.assertRaises(TypeError, cipher.decrypt, u'test1234567890-*') + + def test_mac_len(self): + # Invalid MAC length + self.assertRaises(ValueError, AES.new, self.key_128, AES.MODE_OCB, + nonce=self.nonce_96, mac_len=7) + self.assertRaises(ValueError, AES.new, self.key_128, AES.MODE_OCB, + nonce=self.nonce_96, mac_len=16+1) + + # Valid MAC length + for mac_len in range(8, 16 + 1): + cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96, + mac_len=mac_len) + _, mac = cipher.encrypt_and_digest(self.data) + self.assertEqual(len(mac), mac_len) + + # Default MAC length + cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96) + _, mac = cipher.encrypt_and_digest(self.data) + self.assertEqual(len(mac), 16) + + def test_invalid_mac(self): + from Cryptodome.Util.strxor import strxor_c + cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96) + ct, mac = cipher.encrypt_and_digest(self.data) + + invalid_mac = strxor_c(mac, 0x01) + + cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96) + self.assertRaises(ValueError, cipher.decrypt_and_verify, ct, + invalid_mac) + + def test_hex_mac(self): + cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96) + mac_hex = cipher.hexdigest() + self.assertEqual(cipher.digest(), unhexlify(mac_hex)) + + cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96) + cipher.hexverify(mac_hex) + + def test_message_chunks(self): + # Validate that both associated data and plaintext/ciphertext + # can be broken up in chunks of arbitrary length + + auth_data = get_tag_random("authenticated data", 127) + plaintext = get_tag_random("plaintext", 127) + + cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96) + cipher.update(auth_data) + ciphertext, ref_mac = cipher.encrypt_and_digest(plaintext) + + def break_up(data, chunk_length): + return [data[i:i+chunk_length] for i in range(0, len(data), + chunk_length)] + + # Encryption + for chunk_length in 1, 2, 3, 7, 10, 13, 16, 40, 80, 128: + + cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96) + + for chunk in break_up(auth_data, chunk_length): + cipher.update(chunk) + pt2 = b("") + for chunk in break_up(ciphertext, chunk_length): + pt2 += cipher.decrypt(chunk) + pt2 += cipher.decrypt() + self.assertEqual(plaintext, pt2) + cipher.verify(ref_mac) + + # Decryption + for chunk_length in 1, 2, 3, 7, 10, 13, 16, 40, 80, 128: + + cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96) + + for chunk in break_up(auth_data, chunk_length): + cipher.update(chunk) + ct2 = b("") + for chunk in break_up(plaintext, chunk_length): + ct2 += cipher.encrypt(chunk) + ct2 += cipher.encrypt() + self.assertEqual(ciphertext, ct2) + self.assertEqual(cipher.digest(), ref_mac) + + def test_bytearray(self): + + # Encrypt + key_ba = bytearray(self.key_128) + nonce_ba = bytearray(self.nonce_96) + header_ba = bytearray(self.data) + data_ba = bytearray(self.data) + + cipher1 = AES.new(self.key_128, + AES.MODE_OCB, + nonce=self.nonce_96) + cipher1.update(self.data) + ct = cipher1.encrypt(self.data) + cipher1.encrypt() + tag = cipher1.digest() + + cipher2 = AES.new(key_ba, + AES.MODE_OCB, + nonce=nonce_ba) + key_ba[:3] = b"\xFF\xFF\xFF" + nonce_ba[:3] = b"\xFF\xFF\xFF" + cipher2.update(header_ba) + header_ba[:3] = b"\xFF\xFF\xFF" + ct_test = cipher2.encrypt(data_ba) + cipher2.encrypt() + data_ba[:3] = b"\xFF\xFF\xFF" + tag_test = cipher2.digest() + + self.assertEqual(ct, ct_test) + self.assertEqual(tag, tag_test) + self.assertEqual(cipher1.nonce, cipher2.nonce) + + # Decrypt + key_ba = bytearray(self.key_128) + nonce_ba = bytearray(self.nonce_96) + header_ba = bytearray(self.data) + del data_ba + + cipher4 = AES.new(key_ba, + AES.MODE_OCB, + nonce=nonce_ba) + key_ba[:3] = b"\xFF\xFF\xFF" + nonce_ba[:3] = b"\xFF\xFF\xFF" + cipher4.update(header_ba) + header_ba[:3] = b"\xFF\xFF\xFF" + pt_test = cipher4.decrypt_and_verify(bytearray(ct_test), bytearray(tag_test)) + + self.assertEqual(self.data, pt_test) + + def test_memoryview(self): + + # Encrypt + key_mv = memoryview(bytearray(self.key_128)) + nonce_mv = memoryview(bytearray(self.nonce_96)) + header_mv = memoryview(bytearray(self.data)) + data_mv = memoryview(bytearray(self.data)) + + cipher1 = AES.new(self.key_128, + AES.MODE_OCB, + nonce=self.nonce_96) + cipher1.update(self.data) + ct = cipher1.encrypt(self.data) + cipher1.encrypt() + tag = cipher1.digest() + + cipher2 = AES.new(key_mv, + AES.MODE_OCB, + nonce=nonce_mv) + key_mv[:3] = b"\xFF\xFF\xFF" + nonce_mv[:3] = b"\xFF\xFF\xFF" + cipher2.update(header_mv) + header_mv[:3] = b"\xFF\xFF\xFF" + ct_test = cipher2.encrypt(data_mv) + cipher2.encrypt() + data_mv[:3] = b"\xFF\xFF\xFF" + tag_test = cipher2.digest() + + self.assertEqual(ct, ct_test) + self.assertEqual(tag, tag_test) + self.assertEqual(cipher1.nonce, cipher2.nonce) + + # Decrypt + key_mv = memoryview(bytearray(self.key_128)) + nonce_mv = memoryview(bytearray(self.nonce_96)) + header_mv = memoryview(bytearray(self.data)) + del data_mv + + cipher4 = AES.new(key_mv, + AES.MODE_OCB, + nonce=nonce_mv) + key_mv[:3] = b"\xFF\xFF\xFF" + nonce_mv[:3] = b"\xFF\xFF\xFF" + cipher4.update(header_mv) + header_mv[:3] = b"\xFF\xFF\xFF" + pt_test = cipher4.decrypt_and_verify(memoryview(ct_test), memoryview(tag_test)) + + self.assertEqual(self.data, pt_test) + + +class OcbFSMTests(unittest.TestCase): + + key_128 = get_tag_random("key_128", 16) + nonce_96 = get_tag_random("nonce_128", 12) + data = get_tag_random("data", 128) + + def test_valid_init_encrypt_decrypt_digest_verify(self): + # No authenticated data, fixed plaintext + # Verify path INIT->ENCRYPT->ENCRYPT(NONE)->DIGEST + cipher = AES.new(self.key_128, AES.MODE_OCB, + nonce=self.nonce_96) + ct = cipher.encrypt(self.data) + ct += cipher.encrypt() + mac = cipher.digest() + + # Verify path INIT->DECRYPT->DECRYPT(NONCE)->VERIFY + cipher = AES.new(self.key_128, AES.MODE_OCB, + nonce=self.nonce_96) + cipher.decrypt(ct) + cipher.decrypt() + cipher.verify(mac) + + def test_invalid_init_encrypt_decrypt_digest_verify(self): + # No authenticated data, fixed plaintext + # Verify path INIT->ENCRYPT->DIGEST + cipher = AES.new(self.key_128, AES.MODE_OCB, + nonce=self.nonce_96) + ct = cipher.encrypt(self.data) + self.assertRaises(TypeError, cipher.digest) + + # Verify path INIT->DECRYPT->VERIFY + cipher = AES.new(self.key_128, AES.MODE_OCB, + nonce=self.nonce_96) + cipher.decrypt(ct) + self.assertRaises(TypeError, cipher.verify) + + def test_valid_init_update_digest_verify(self): + # No plaintext, fixed authenticated data + # Verify path INIT->UPDATE->DIGEST + cipher = AES.new(self.key_128, AES.MODE_OCB, + nonce=self.nonce_96) + cipher.update(self.data) + mac = cipher.digest() + + # Verify path INIT->UPDATE->VERIFY + cipher = AES.new(self.key_128, AES.MODE_OCB, + nonce=self.nonce_96) + cipher.update(self.data) + cipher.verify(mac) + + def test_valid_full_path(self): + # Fixed authenticated data, fixed plaintext + # Verify path INIT->UPDATE->ENCRYPT->ENCRYPT(NONE)->DIGEST + cipher = AES.new(self.key_128, AES.MODE_OCB, + nonce=self.nonce_96) + cipher.update(self.data) + ct = cipher.encrypt(self.data) + ct += cipher.encrypt() + mac = cipher.digest() + + # Verify path INIT->UPDATE->DECRYPT->DECRYPT(NONE)->VERIFY + cipher = AES.new(self.key_128, AES.MODE_OCB, + nonce=self.nonce_96) + cipher.update(self.data) + cipher.decrypt(ct) + cipher.decrypt() + cipher.verify(mac) + + # Verify path INIT->UPDATE->ENCRYPT->ENCRYPT_AND_DIGEST + cipher = AES.new(self.key_128, AES.MODE_OCB, + nonce=self.nonce_96) + cipher.update(self.data) + ct1 = cipher.encrypt(self.data[:2]) + ct2, mac = cipher.encrypt_and_digest(self.data[2:]) + + # Verify path INIT->UPDATE->DECRYPT->DECRYPT_AND_VERIFY + cipher = AES.new(self.key_128, AES.MODE_OCB, + nonce=self.nonce_96) + cipher.update(self.data) + cipher.decrypt(ct1) + cipher.decrypt_and_verify(ct2, mac) + + def test_invalid_encrypt_after_final(self): + cipher = AES.new(self.key_128, AES.MODE_OCB, + nonce=self.nonce_96) + cipher.update(self.data) + cipher.encrypt(self.data) + cipher.encrypt() + self.assertRaises(TypeError, cipher.encrypt, self.data) + + def test_invalid_decrypt_after_final(self): + cipher = AES.new(self.key_128, AES.MODE_OCB, + nonce=self.nonce_96) + cipher.update(self.data) + cipher.decrypt(self.data) + cipher.decrypt() + self.assertRaises(TypeError, cipher.decrypt, self.data) + + def test_valid_init_digest(self): + # Verify path INIT->DIGEST + cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96) + cipher.digest() + + def test_valid_init_verify(self): + # Verify path INIT->VERIFY + cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96) + mac = cipher.digest() + + cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96) + cipher.verify(mac) + + def test_valid_multiple_encrypt_or_decrypt(self): + for method_name in "encrypt", "decrypt": + for auth_data in (None, b("333"), self.data, + self.data + b("3")): + cipher = AES.new(self.key_128, AES.MODE_OCB, + nonce=self.nonce_96) + if auth_data is not None: + cipher.update(auth_data) + method = getattr(cipher, method_name) + method(self.data) + method(self.data) + method(self.data) + method(self.data) + method() + + def test_valid_multiple_digest_or_verify(self): + # Multiple calls to digest + cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96) + cipher.update(self.data) + first_mac = cipher.digest() + for x in range(4): + self.assertEqual(first_mac, cipher.digest()) + + # Multiple calls to verify + cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96) + cipher.update(self.data) + for x in range(5): + cipher.verify(first_mac) + + def test_valid_encrypt_and_digest_decrypt_and_verify(self): + # encrypt_and_digest + cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96) + cipher.update(self.data) + ct, mac = cipher.encrypt_and_digest(self.data) + + # decrypt_and_verify + cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96) + cipher.update(self.data) + pt = cipher.decrypt_and_verify(ct, mac) + self.assertEqual(self.data, pt) + + def test_invalid_mixing_encrypt_decrypt(self): + # Once per method, with or without assoc. data + for method1_name, method2_name in (("encrypt", "decrypt"), + ("decrypt", "encrypt")): + for assoc_data_present in (True, False): + cipher = AES.new(self.key_128, AES.MODE_OCB, + nonce=self.nonce_96) + if assoc_data_present: + cipher.update(self.data) + getattr(cipher, method1_name)(self.data) + self.assertRaises(TypeError, getattr(cipher, method2_name), + self.data) + + def test_invalid_encrypt_or_update_after_digest(self): + for method_name in "encrypt", "update": + cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96) + cipher.encrypt(self.data) + cipher.encrypt() + cipher.digest() + self.assertRaises(TypeError, getattr(cipher, method_name), + self.data) + + cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96) + cipher.encrypt_and_digest(self.data) + + def test_invalid_decrypt_or_update_after_verify(self): + cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96) + ct = cipher.encrypt(self.data) + ct += cipher.encrypt() + mac = cipher.digest() + + for method_name in "decrypt", "update": + cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96) + cipher.decrypt(ct) + cipher.decrypt() + cipher.verify(mac) + self.assertRaises(TypeError, getattr(cipher, method_name), + self.data) + + cipher = AES.new(self.key_128, AES.MODE_OCB, nonce=self.nonce_96) + cipher.decrypt_and_verify(ct, mac) + self.assertRaises(TypeError, getattr(cipher, method_name), + self.data) + + +def algo_rfc7253(keylen, taglen, noncelen): + """Implement the algorithm at page 18 of RFC 7253""" + + key = bchr(0) * (keylen // 8 - 1) + bchr(taglen) + C = b"" + + for i in range(128): + S = bchr(0) * i + + N = long_to_bytes(3 * i + 1, noncelen // 8) + cipher = AES.new(key, AES.MODE_OCB, nonce=N, mac_len=taglen // 8) + cipher.update(S) + C += cipher.encrypt(S) + cipher.encrypt() + cipher.digest() + + N = long_to_bytes(3 * i + 2, noncelen // 8) + cipher = AES.new(key, AES.MODE_OCB, nonce=N, mac_len=taglen // 8) + C += cipher.encrypt(S) + cipher.encrypt() + cipher.digest() + + N = long_to_bytes(3 * i + 3, noncelen // 8) + cipher = AES.new(key, AES.MODE_OCB, nonce=N, mac_len=taglen // 8) + cipher.update(S) + C += cipher.encrypt() + cipher.digest() + + N = long_to_bytes(385, noncelen // 8) + cipher = AES.new(key, AES.MODE_OCB, nonce=N, mac_len=taglen // 8) + cipher.update(C) + return cipher.encrypt() + cipher.digest() + + +class OcbRfc7253Test(unittest.TestCase): + + # Tuple with + # - nonce + # - authenticated data + # - plaintext + # - ciphertext and 16 byte MAC tag + tv1_key = "000102030405060708090A0B0C0D0E0F" + tv1 = ( + ( + "BBAA99887766554433221100", + "", + "", + "785407BFFFC8AD9EDCC5520AC9111EE6" + ), + ( + "BBAA99887766554433221101", + "0001020304050607", + "0001020304050607", + "6820B3657B6F615A5725BDA0D3B4EB3A257C9AF1F8F03009" + ), + ( + "BBAA99887766554433221102", + "0001020304050607", + "", + "81017F8203F081277152FADE694A0A00" + ), + ( + "BBAA99887766554433221103", + "", + "0001020304050607", + "45DD69F8F5AAE72414054CD1F35D82760B2CD00D2F99BFA9" + ), + ( + "BBAA99887766554433221104", + "000102030405060708090A0B0C0D0E0F", + "000102030405060708090A0B0C0D0E0F", + "571D535B60B277188BE5147170A9A22C3AD7A4FF3835B8C5" + "701C1CCEC8FC3358" + ), + ( + "BBAA99887766554433221105", + "000102030405060708090A0B0C0D0E0F", + "", + "8CF761B6902EF764462AD86498CA6B97" + ), + ( + "BBAA99887766554433221106", + "", + "000102030405060708090A0B0C0D0E0F", + "5CE88EC2E0692706A915C00AEB8B2396F40E1C743F52436B" + "DF06D8FA1ECA343D" + ), + ( + "BBAA99887766554433221107", + "000102030405060708090A0B0C0D0E0F1011121314151617", + "000102030405060708090A0B0C0D0E0F1011121314151617", + "1CA2207308C87C010756104D8840CE1952F09673A448A122" + "C92C62241051F57356D7F3C90BB0E07F" + ), + ( + "BBAA99887766554433221108", + "000102030405060708090A0B0C0D0E0F1011121314151617", + "", + "6DC225A071FC1B9F7C69F93B0F1E10DE" + ), + ( + "BBAA99887766554433221109", + "", + "000102030405060708090A0B0C0D0E0F1011121314151617", + "221BD0DE7FA6FE993ECCD769460A0AF2D6CDED0C395B1C3C" + "E725F32494B9F914D85C0B1EB38357FF" + ), + ( + "BBAA9988776655443322110A", + "000102030405060708090A0B0C0D0E0F1011121314151617" + "18191A1B1C1D1E1F", + "000102030405060708090A0B0C0D0E0F1011121314151617" + "18191A1B1C1D1E1F", + "BD6F6C496201C69296C11EFD138A467ABD3C707924B964DE" + "AFFC40319AF5A48540FBBA186C5553C68AD9F592A79A4240" + ), + ( + "BBAA9988776655443322110B", + "000102030405060708090A0B0C0D0E0F1011121314151617" + "18191A1B1C1D1E1F", + "", + "FE80690BEE8A485D11F32965BC9D2A32" + ), + ( + "BBAA9988776655443322110C", + "", + "000102030405060708090A0B0C0D0E0F1011121314151617" + "18191A1B1C1D1E1F", + "2942BFC773BDA23CABC6ACFD9BFD5835BD300F0973792EF4" + "6040C53F1432BCDFB5E1DDE3BC18A5F840B52E653444D5DF" + ), + ( + "BBAA9988776655443322110D", + "000102030405060708090A0B0C0D0E0F1011121314151617" + "18191A1B1C1D1E1F2021222324252627", + "000102030405060708090A0B0C0D0E0F1011121314151617" + "18191A1B1C1D1E1F2021222324252627", + "D5CA91748410C1751FF8A2F618255B68A0A12E093FF45460" + "6E59F9C1D0DDC54B65E8628E568BAD7AED07BA06A4A69483" + "A7035490C5769E60" + ), + ( + "BBAA9988776655443322110E", + "000102030405060708090A0B0C0D0E0F1011121314151617" + "18191A1B1C1D1E1F2021222324252627", + "", + "C5CD9D1850C141E358649994EE701B68" + ), + ( + "BBAA9988776655443322110F", + "", + "000102030405060708090A0B0C0D0E0F1011121314151617" + "18191A1B1C1D1E1F2021222324252627", + "4412923493C57D5DE0D700F753CCE0D1D2D95060122E9F15" + "A5DDBFC5787E50B5CC55EE507BCB084E479AD363AC366B95" + "A98CA5F3000B1479" + ) + ) + + # Tuple with + # - key + # - nonce + # - authenticated data + # - plaintext + # - ciphertext and 12 byte MAC tag + tv2 = ( + "0F0E0D0C0B0A09080706050403020100", + "BBAA9988776655443322110D", + "000102030405060708090A0B0C0D0E0F1011121314151617" + "18191A1B1C1D1E1F2021222324252627", + "000102030405060708090A0B0C0D0E0F1011121314151617" + "18191A1B1C1D1E1F2021222324252627", + "1792A4E31E0755FB03E31B22116E6C2DDF9EFD6E33D536F1" + "A0124B0A55BAE884ED93481529C76B6AD0C515F4D1CDD4FD" + "AC4F02AA" + ) + + # Tuple with + # - key length + # - MAC tag length + # - Expected output + tv3 = ( + (128, 128, "67E944D23256C5E0B6C61FA22FDF1EA2"), + (192, 128, "F673F2C3E7174AAE7BAE986CA9F29E17"), + (256, 128, "D90EB8E9C977C88B79DD793D7FFA161C"), + (128, 96, "77A3D8E73589158D25D01209"), + (192, 96, "05D56EAD2752C86BE6932C5E"), + (256, 96, "5458359AC23B0CBA9E6330DD"), + (128, 64, "192C9B7BD90BA06A"), + (192, 64, "0066BC6E0EF34E24"), + (256, 64, "7D4EA5D445501CBE"), + ) + + def test1(self): + key = unhexlify(b(self.tv1_key)) + for tv in self.tv1: + nonce, aad, pt, ct = [unhexlify(b(x)) for x in tv] + ct, mac_tag = ct[:-16], ct[-16:] + + cipher = AES.new(key, AES.MODE_OCB, nonce=nonce) + cipher.update(aad) + ct2 = cipher.encrypt(pt) + cipher.encrypt() + self.assertEqual(ct, ct2) + self.assertEqual(mac_tag, cipher.digest()) + + cipher = AES.new(key, AES.MODE_OCB, nonce=nonce) + cipher.update(aad) + pt2 = cipher.decrypt(ct) + cipher.decrypt() + self.assertEqual(pt, pt2) + cipher.verify(mac_tag) + + def test2(self): + + key, nonce, aad, pt, ct = [unhexlify(b(x)) for x in self.tv2] + ct, mac_tag = ct[:-12], ct[-12:] + + cipher = AES.new(key, AES.MODE_OCB, nonce=nonce, mac_len=12) + cipher.update(aad) + ct2 = cipher.encrypt(pt) + cipher.encrypt() + self.assertEqual(ct, ct2) + self.assertEqual(mac_tag, cipher.digest()) + + cipher = AES.new(key, AES.MODE_OCB, nonce=nonce, mac_len=12) + cipher.update(aad) + pt2 = cipher.decrypt(ct) + cipher.decrypt() + self.assertEqual(pt, pt2) + cipher.verify(mac_tag) + + def test3(self): + for keylen, taglen, result in self.tv3: + result2 = algo_rfc7253(keylen, taglen, 96) + self.assertEqual(unhexlify(b(result)), result2) + + +class OcbDkgTest(unittest.TestCase): + """Test vectors from https://gitlab.com/dkg/ocb-test-vectors""" + + def test_1_2(self): + tvs = [] + for fi in (1, 2): + for nb in (104, 112, 120): + tv_file = load_test_vectors(("Cipher", "AES"), + "test-vector-%d-nonce%d.txt" % (fi, nb), + "DKG tests, %d, %d bits" % (fi, nb), + {}) + if tv_file is None: + break + key = tv_file[0].k + for tv in tv_file[1:]: + tv.k = key + tvs.append(tv) + + for tv in tvs: + k, n, a, p, c = tv.k, tv.n, tv.a, tv.p, tv.c + mac_len = len(c) - len(p) + cipher = AES.new(k, AES.MODE_OCB, nonce=n, mac_len=mac_len) + cipher.update(a) + c_out, tag_out = cipher.encrypt_and_digest(p) + self.assertEqual(c, c_out + tag_out) + + def test_3(self): + + def check(keylen, taglen, noncelen, exp): + result = algo_rfc7253(keylen, taglen, noncelen) + self.assertEqual(result, unhexlify(exp)) + + # test-vector-3-nonce104.txt + check(128, 128, 104, "C47F5F0341E15326D4D1C46F47F05062") + check(192, 128, 104, "95B9167A38EB80495DFC561A8486E109") + check(256, 128, 104, "AFE1CDDB97028FD92F8FB3C8CFBA7D83") + check(128, 96, 104, "F471B4983BA80946DF217A54") + check(192, 96, 104, "5AE828BC51C24D85FA5CC7B2") + check(256, 96, 104, "8C8335982E2B734616CAD14C") + check(128, 64, 104, "B553F74B85FD1E5B") + check(192, 64, 104, "3B49D20E513531F9") + check(256, 64, 104, "ED6DA5B1216BF8BB") + + # test-vector-3-nonce112.txt + check(128, 128, 112, "CA8AFCA031BAC3F480A583BD6C50A547") + check(192, 128, 112, "D170C1DF356308079DA9A3F619147148") + check(256, 128, 112, "57F94381F2F9231EFB04AECD323757C3") + check(128, 96, 112, "3A618B2531ED39F260C750DC") + check(192, 96, 112, "9071EB89FEDBADDA88FD286E") + check(256, 96, 112, "FDF0EFB97F21A39AC4BAB5AC") + check(128, 64, 112, "FAB2FF3A8DD82A13") + check(192, 64, 112, "AC01D912BD0737D3") + check(256, 64, 112, "9D1FD0B500EA4ECF") + + # test-vector-3-nonce120.txt + check(128, 128, 120, "9E043A7140A25FB91F43BCC9DD7E0F46") + check(192, 128, 120, "680000E53908323A7F396B955B8EC641") + check(256, 128, 120, "8304B97FAACDA56E676602E1878A7E6F") + check(128, 96, 120, "81F978AC9867E825D339847D") + check(192, 96, 120, "EFCF2D60B24926ADA48CF5B1") + check(256, 96, 120, "84961DC56E917B165E58C174") + check(128, 64, 120, "227AEE6C9D905A61") + check(192, 64, 120, "541DE691B9E1A2F9") + check(256, 64, 120, "B0E761381C7129FC") + + def test_2_bugfix(self): + nonce = unhexlify("EEDDCCBBAA9988776655443322110D") + key = unhexlify("0F0E0D0C0B0A09080706050403020100") + A = unhexlify("000102030405060708090A0B0C0D0E0F1011121314151617" + "18191A1B1C1D1E1F2021222324252627") + P = unhexlify("000102030405060708090A0B0C0D0E0F1011121314151617" + "18191A1B1C1D1E1F2021222324252627") + C = unhexlify("07E903BFC49552411ABC865F5ECE60F6FAD1F5A9F14D3070" + "FA2F1308A563207FFE14C1EEA44B22059C7484319D8A2C53" + "C236A7B3") + mac_len = len(C) - len(P) + + # Prior to version 3.17, a nonce of maximum length (15 bytes) + # was actually used as a 14 byte nonce. The last byte was erroneously + # ignored. + buggy_result = unhexlify("BA015C4E5AE54D76C890AE81BD40DC57" + "03EDC30E8AC2A58BC5D8FA4D61C5BAE6" + "C39BEAC435B2FD56A2A5085C1B135D77" + "0C8264B7") + cipher = AES.new(key, AES.MODE_OCB, nonce=nonce[:-1], mac_len=mac_len) + cipher.update(A) + C_out2, tag_out2 = cipher.encrypt_and_digest(P) + self.assertEqual(buggy_result, C_out2 + tag_out2) + + +def get_tests(config={}): + tests = [] + tests += list_test_cases(OcbTests) + tests += list_test_cases(OcbFSMTests) + tests += list_test_cases(OcbRfc7253Test) + tests += list_test_cases(OcbDkgTest) + return tests + + +if __name__ == '__main__': + def suite(): + return unittest.TestSuite(get_tests()) + unittest.main(defaultTest='suite') diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/test_OFB.py b/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/test_OFB.py new file mode 100644 index 0000000..9a8ef0a --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/test_OFB.py @@ -0,0 +1,238 @@ +# =================================================================== +# +# Copyright (c) 2015, Legrandin +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# =================================================================== + +import unittest +from binascii import unhexlify + +from Cryptodome.SelfTest.st_common import list_test_cases +from Cryptodome.Util.py3compat import tobytes +from Cryptodome.Cipher import AES, DES3, DES +from Cryptodome.Hash import SHAKE128 +from Cryptodome.SelfTest.loader import load_test_vectors_wycheproof + +def get_tag_random(tag, length): + return SHAKE128.new(data=tobytes(tag)).read(length) + +from Cryptodome.SelfTest.Cipher.test_CBC import BlockChainingTests + +class OfbTests(BlockChainingTests): + + aes_mode = AES.MODE_OFB + des3_mode = DES3.MODE_OFB + + # Redefine test_unaligned_data_128/64 + + def test_unaligned_data_128(self): + plaintexts = [ b"7777777" ] * 100 + + cipher = AES.new(self.key_128, AES.MODE_CFB, self.iv_128, segment_size=8) + ciphertexts = [ cipher.encrypt(x) for x in plaintexts ] + cipher = AES.new(self.key_128, AES.MODE_CFB, self.iv_128, segment_size=8) + self.assertEqual(b"".join(ciphertexts), cipher.encrypt(b"".join(plaintexts))) + + cipher = AES.new(self.key_128, AES.MODE_CFB, self.iv_128, segment_size=128) + ciphertexts = [ cipher.encrypt(x) for x in plaintexts ] + cipher = AES.new(self.key_128, AES.MODE_CFB, self.iv_128, segment_size=128) + self.assertEqual(b"".join(ciphertexts), cipher.encrypt(b"".join(plaintexts))) + + def test_unaligned_data_64(self): + plaintexts = [ b"7777777" ] * 100 + cipher = DES3.new(self.key_192, DES3.MODE_CFB, self.iv_64, segment_size=8) + ciphertexts = [ cipher.encrypt(x) for x in plaintexts ] + cipher = DES3.new(self.key_192, DES3.MODE_CFB, self.iv_64, segment_size=8) + self.assertEqual(b"".join(ciphertexts), cipher.encrypt(b"".join(plaintexts))) + + cipher = DES3.new(self.key_192, DES3.MODE_CFB, self.iv_64, segment_size=64) + ciphertexts = [ cipher.encrypt(x) for x in plaintexts ] + cipher = DES3.new(self.key_192, DES3.MODE_CFB, self.iv_64, segment_size=64) + self.assertEqual(b"".join(ciphertexts), cipher.encrypt(b"".join(plaintexts))) + + +from Cryptodome.SelfTest.Cipher.test_CBC import NistBlockChainingVectors + +class NistOfbVectors(NistBlockChainingVectors): + aes_mode = AES.MODE_OFB + des_mode = DES.MODE_OFB + des3_mode = DES3.MODE_OFB + + +# Create one test method per file +nist_aes_kat_mmt_files = ( + # KAT + "OFBGFSbox128.rsp", + "OFBGFSbox192.rsp", + "OFBGFSbox256.rsp", + "OFBKeySbox128.rsp", + "OFBKeySbox192.rsp", + "OFBKeySbox256.rsp", + "OFBVarKey128.rsp", + "OFBVarKey192.rsp", + "OFBVarKey256.rsp", + "OFBVarTxt128.rsp", + "OFBVarTxt192.rsp", + "OFBVarTxt256.rsp", + # MMT + "OFBMMT128.rsp", + "OFBMMT192.rsp", + "OFBMMT256.rsp", + ) +nist_aes_mct_files = ( + "OFBMCT128.rsp", + "OFBMCT192.rsp", + "OFBMCT256.rsp", + ) + +for file_name in nist_aes_kat_mmt_files: + def new_func(self, file_name=file_name): + self._do_kat_aes_test(file_name) + setattr(NistOfbVectors, "test_AES_" + file_name, new_func) + +for file_name in nist_aes_mct_files: + def new_func(self, file_name=file_name): + self._do_mct_aes_test(file_name) + setattr(NistOfbVectors, "test_AES_" + file_name, new_func) +del file_name, new_func + +nist_tdes_files = ( + "TOFBMMT2.rsp", # 2TDES + "TOFBMMT3.rsp", # 3TDES + "TOFBinvperm.rsp", # Single DES + "TOFBpermop.rsp", + "TOFBsubtab.rsp", + "TOFBvarkey.rsp", + "TOFBvartext.rsp", + ) + +for file_name in nist_tdes_files: + def new_func(self, file_name=file_name): + self._do_tdes_test(file_name) + setattr(NistOfbVectors, "test_TDES_" + file_name, new_func) + +# END OF NIST OFB TEST VECTORS + + +class SP800TestVectors(unittest.TestCase): + """Class exercising the OFB test vectors found in Section F.4 + of NIST SP 800-3A""" + + def test_aes_128(self): + plaintext = '6bc1bee22e409f96e93d7e117393172a' +\ + 'ae2d8a571e03ac9c9eb76fac45af8e51' +\ + '30c81c46a35ce411e5fbc1191a0a52ef' +\ + 'f69f2445df4f9b17ad2b417be66c3710' + ciphertext = '3b3fd92eb72dad20333449f8e83cfb4a' +\ + '7789508d16918f03f53c52dac54ed825' +\ + '9740051e9c5fecf64344f7a82260edcc' +\ + '304c6528f659c77866a510d9c1d6ae5e' + key = '2b7e151628aed2a6abf7158809cf4f3c' + iv = '000102030405060708090a0b0c0d0e0f' + + key = unhexlify(key) + iv = unhexlify(iv) + plaintext = unhexlify(plaintext) + ciphertext = unhexlify(ciphertext) + + cipher = AES.new(key, AES.MODE_OFB, iv) + self.assertEqual(cipher.encrypt(plaintext), ciphertext) + cipher = AES.new(key, AES.MODE_OFB, iv) + self.assertEqual(cipher.decrypt(ciphertext), plaintext) + + cipher = AES.new(key, AES.MODE_OFB, iv) + self.assertEqual(cipher.encrypt(plaintext[:-8]), ciphertext[:-8]) + cipher = AES.new(key, AES.MODE_OFB, iv) + self.assertEqual(cipher.decrypt(ciphertext[:-8]), plaintext[:-8]) + + def test_aes_192(self): + plaintext = '6bc1bee22e409f96e93d7e117393172a' +\ + 'ae2d8a571e03ac9c9eb76fac45af8e51' +\ + '30c81c46a35ce411e5fbc1191a0a52ef' +\ + 'f69f2445df4f9b17ad2b417be66c3710' + ciphertext = 'cdc80d6fddf18cab34c25909c99a4174' +\ + 'fcc28b8d4c63837c09e81700c1100401' +\ + '8d9a9aeac0f6596f559c6d4daf59a5f2' +\ + '6d9f200857ca6c3e9cac524bd9acc92a' + key = '8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b' + iv = '000102030405060708090a0b0c0d0e0f' + + key = unhexlify(key) + iv = unhexlify(iv) + plaintext = unhexlify(plaintext) + ciphertext = unhexlify(ciphertext) + + cipher = AES.new(key, AES.MODE_OFB, iv) + self.assertEqual(cipher.encrypt(plaintext), ciphertext) + cipher = AES.new(key, AES.MODE_OFB, iv) + self.assertEqual(cipher.decrypt(ciphertext), plaintext) + + cipher = AES.new(key, AES.MODE_OFB, iv) + self.assertEqual(cipher.encrypt(plaintext[:-8]), ciphertext[:-8]) + cipher = AES.new(key, AES.MODE_OFB, iv) + self.assertEqual(cipher.decrypt(ciphertext[:-8]), plaintext[:-8]) + + def test_aes_256(self): + plaintext = '6bc1bee22e409f96e93d7e117393172a' +\ + 'ae2d8a571e03ac9c9eb76fac45af8e51' +\ + '30c81c46a35ce411e5fbc1191a0a52ef' +\ + 'f69f2445df4f9b17ad2b417be66c3710' + ciphertext = 'dc7e84bfda79164b7ecd8486985d3860' +\ + '4febdc6740d20b3ac88f6ad82a4fb08d' +\ + '71ab47a086e86eedf39d1c5bba97c408' +\ + '0126141d67f37be8538f5a8be740e484' + key = '603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4' + iv = '000102030405060708090a0b0c0d0e0f' + + key = unhexlify(key) + iv = unhexlify(iv) + plaintext = unhexlify(plaintext) + ciphertext = unhexlify(ciphertext) + + cipher = AES.new(key, AES.MODE_OFB, iv) + self.assertEqual(cipher.encrypt(plaintext), ciphertext) + cipher = AES.new(key, AES.MODE_OFB, iv) + self.assertEqual(cipher.decrypt(ciphertext), plaintext) + + cipher = AES.new(key, AES.MODE_OFB, iv) + self.assertEqual(cipher.encrypt(plaintext[:-8]), ciphertext[:-8]) + cipher = AES.new(key, AES.MODE_OFB, iv) + self.assertEqual(cipher.decrypt(ciphertext[:-8]), plaintext[:-8]) + + +def get_tests(config={}): + tests = [] + tests += list_test_cases(OfbTests) + if config.get('slow_tests'): + tests += list_test_cases(NistOfbVectors) + tests += list_test_cases(SP800TestVectors) + return tests + + +if __name__ == '__main__': + suite = lambda: unittest.TestSuite(get_tests()) + unittest.main(defaultTest='suite') diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/test_OpenPGP.py b/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/test_OpenPGP.py new file mode 100644 index 0000000..4090a1a --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/test_OpenPGP.py @@ -0,0 +1,218 @@ +# =================================================================== +# +# Copyright (c) 2015, Legrandin +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# =================================================================== + +import unittest +from binascii import unhexlify + +from Cryptodome.SelfTest.st_common import list_test_cases +from Cryptodome.Util.py3compat import tobytes +from Cryptodome.Cipher import AES, DES3, DES +from Cryptodome.Hash import SHAKE128 + +def get_tag_random(tag, length): + return SHAKE128.new(data=tobytes(tag)).read(length) + + +from Cryptodome.SelfTest.Cipher.test_CBC import BlockChainingTests + +class OpenPGPTests(BlockChainingTests): + + aes_mode = AES.MODE_OPENPGP + des3_mode = DES3.MODE_OPENPGP + + # Redefine test_unaligned_data_128/64 + + key_128 = get_tag_random("key_128", 16) + key_192 = get_tag_random("key_192", 24) + iv_128 = get_tag_random("iv_128", 16) + iv_64 = get_tag_random("iv_64", 8) + data_128 = get_tag_random("data_128", 16) + + def test_loopback_128(self): + cipher = AES.new(self.key_128, AES.MODE_OPENPGP, self.iv_128) + pt = get_tag_random("plaintext", 16 * 100) + ct = cipher.encrypt(pt) + + eiv, ct = ct[:18], ct[18:] + + cipher = AES.new(self.key_128, AES.MODE_OPENPGP, eiv) + pt2 = cipher.decrypt(ct) + self.assertEqual(pt, pt2) + + def test_loopback_64(self): + cipher = DES3.new(self.key_192, DES3.MODE_OPENPGP, self.iv_64) + pt = get_tag_random("plaintext", 8 * 100) + ct = cipher.encrypt(pt) + + eiv, ct = ct[:10], ct[10:] + + cipher = DES3.new(self.key_192, DES3.MODE_OPENPGP, eiv) + pt2 = cipher.decrypt(ct) + self.assertEqual(pt, pt2) + + def test_IV_iv_attributes(self): + cipher = AES.new(self.key_128, AES.MODE_OPENPGP, self.iv_128) + eiv = cipher.encrypt(b"") + self.assertEqual(cipher.iv, self.iv_128) + + cipher = AES.new(self.key_128, AES.MODE_OPENPGP, eiv) + self.assertEqual(cipher.iv, self.iv_128) + + def test_null_encryption_decryption(self): + cipher = AES.new(self.key_128, AES.MODE_OPENPGP, self.iv_128) + eiv = cipher.encrypt(b"") + + cipher = AES.new(self.key_128, AES.MODE_OPENPGP, eiv) + self.assertEqual(cipher.decrypt(b""), b"") + + def test_either_encrypt_or_decrypt(self): + cipher = AES.new(self.key_128, AES.MODE_OPENPGP, self.iv_128) + eiv = cipher.encrypt(b"") + self.assertRaises(TypeError, cipher.decrypt, b"") + + cipher = AES.new(self.key_128, AES.MODE_OPENPGP, eiv) + cipher.decrypt(b"") + self.assertRaises(TypeError, cipher.encrypt, b"") + + def test_unaligned_data_128(self): + plaintexts = [ b"7777777" ] * 100 + + cipher = AES.new(self.key_128, AES.MODE_OPENPGP, self.iv_128) + ciphertexts = [ cipher.encrypt(x) for x in plaintexts ] + cipher = AES.new(self.key_128, AES.MODE_OPENPGP, self.iv_128) + self.assertEqual(b"".join(ciphertexts), cipher.encrypt(b"".join(plaintexts))) + + def test_unaligned_data_64(self): + plaintexts = [ b"7777777" ] * 100 + + cipher = DES3.new(self.key_192, DES3.MODE_OPENPGP, self.iv_64) + ciphertexts = [ cipher.encrypt(x) for x in plaintexts ] + cipher = DES3.new(self.key_192, DES3.MODE_OPENPGP, self.iv_64) + self.assertEqual(b"".join(ciphertexts), cipher.encrypt(b"".join(plaintexts))) + + def test_output_param(self): + pass + + def test_output_param_same_buffer(self): + pass + + def test_output_param_memoryview(self): + pass + + def test_output_param_neg(self): + pass + + +class TestVectors(unittest.TestCase): + + def test_aes(self): + # The following test vectors have been generated with gpg v1.4.0. + # The command line used was: + # + # gpg -c -z 0 --cipher-algo AES --passphrase secret_passphrase \ + # --disable-mdc --s2k-mode 0 --output ct pt + # + # As result, the content of the file 'pt' is encrypted with a key derived + # from 'secret_passphrase' and written to file 'ct'. + # Test vectors must be extracted from 'ct', which is a collection of + # TLVs (see RFC4880 for all details): + # - the encrypted data (with the encrypted IV as prefix) is the payload + # of the TLV with tag 9 (Symmetrical Encrypted Data Packet). + # This is the ciphertext in the test vector. + # - inside the encrypted part, there is a further layer of TLVs. One must + # look for tag 11 (Literal Data Packet); in its payload, after a short + # but time dependent header, there is the content of file 'pt'. + # In the test vector, the plaintext is the complete set of TLVs that gets + # encrypted. It is not just the content of 'pt'. + # - the key is the leftmost 16 bytes of the SHA1 digest of the password. + # The test vector contains such shortened digest. + # + # Note that encryption uses a clear IV, and decryption an encrypted IV + + plaintext = 'ac18620270744fb4f647426c61636b4361745768697465436174' + ciphertext = 'dc6b9e1f095de609765c59983db5956ae4f63aea7405389d2ebb' + key = '5baa61e4c9b93f3f0682250b6cf8331b' + iv = '3d7d3e62282add7eb203eeba5c800733' + encrypted_iv='fd934601ef49cb58b6d9aebca6056bdb96ef' + + plaintext = unhexlify(plaintext) + ciphertext = unhexlify(ciphertext) + key = unhexlify(key) + iv = unhexlify(iv) + encrypted_iv = unhexlify(encrypted_iv) + + cipher = AES.new(key, AES.MODE_OPENPGP, iv) + ct = cipher.encrypt(plaintext) + self.assertEqual(ct[:18], encrypted_iv) + self.assertEqual(ct[18:], ciphertext) + + cipher = AES.new(key, AES.MODE_OPENPGP, encrypted_iv) + pt = cipher.decrypt(ciphertext) + self.assertEqual(pt, plaintext) + + def test_des3(self): + # The following test vectors have been generated with gpg v1.4.0. + # The command line used was: + # gpg -c -z 0 --cipher-algo 3DES --passphrase secret_passphrase \ + # --disable-mdc --s2k-mode 0 --output ct pt + # For an explanation, see test_AES.py . + + plaintext = 'ac1762037074324fb53ba3596f73656d69746556616c6c6579' + ciphertext = '9979238528357b90e2e0be549cb0b2d5999b9a4a447e5c5c7d' + key = '7ade65b460f5ea9be35f9e14aa883a2048e3824aa616c0b2' + iv='cd47e2afb8b7e4b0' + encrypted_iv='6a7eef0b58050e8b904a' + + plaintext = unhexlify(plaintext) + ciphertext = unhexlify(ciphertext) + key = unhexlify(key) + iv = unhexlify(iv) + encrypted_iv = unhexlify(encrypted_iv) + + cipher = DES3.new(key, DES3.MODE_OPENPGP, iv) + ct = cipher.encrypt(plaintext) + self.assertEqual(ct[:10], encrypted_iv) + self.assertEqual(ct[10:], ciphertext) + + cipher = DES3.new(key, DES3.MODE_OPENPGP, encrypted_iv) + pt = cipher.decrypt(ciphertext) + self.assertEqual(pt, plaintext) + + +def get_tests(config={}): + tests = [] + tests += list_test_cases(OpenPGPTests) + tests += list_test_cases(TestVectors) + return tests + + +if __name__ == '__main__': + suite = lambda: unittest.TestSuite(get_tests()) + unittest.main(defaultTest='suite') diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/test_SIV.py b/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/test_SIV.py new file mode 100644 index 0000000..d4bb5a9 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/test_SIV.py @@ -0,0 +1,552 @@ +# =================================================================== +# +# Copyright (c) 2015, Legrandin +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# =================================================================== + +import json +import unittest +from binascii import unhexlify + +from Cryptodome.SelfTest.st_common import list_test_cases +from Cryptodome.SelfTest.loader import load_test_vectors_wycheproof + +from Cryptodome.Util.py3compat import tobytes, bchr +from Cryptodome.Cipher import AES +from Cryptodome.Hash import SHAKE128 + +from Cryptodome.Util.strxor import strxor + + +def get_tag_random(tag, length): + return SHAKE128.new(data=tobytes(tag)).read(length) + + +class SivTests(unittest.TestCase): + + key_256 = get_tag_random("key_256", 32) + key_384 = get_tag_random("key_384", 48) + key_512 = get_tag_random("key_512", 64) + nonce_96 = get_tag_random("nonce_128", 12) + data = get_tag_random("data", 128) + + def test_loopback_128(self): + for key in self.key_256, self.key_384, self.key_512: + cipher = AES.new(key, AES.MODE_SIV, nonce=self.nonce_96) + pt = get_tag_random("plaintext", 16 * 100) + ct, mac = cipher.encrypt_and_digest(pt) + + cipher = AES.new(key, AES.MODE_SIV, nonce=self.nonce_96) + pt2 = cipher.decrypt_and_verify(ct, mac) + self.assertEqual(pt, pt2) + + def test_nonce(self): + # Deterministic encryption + AES.new(self.key_256, AES.MODE_SIV) + + cipher = AES.new(self.key_256, AES.MODE_SIV, self.nonce_96) + ct1, tag1 = cipher.encrypt_and_digest(self.data) + + cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) + ct2, tag2 = cipher.encrypt_and_digest(self.data) + self.assertEqual(ct1 + tag1, ct2 + tag2) + + def test_nonce_must_be_bytes(self): + self.assertRaises(TypeError, AES.new, self.key_256, AES.MODE_SIV, + nonce=u'test12345678') + + def test_nonce_length(self): + # nonce can be of any length (but not empty) + self.assertRaises(ValueError, AES.new, self.key_256, AES.MODE_SIV, + nonce=b"") + + for x in range(1, 128): + cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=bchr(1) * x) + cipher.encrypt_and_digest(b'\x01') + + def test_block_size_128(self): + cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) + self.assertEqual(cipher.block_size, AES.block_size) + + def test_nonce_attribute(self): + cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) + self.assertEqual(cipher.nonce, self.nonce_96) + + # By default, no nonce is randomly generated + self.assertFalse(hasattr(AES.new(self.key_256, AES.MODE_SIV), "nonce")) + + def test_unknown_parameters(self): + self.assertRaises(TypeError, AES.new, self.key_256, AES.MODE_SIV, + self.nonce_96, 7) + self.assertRaises(TypeError, AES.new, self.key_256, AES.MODE_SIV, + nonce=self.nonce_96, unknown=7) + + # But some are only known by the base cipher + # (e.g. use_aesni consumed by the AES module) + AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96, + use_aesni=False) + + def test_encrypt_excludes_decrypt(self): + cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) + cipher.encrypt_and_digest(self.data) + self.assertRaises(TypeError, cipher.decrypt, self.data) + + cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) + cipher.encrypt_and_digest(self.data) + self.assertRaises(TypeError, cipher.decrypt_and_verify, + self.data, self.data) + + def test_data_must_be_bytes(self): + cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) + self.assertRaises(TypeError, cipher.encrypt, u'test1234567890-*') + + cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) + self.assertRaises(TypeError, cipher.decrypt_and_verify, + u'test1234567890-*', b"xxxx") + + def test_mac_len(self): + cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) + _, mac = cipher.encrypt_and_digest(self.data) + self.assertEqual(len(mac), 16) + + def test_invalid_mac(self): + from Cryptodome.Util.strxor import strxor_c + cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) + ct, mac = cipher.encrypt_and_digest(self.data) + + invalid_mac = strxor_c(mac, 0x01) + + cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) + self.assertRaises(ValueError, cipher.decrypt_and_verify, ct, + invalid_mac) + + def test_hex_mac(self): + cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) + mac_hex = cipher.hexdigest() + self.assertEqual(cipher.digest(), unhexlify(mac_hex)) + + cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) + cipher.hexverify(mac_hex) + + def test_bytearray(self): + + # Encrypt + key = bytearray(self.key_256) + nonce = bytearray(self.nonce_96) + data = bytearray(self.data) + header = bytearray(self.data) + + cipher1 = AES.new(self.key_256, + AES.MODE_SIV, + nonce=self.nonce_96) + cipher1.update(self.data) + ct, tag = cipher1.encrypt_and_digest(self.data) + + cipher2 = AES.new(key, + AES.MODE_SIV, + nonce=nonce) + key[:3] = b'\xFF\xFF\xFF' + nonce[:3] = b'\xFF\xFF\xFF' + cipher2.update(header) + header[:3] = b'\xFF\xFF\xFF' + ct_test, tag_test = cipher2.encrypt_and_digest(data) + + self.assertEqual(ct, ct_test) + self.assertEqual(tag, tag_test) + self.assertEqual(cipher1.nonce, cipher2.nonce) + + # Decrypt + key = bytearray(self.key_256) + nonce = bytearray(self.nonce_96) + header = bytearray(self.data) + ct_ba = bytearray(ct) + tag_ba = bytearray(tag) + + cipher3 = AES.new(key, + AES.MODE_SIV, + nonce=nonce) + key[:3] = b'\xFF\xFF\xFF' + nonce[:3] = b'\xFF\xFF\xFF' + cipher3.update(header) + header[:3] = b'\xFF\xFF\xFF' + pt_test = cipher3.decrypt_and_verify(ct_ba, tag_ba) + + self.assertEqual(self.data, pt_test) + + def test_memoryview(self): + + # Encrypt + key = memoryview(bytearray(self.key_256)) + nonce = memoryview(bytearray(self.nonce_96)) + data = memoryview(bytearray(self.data)) + header = memoryview(bytearray(self.data)) + + cipher1 = AES.new(self.key_256, + AES.MODE_SIV, + nonce=self.nonce_96) + cipher1.update(self.data) + ct, tag = cipher1.encrypt_and_digest(self.data) + + cipher2 = AES.new(key, + AES.MODE_SIV, + nonce=nonce) + key[:3] = b'\xFF\xFF\xFF' + nonce[:3] = b'\xFF\xFF\xFF' + cipher2.update(header) + header[:3] = b'\xFF\xFF\xFF' + ct_test, tag_test= cipher2.encrypt_and_digest(data) + + self.assertEqual(ct, ct_test) + self.assertEqual(tag, tag_test) + self.assertEqual(cipher1.nonce, cipher2.nonce) + + # Decrypt + key = memoryview(bytearray(self.key_256)) + nonce = memoryview(bytearray(self.nonce_96)) + header = memoryview(bytearray(self.data)) + ct_ba = memoryview(bytearray(ct)) + tag_ba = memoryview(bytearray(tag)) + + cipher3 = AES.new(key, + AES.MODE_SIV, + nonce=nonce) + key[:3] = b'\xFF\xFF\xFF' + nonce[:3] = b'\xFF\xFF\xFF' + cipher3.update(header) + header[:3] = b'\xFF\xFF\xFF' + pt_test = cipher3.decrypt_and_verify(ct_ba, tag_ba) + + self.assertEqual(self.data, pt_test) + + def test_output_param(self): + + pt = b'5' * 128 + cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) + ct, tag = cipher.encrypt_and_digest(pt) + + output = bytearray(128) + cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) + res, tag_out = cipher.encrypt_and_digest(pt, output=output) + self.assertEqual(ct, output) + self.assertEqual(res, None) + self.assertEqual(tag, tag_out) + + cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) + res = cipher.decrypt_and_verify(ct, tag, output=output) + self.assertEqual(pt, output) + self.assertEqual(res, None) + + def test_output_param_memoryview(self): + + pt = b'5' * 128 + cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) + ct, tag = cipher.encrypt_and_digest(pt) + + output = memoryview(bytearray(128)) + cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) + cipher.encrypt_and_digest(pt, output=output) + self.assertEqual(ct, output) + + cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) + cipher.decrypt_and_verify(ct, tag, output=output) + self.assertEqual(pt, output) + + def test_output_param_neg(self): + LEN_PT = 128 + + pt = b'5' * LEN_PT + cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) + ct, tag = cipher.encrypt_and_digest(pt) + + cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) + self.assertRaises(TypeError, cipher.encrypt_and_digest, pt, output=b'0' * LEN_PT) + + cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) + self.assertRaises(TypeError, cipher.decrypt_and_verify, ct, tag, output=b'0' * LEN_PT) + + shorter_output = bytearray(LEN_PT - 1) + cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) + self.assertRaises(ValueError, cipher.encrypt_and_digest, pt, output=shorter_output) + cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) + self.assertRaises(ValueError, cipher.decrypt_and_verify, ct, tag, output=shorter_output) + + +class SivFSMTests(unittest.TestCase): + + key_256 = get_tag_random("key_256", 32) + nonce_96 = get_tag_random("nonce_96", 12) + data = get_tag_random("data", 128) + + def test_invalid_init_encrypt(self): + # Path INIT->ENCRYPT fails + cipher = AES.new(self.key_256, AES.MODE_SIV, + nonce=self.nonce_96) + self.assertRaises(TypeError, cipher.encrypt, b"xxx") + + def test_invalid_init_decrypt(self): + # Path INIT->DECRYPT fails + cipher = AES.new(self.key_256, AES.MODE_SIV, + nonce=self.nonce_96) + self.assertRaises(TypeError, cipher.decrypt, b"xxx") + + def test_valid_init_update_digest_verify(self): + # No plaintext, fixed authenticated data + # Verify path INIT->UPDATE->DIGEST + cipher = AES.new(self.key_256, AES.MODE_SIV, + nonce=self.nonce_96) + cipher.update(self.data) + mac = cipher.digest() + + # Verify path INIT->UPDATE->VERIFY + cipher = AES.new(self.key_256, AES.MODE_SIV, + nonce=self.nonce_96) + cipher.update(self.data) + cipher.verify(mac) + + def test_valid_init_digest(self): + # Verify path INIT->DIGEST + cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) + cipher.digest() + + def test_valid_init_verify(self): + # Verify path INIT->VERIFY + cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) + mac = cipher.digest() + + cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) + cipher.verify(mac) + + def test_valid_multiple_digest_or_verify(self): + # Multiple calls to digest + cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) + cipher.update(self.data) + first_mac = cipher.digest() + for x in range(4): + self.assertEqual(first_mac, cipher.digest()) + + # Multiple calls to verify + cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) + cipher.update(self.data) + for x in range(5): + cipher.verify(first_mac) + + def test_valid_encrypt_and_digest_decrypt_and_verify(self): + # encrypt_and_digest + cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) + cipher.update(self.data) + ct, mac = cipher.encrypt_and_digest(self.data) + + # decrypt_and_verify + cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) + cipher.update(self.data) + pt = cipher.decrypt_and_verify(ct, mac) + self.assertEqual(self.data, pt) + + def test_invalid_multiple_encrypt_and_digest(self): + cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) + ct, tag = cipher.encrypt_and_digest(self.data) + self.assertRaises(TypeError, cipher.encrypt_and_digest, b'') + + def test_invalid_multiple_decrypt_and_verify(self): + cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) + ct, tag = cipher.encrypt_and_digest(self.data) + + cipher = AES.new(self.key_256, AES.MODE_SIV, nonce=self.nonce_96) + cipher.decrypt_and_verify(ct, tag) + self.assertRaises(TypeError, cipher.decrypt_and_verify, ct, tag) + + +def transform(tv): + new_tv = [[unhexlify(x) for x in tv[0].split("-")]] + new_tv += [ unhexlify(x) for x in tv[1:5]] + if tv[5]: + nonce = unhexlify(tv[5]) + else: + nonce = None + new_tv += [ nonce ] + return new_tv + + +class TestVectors(unittest.TestCase): + """Class exercising the SIV test vectors found in RFC5297""" + + # This is a list of tuples with 5 items: + # + # 1. Header + '|' + plaintext + # 2. Header + '|' + ciphertext + '|' + MAC + # 3. AES-128 key + # 4. Description + # 5. Dictionary of parameters to be passed to AES.new(). + # It must include the nonce. + # + # A "Header" is a dash ('-') separated sequece of components. + # + test_vectors_hex = [ + ( + '101112131415161718191a1b1c1d1e1f2021222324252627', + '112233445566778899aabbccddee', + '40c02b9690c4dc04daef7f6afe5c', + '85632d07c6e8f37f950acd320a2ecc93', + 'fffefdfcfbfaf9f8f7f6f5f4f3f2f1f0f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff', + None + ), + ( + '00112233445566778899aabbccddeeffdeaddadadeaddadaffeeddccbbaa9988' + + '7766554433221100-102030405060708090a0', + '7468697320697320736f6d6520706c61696e7465787420746f20656e63727970' + + '74207573696e67205349562d414553', + 'cb900f2fddbe404326601965c889bf17dba77ceb094fa663b7a3f748ba8af829' + + 'ea64ad544a272e9c485b62a3fd5c0d', + '7bdb6e3b432667eb06f4d14bff2fbd0f', + '7f7e7d7c7b7a79787776757473727170404142434445464748494a4b4c4d4e4f', + '09f911029d74e35bd84156c5635688c0' + ), + ] + + test_vectors = [ transform(tv) for tv in test_vectors_hex ] + + def runTest(self): + for assoc_data, pt, ct, mac, key, nonce in self.test_vectors: + + # Encrypt + cipher = AES.new(key, AES.MODE_SIV, nonce=nonce) + for x in assoc_data: + cipher.update(x) + ct2, mac2 = cipher.encrypt_and_digest(pt) + self.assertEqual(ct, ct2) + self.assertEqual(mac, mac2) + + # Decrypt + cipher = AES.new(key, AES.MODE_SIV, nonce=nonce) + for x in assoc_data: + cipher.update(x) + pt2 = cipher.decrypt_and_verify(ct, mac) + self.assertEqual(pt, pt2) + + +class TestVectorsWycheproof(unittest.TestCase): + + def __init__(self): + unittest.TestCase.__init__(self) + self._id = "None" + + def setUp(self): + self.tv = load_test_vectors_wycheproof(("Cipher", "wycheproof"), + "aes_siv_cmac_test.json", + "Wycheproof AES SIV") + + def shortDescription(self): + return self._id + + def test_encrypt(self, tv): + self._id = "Wycheproof Encrypt AES-SIV Test #" + str(tv.id) + + cipher = AES.new(tv.key, AES.MODE_SIV) + cipher.update(tv.aad) + ct, tag = cipher.encrypt_and_digest(tv.msg) + if tv.valid: + self.assertEqual(tag + ct, tv.ct) + + def test_decrypt(self, tv): + self._id = "Wycheproof Decrypt AES_SIV Test #" + str(tv.id) + + cipher = AES.new(tv.key, AES.MODE_SIV) + cipher.update(tv.aad) + try: + pt = cipher.decrypt_and_verify(tv.ct[16:], tv.ct[:16]) + except ValueError: + assert not tv.valid + else: + assert tv.valid + self.assertEqual(pt, tv.msg) + + def runTest(self): + + for tv in self.tv: + self.test_encrypt(tv) + self.test_decrypt(tv) + + +class TestVectorsWycheproof2(unittest.TestCase): + + def __init__(self): + unittest.TestCase.__init__(self) + self._id = "None" + + def setUp(self): + self.tv = load_test_vectors_wycheproof(("Cipher", "wycheproof"), + "aead_aes_siv_cmac_test.json", + "Wycheproof AEAD SIV") + + def shortDescription(self): + return self._id + + def test_encrypt(self, tv): + self._id = "Wycheproof Encrypt AEAD-AES-SIV Test #" + str(tv.id) + + cipher = AES.new(tv.key, AES.MODE_SIV, nonce=tv.iv) + cipher.update(tv.aad) + ct, tag = cipher.encrypt_and_digest(tv.msg) + if tv.valid: + self.assertEqual(ct, tv.ct) + self.assertEqual(tag, tv.tag) + + def test_decrypt(self, tv): + self._id = "Wycheproof Decrypt AEAD-AES-SIV Test #" + str(tv.id) + + cipher = AES.new(tv.key, AES.MODE_SIV, nonce=tv.iv) + cipher.update(tv.aad) + try: + pt = cipher.decrypt_and_verify(tv.ct, tv.tag) + except ValueError: + assert not tv.valid + else: + assert tv.valid + self.assertEqual(pt, tv.msg) + + def runTest(self): + + for tv in self.tv: + self.test_encrypt(tv) + self.test_decrypt(tv) + + +def get_tests(config={}): + wycheproof_warnings = config.get('wycheproof_warnings') + + tests = [] + tests += list_test_cases(SivTests) + tests += list_test_cases(SivFSMTests) + tests += [ TestVectors() ] + tests += [ TestVectorsWycheproof() ] + tests += [ TestVectorsWycheproof2() ] + return tests + + +if __name__ == '__main__': + suite = lambda: unittest.TestSuite(get_tests()) + unittest.main(defaultTest='suite') diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/test_Salsa20.py b/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/test_Salsa20.py new file mode 100644 index 0000000..a444906 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/test_Salsa20.py @@ -0,0 +1,367 @@ +# -*- coding: utf-8 -*- +# +# SelfTest/Cipher/Salsa20.py: Self-test for the Salsa20 stream cipher +# +# Written in 2013 by Fabrizio Tarizzo +# +# =================================================================== +# The contents of this file are dedicated to the public domain. To +# the extent that dedication to the public domain is not available, +# everyone is granted a worldwide, perpetual, royalty-free, +# non-exclusive license to exercise all rights associated with the +# contents of this file for any purpose whatsoever. +# No rights are reserved. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# =================================================================== + +"""Self-test suite for Cryptodome.Cipher.Salsa20""" + +import unittest + +from Cryptodome.Util.py3compat import bchr + +from Cryptodome.SelfTest.st_common import list_test_cases + +from Cryptodome.Cipher import Salsa20 + +from .common import make_stream_tests + +# This is a list of (plaintext, ciphertext, key[, description[, params]]) +# tuples. +test_data = [ + # Test vectors are taken from + # http://www.ecrypt.eu.org/stream/svn/viewcvs.cgi/ecrypt/trunk/submissions/salsa20/full/verified.test-vectors + ( '00' * 512, + '4dfa5e481da23ea09a31022050859936da52fcee218005164f267cb65f5cfd7f' + + '2b4f97e0ff16924a52df269515110a07f9e460bc65ef95da58f740b7d1dbb0aa' + + 'd64cec189c7eb8c6bbf3d7376c80a481d43e628701f6a27afb9fe23919f24114' + + '8db44f70d7063efcc3dd55a0893a613c3c6fe1c127bd6f59910589293bb6ef9e' + + 'e24819066dee1a64f49b0bbad5988635272b169af861f85df881939f29ada6fd' + + '0241410e8d332ae4798d929434a2630de451ec4e0169694cbaa7ebb121ea6a2b' + + 'da9c1581f429e0a00f7d67e23b730676783b262e8eb43a25f55fb90b3e753aef' + + '8c6713ec66c51881111593ccb3e8cb8f8de124080501eeeb389c4bcb6977cf95' + + '7d5789631eb4554400e1e025935dfa7b3e9039d61bdc58a8697d36815bf1985c' + + 'efdf7ae112e5bb81e37ecf0616ce7147fc08a93a367e08631f23c03b00a8da2f' + + 'aa5024e5c8d30aca43fc2d5082067b21b234bc741d68fb292c6012c3764ccee3' + + '1e364a5403e00cfee338a21a01e7d3cefd5a770ca0ab48c435ea6116435f7ad8' + + '30b217b49f978a68e207ed9f462af7fb195b2115fe8f24f152e4ddc32202d6f2' + + 'b52fafbcfbc202d8a259a611e901d3f62d065eb13f09bbc45cd45119b843efaa' + + 'b375703739daced4dd4059fd71c3c47fc2f9939670fad4a46066adcc6a564578' + + '3308b90ffb72be04a6b147cbe38cc0c3b9267c296a92a7c69873f9f263be9703', + '80000000000000000000000000000000', + '128 bits key, set 1, vector 0', + dict (iv='00'*8)), + + ( '00' * 512, + 'e3be8fdd8beca2e3ea8ef9475b29a6e7003951e1097a5c38d23b7a5fad9f6844' + + 'b22c97559e2723c7cbbd3fe4fc8d9a0744652a83e72a9c461876af4d7ef1a117' + + '8da2b74eef1b6283e7e20166abcae538e9716e4669e2816b6b20c5c356802001' + + 'cc1403a9a117d12a2669f456366d6ebb0f1246f1265150f793cdb4b253e348ae' + + '203d89bc025e802a7e0e00621d70aa36b7e07cb1e7d5b38d5e222b8b0e4b8407' + + '0142b1e29504767d76824850320b5368129fdd74e861b498e3be8d16f2d7d169' + + '57be81f47b17d9ae7c4ff15429a73e10acf250ed3a90a93c711308a74c6216a9' + + 'ed84cd126da7f28e8abf8bb63517e1ca98e712f4fb2e1a6aed9fdc73291faa17' + + '958211c4ba2ebd5838c635edb81f513a91a294e194f1c039aeec657dce40aa7e' + + '7c0af57cacefa40c9f14b71a4b3456a63e162ec7d8d10b8ffb1810d71001b618' + + '2f9f73da53b85405c11f7b2d890fa8ae0c7f2e926d8a98c7ec4e91b65120e988' + + '349631a700c6facec3471cb0413656e75e309456584084d7e12c5b43a41c43ed' + + '9a048abd9b880da65f6a665a20fe7b77cd292fe62cae644b7f7df69f32bdb331' + + '903e6505ce44fdc293920c6a9ec7057e23df7dad298f82ddf4efb7fdc7bfc622' + + '696afcfd0cddcc83c7e77f11a649d79acdc3354e9635ff137e929933a0bd6f53' + + '77efa105a3a4266b7c0d089d08f1e855cc32b15b93784a36e56a76cc64bc8477', + '8000000000000000000000000000000000000000000000000000000000000000', + '256 bits key, set 1, vector 0', + dict (iv='00'*8)), + + ( '00' * 512, + '169060ccb42bea7bee4d8012a02f3635eb7bca12859fa159cd559094b3507db8' + + '01735d1a1300102a9c9415546829cbd2021ba217b39b81d89c55b13d0c603359' + + '3f84159a3c84f4b4f4a0edcd9d38ff261a737909e0b66d68b5cac496f3a5be99' + + 'cb12c321ab711afaab36cc0947955e1a9bb952ed54425e7711279fbc81bb83f5' + + '6e55cea44e6daddb05858a153ea6213b3350c12aa1a83ef2726f09485fa71790' + + 'f9b9f922c7dda1113b1f9d56658ed3402803f511bc1f122601d5e7f0ff036e23' + + '23ef24bb24195b9fd574823cd8a40c29d86bd35c191e2038779ff696c712b6d8' + + '2e7014dbe1ac5d527af076c088c4a8d44317958189f6ef54933a7e0816b5b916' + + 'd8f12ed8afe9422b85e5cc9b8adec9d6cfabe8dbc1082bccc02f5a7266aa074c' + + 'a284e583a35837798cc0e69d4ce937653b8cdd65ce414b89138615ccb165ad19' + + '3c6b9c3d05eef4be921a10ea811fe61d11c6867600188e065daff90b509ec56b' + + 'd41e7e8968c478c78d590c2d2ee24ea009c8f49bc3d81672cfc47895a9e21c9a' + + '471ebf8e294bee5d2de436ac8d052bf31111b345f1da23c3a4d13b9fc5f0900a' + + 'a298f98f538973b8fad40d4d159777de2cfe2a3dead1645ddb49794827dba040' + + 'f70a0ff4ecd155e0f033604693a51e2363880e2ecf98699e7174af7c2c6b0fc6' + + '59ae329599a3949272a37b9b2183a0910922a3f325ae124dcbdd735364055ceb', + '09090909090909090909090909090909', + '128 bits key, set 2, vector 9', + dict (iv='00'*8)), + + ( '00' * 512, + '7041e747ceb22ed7812985465f50333124f971da1c5d6efe5ca201b886f31046' + + 'e757e5c3ec914f60ed1f6bce2819b6810953f12b8ba1199bf82d746a8b8a88f1' + + '142002978ec4c35b95dc2c82990f9e847a0ab45f2ca72625f5190c820f29f3aa' + + 'f5f0b5572b06b70a144f2a240c3b3098d4831fa1ce1459f8d1df226a6a79b0ab' + + '41e91799ef31b5ff3d756c19126b19025858ee70fbd69f2be955cb011c005e31' + + '32b271b378f39b0cb594e95c99ce6ff17735a541891845bbf0450afcb4a850b9' + + '4ee90afb713ae7e01295c74381180a3816d7020d5a396c0d97aaa783eaabb6ec' + + '44d5111157f2212d1b1b8fca7893e8b520cd482418c272ab119b569a2b9598eb' + + '355624d12e79adab81153b58cd22eaf1b2a32395dedc4a1c66f4d274070b9800' + + 'ea95766f0245a8295f8aadb36ddbbdfa936417c8dbc6235d19494036964d3e70' + + 'b125b0f800c3d53881d9d11e7970f827c2f9556935cd29e927b0aceb8cae5fd4' + + '0fd88a8854010a33db94c96c98735858f1c5df6844f864feaca8f41539313e7f' + + '3c0610214912cd5e6362197646207e2d64cd5b26c9dfe0822629dcbeb16662e8' + + '9ff5bf5cf2e499138a5e27bd5027329d0e68ddf53103e9e409523662e27f61f6' + + '5cf38c1232023e6a6ef66c315bcb2a4328642faabb7ca1e889e039e7c444b34b' + + 'b3443f596ac730f3df3dfcdb343c307c80f76e43e8898c5e8f43dc3bb280add0', + '0909090909090909090909090909090909090909090909090909090909090909', + '256 bits key, set 2, vector 9', + dict (iv='00'*8)), + + ( '00' * 1024, + '71daee5142d0728b41b6597933ebf467e43279e30978677078941602629cbf68' + + 'b73d6bd2c95f118d2b3e6ec955dabb6dc61c4143bc9a9b32b99dbe6866166dc0' + + '8631b7d6553050303d7252c264d3a90d26c853634813e09ad7545a6ce7e84a5d' + + 'fc75ec43431207d5319970b0faadb0e1510625bb54372c8515e28e2accf0a993' + + '0ad15f431874923d2a59e20d9f2a5367dba6051564f150287debb1db536ff9b0' + + '9ad981f25e5010d85d76ee0c305f755b25e6f09341e0812f95c94f42eead346e' + + '81f39c58c5faa2c88953dc0cac90469db2063cb5cdb22c9eae22afbf0506fca4' + + '1dc710b846fbdfe3c46883dd118f3a5e8b11b6afd9e71680d8666557301a2daa' + + 'fb9496c559784d35a035360885f9b17bd7191977deea932b981ebdb29057ae3c' + + '92cfeff5e6c5d0cb62f209ce342d4e35c69646ccd14e53350e488bb310a32f8b' + + '0248e70acc5b473df537ced3f81a014d4083932bedd62ed0e447b6766cd2604b' + + '706e9b346c4468beb46a34ecf1610ebd38331d52bf33346afec15eefb2a7699e' + + '8759db5a1f636a48a039688e39de34d995df9f27ed9edc8dd795e39e53d9d925' + + 'b278010565ff665269042f05096d94da3433d957ec13d2fd82a0066283d0d1ee' + + 'b81bf0ef133b7fd90248b8ffb499b2414cd4fa003093ff0864575a43749bf596' + + '02f26c717fa96b1d057697db08ebc3fa664a016a67dcef8807577cc3a09385d3' + + 'f4dc79b34364bb3b166ce65fe1dd28e3950fe6fa81063f7b16ce1c0e6daac1f8' + + '188455b77752045e863c9b256ad92bc6e2d08314c5bba191c274f42dfbb3d652' + + 'bb771956555e880f84cd8b827a4c5a52f3a099fa0259bd4aac3efd541f191170' + + '4412d6e85fbcc628b335875b9fef24807f6e1bc66c3186159e1e7f5a13913e02' + + 'd241ce2efdbcaa275039fb14eac5923d17ffbc7f1abd3b45e92127575bfbabf9' + + '3a257ebef0aa1437b326e41b585af572f7239c33b32981a1577a4f629b027e1e' + + 'b49d58cc497e944d79cef44357c2bf25442ab779651e991147bf79d6fd3a8868' + + '0cd3b1748e07fd10d78aceef6db8a5e563570d40127f754146c34a440f2a991a' + + '23fa39d365141f255041f2135c5cba4373452c114da1801bacca38610e3a6524' + + '2b822d32de4ab5a7d3cf9b61b37493c863bd12e2cae10530cddcda2cb7a5436b' + + 'ef8988d4d24e8cdc31b2d2a3586340bc5141f8f6632d0dd543bfed81eb471ba1' + + 'f3dc2225a15ffddcc03eb48f44e27e2aa390598adf83f15c6608a5f18d4dfcf0' + + 'f547d467a4d70b281c83a595d7660d0b62de78b9cca023cca89d7b1f83484638' + + '0e228c25f049184a612ef5bb3d37454e6cfa5b10dceda619d898a699b3c8981a' + + '173407844bb89b4287bf57dd6600c79e352c681d74b03fa7ea0d7bf6ad69f8a6' + + '8ecb001963bd2dd8a2baa0083ec09751cd9742402ad716be16d5c052304cfca1', + '0F62B5085BAE0154A7FA4DA0F34699EC', + '128 bits key, Set 6, vector# 3', + dict (iv='288FF65DC42B92F9')), + + ( '00' * 1024, + '5e5e71f90199340304abb22a37b6625bf883fb89ce3b21f54a10b81066ef87da' + + '30b77699aa7379da595c77dd59542da208e5954f89e40eb7aa80a84a6176663f' + + 'd910cde567cf1ff60f7040548d8f376bfd1f44c4774aac37410ede7d5c3463fc' + + '4508a603201d8495ad257894e5eb1914b53e8da5e4bf2bc83ac87ce55cc67df7' + + '093d9853d2a83a9c8be969175df7c807a17156df768445dd0874a9271c6537f5' + + 'ce0466473582375f067fa4fcdaf65dbc0139cd75e8c21a482f28c0fb8c3d9f94' + + '22606cc8e88fe28fe73ec3cb10ff0e8cc5f2a49e540f007265c65b7130bfdb98' + + '795b1df9522da46e48b30e55d9f0d787955ece720205b29c85f3ad9be33b4459' + + '7d21b54d06c9a60b04b8e640c64e566e51566730e86cf128ab14174f91bd8981' + + 'a6fb00fe587bbd6c38b5a1dfdb04ea7e61536fd229f957aa9b070ca931358e85' + + '11b92c53c523cb54828fb1513c5636fa9a0645b4a3c922c0db94986d92f314ff' + + '7852c03b231e4dceea5dd8cced621869cff818daf3c270ff3c8be2e5c74be767' + + 'a4e1fdf3327a934fe31e46df5a74ae2021cee021d958c4f615263d99a5ddae7f' + + 'eab45e6eccbafefe4761c57750847b7e75ee2e2f14333c0779ce4678f47b1e1b' + + '760a03a5f17d6e91d4b42313b3f1077ee270e432fe04917ed1fc8babebf7c941' + + '42b80dfb44a28a2a3e59093027606f6860bfb8c2e5897078cfccda7314c70035' + + 'f137de6f05daa035891d5f6f76e1df0fce1112a2ff0ac2bd3534b5d1bf4c7165' + + 'fb40a1b6eacb7f295711c4907ae457514a7010f3a342b4427593d61ba993bc59' + + '8bd09c56b9ee53aac5dd861fa4b4bb53888952a4aa9d8ca8671582de716270e1' + + '97375b3ee49e51fa2bf4ef32015dd9a764d966aa2ae541592d0aa650849e99ca' + + '5c6c39beebf516457cc32fe4c105bff314a12f1ec94bdf4d626f5d9b1cbbde42' + + 'e5733f0885765ba29e2e82c829d312f5fc7e180679ac84826c08d0a644b326d0' + + '44da0fdcc75fa53cfe4ced0437fa4df5a7ecbca8b4cb7c4a9ecf9a60d00a56eb' + + '81da52adc21f508dbb60a9503a3cc94a896616d86020d5b0e5c637329b6d396a' + + '41a21ba2c4a9493cf33fa2d4f10f77d5b12fdad7e478ccfe79b74851fc96a7ca' + + '6320c5efd561a222c0ab0fb44bbda0e42149611d2262bb7d1719150fa798718a' + + '0eec63ee297cad459869c8b0f06c4e2b56cbac03cd2605b2a924efedf85ec8f1' + + '9b0b6c90e7cbd933223ffeb1b3a3f9677657905829294c4c70acdb8b0891b47d' + + '0875d0cd6c0f4efe2917fc44b581ef0d1e4280197065d07da34ab33283364552' + + 'efad0bd9257b059acdd0a6f246812feb69e7e76065f27dbc2eee94da9cc41835' + + 'bf826e36e5cebe5d4d6a37a6a666246290ce51a0c082718ab0ec855668db1add' + + 'a658e5f257e0db39384d02e6145c4c00eaa079098f6d820d872de711b6ed08cf', + '0F62B5085BAE0154A7FA4DA0F34699EC3F92E5388BDE3184D72A7DD02376C91C', + '256 bits key, Set 6, vector# 3', + dict (iv='288FF65DC42B92F9')), + +] + + +class KeyLength(unittest.TestCase): + + def runTest(self): + + nonce = bchr(0) * 8 + for key_length in (15, 30, 33): + key = bchr(1) * key_length + self.assertRaises(ValueError, Salsa20.new, key, nonce) + + +class NonceTests(unittest.TestCase): + + def test_invalid_nonce_length(self): + key = bchr(1) * 16 + self.assertRaises(ValueError, Salsa20.new, key, bchr(0) * 7) + self.assertRaises(ValueError, Salsa20.new, key, bchr(0) * 9) + + def test_default_nonce(self): + + cipher1 = Salsa20.new(bchr(1) * 16) + cipher2 = Salsa20.new(bchr(1) * 16) + self.assertEqual(len(cipher1.nonce), 8) + self.assertNotEqual(cipher1.nonce, cipher2.nonce) + + +class ByteArrayTest(unittest.TestCase): + """Verify we can encrypt or decrypt bytearrays""" + + def runTest(self): + + data = b"0123" + key = b"9" * 32 + nonce = b"t" * 8 + + # Encryption + data_ba = bytearray(data) + key_ba = bytearray(key) + nonce_ba = bytearray(nonce) + + cipher1 = Salsa20.new(key=key, nonce=nonce) + ct = cipher1.encrypt(data) + + cipher2 = Salsa20.new(key=key_ba, nonce=nonce_ba) + key_ba[:1] = b'\xFF' + nonce_ba[:1] = b'\xFF' + ct_test = cipher2.encrypt(data_ba) + + self.assertEqual(ct, ct_test) + self.assertEqual(cipher1.nonce, cipher2.nonce) + + # Decryption + key_ba = bytearray(key) + nonce_ba = bytearray(nonce) + ct_ba = bytearray(ct) + + cipher3 = Salsa20.new(key=key_ba, nonce=nonce_ba) + key_ba[:1] = b'\xFF' + nonce_ba[:1] = b'\xFF' + pt_test = cipher3.decrypt(ct_ba) + + self.assertEqual(data, pt_test) + + +class MemoryviewTest(unittest.TestCase): + """Verify we can encrypt or decrypt bytearrays""" + + def runTest(self): + + data = b"0123" + key = b"9" * 32 + nonce = b"t" * 8 + + # Encryption + data_mv = memoryview(bytearray(data)) + key_mv = memoryview(bytearray(key)) + nonce_mv = memoryview(bytearray(nonce)) + + cipher1 = Salsa20.new(key=key, nonce=nonce) + ct = cipher1.encrypt(data) + + cipher2 = Salsa20.new(key=key_mv, nonce=nonce_mv) + key_mv[:1] = b'\xFF' + nonce_mv[:1] = b'\xFF' + ct_test = cipher2.encrypt(data_mv) + + self.assertEqual(ct, ct_test) + self.assertEqual(cipher1.nonce, cipher2.nonce) + + # Decryption + key_mv = memoryview(bytearray(key)) + nonce_mv = memoryview(bytearray(nonce)) + ct_mv = memoryview(bytearray(ct)) + + cipher3 = Salsa20.new(key=key_mv, nonce=nonce_mv) + key_mv[:1] = b'\xFF' + nonce_mv[:1] = b'\xFF' + pt_test = cipher3.decrypt(ct_mv) + + self.assertEqual(data, pt_test) + + +class TestOutput(unittest.TestCase): + + def runTest(self): + # Encrypt/Decrypt data and test output parameter + + key = b'4' * 32 + nonce = b'5' * 8 + cipher = Salsa20.new(key=key, nonce=nonce) + + pt = b'5' * 300 + ct = cipher.encrypt(pt) + + output = bytearray(len(pt)) + cipher = Salsa20.new(key=key, nonce=nonce) + res = cipher.encrypt(pt, output=output) + self.assertEqual(ct, output) + self.assertEqual(res, None) + + cipher = Salsa20.new(key=key, nonce=nonce) + res = cipher.decrypt(ct, output=output) + self.assertEqual(pt, output) + self.assertEqual(res, None) + + output = memoryview(bytearray(len(pt))) + cipher = Salsa20.new(key=key, nonce=nonce) + cipher.encrypt(pt, output=output) + self.assertEqual(ct, output) + + cipher = Salsa20.new(key=key, nonce=nonce) + cipher.decrypt(ct, output=output) + self.assertEqual(pt, output) + + cipher = Salsa20.new(key=key, nonce=nonce) + self.assertRaises(TypeError, cipher.encrypt, pt, output=b'0'*len(pt)) + + cipher = Salsa20.new(key=key, nonce=nonce) + self.assertRaises(TypeError, cipher.decrypt, ct, output=b'0'*len(ct)) + + shorter_output = bytearray(len(pt) - 1) + + cipher = Salsa20.new(key=key, nonce=nonce) + self.assertRaises(ValueError, cipher.encrypt, pt, output=shorter_output) + + cipher = Salsa20.new(key=key, nonce=nonce) + self.assertRaises(ValueError, cipher.decrypt, ct, output=shorter_output) + + +def get_tests(config={}): + tests = make_stream_tests(Salsa20, "Salsa20", test_data) + tests.append(KeyLength()) + tests += list_test_cases(NonceTests) + tests.append(ByteArrayTest()) + tests.append(MemoryviewTest()) + tests.append(TestOutput()) + + return tests + + +if __name__ == '__main__': + import unittest + suite = lambda: unittest.TestSuite(get_tests()) + unittest.main(defaultTest='suite') + +# vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/test_pkcs1_15.py b/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/test_pkcs1_15.py new file mode 100644 index 0000000..12c09dd --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/test_pkcs1_15.py @@ -0,0 +1,283 @@ +# -*- coding: utf-8 -*- +# +# SelfTest/Cipher/test_pkcs1_15.py: Self-test for PKCS#1 v1.5 encryption +# +# =================================================================== +# The contents of this file are dedicated to the public domain. To +# the extent that dedication to the public domain is not available, +# everyone is granted a worldwide, perpetual, royalty-free, +# non-exclusive license to exercise all rights associated with the +# contents of this file for any purpose whatsoever. +# No rights are reserved. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# =================================================================== + +from __future__ import print_function + +import unittest + +from Cryptodome.PublicKey import RSA +from Cryptodome.SelfTest.st_common import list_test_cases, a2b_hex +from Cryptodome import Random +from Cryptodome.Cipher import PKCS1_v1_5 as PKCS +from Cryptodome.Util.py3compat import b +from Cryptodome.Util.number import bytes_to_long, long_to_bytes +from Cryptodome.SelfTest.loader import load_test_vectors_wycheproof + + +def rws(t): + """Remove white spaces, tabs, and new lines from a string""" + for c in ['\n', '\t', ' ']: + t = t.replace(c, '') + return t + + +def t2b(t): + """Convert a text string with bytes in hex form to a byte string""" + clean = b(rws(t)) + if len(clean) % 2 == 1: + raise ValueError("Even number of characters expected") + return a2b_hex(clean) + + +class PKCS1_15_Tests(unittest.TestCase): + + def setUp(self): + self.rng = Random.new().read + self.key1024 = RSA.generate(1024, self.rng) + + # List of tuples with test data for PKCS#1 v1.5. + # Each tuple is made up by: + # Item #0: dictionary with RSA key component, or key to import + # Item #1: plaintext + # Item #2: ciphertext + # Item #3: random data + + _testData = ( + + # + # Generated with openssl 0.9.8o + # + ( + # Private key + '''-----BEGIN RSA PRIVATE KEY----- +MIICXAIBAAKBgQDAiAnvIAOvqVwJTaYzsKnefZftgtXGE2hPJppGsWl78yz9jeXY +W/FxX/gTPURArNhdnhP6n3p2ZaDIBrO2zizbgIXs0IsljTTcr4vnI8fMXzyNUOjA +zP3nzMqZDZK6757XQAobOssMkBFqRWwilT/3DsBhRpl3iMUhF+wvpTSHewIDAQAB +AoGAC4HV/inOrpgTvSab8Wj0riyZgQOZ3U3ZpSlsfR8ra9Ib9Uee3jCYnKscu6Gk +y6zI/cdt8EPJ4PuwAWSNJzbpbVaDvUq25OD+CX8/uRT08yBS4J8TzBitZJTD4lS7 +atdTnKT0Wmwk+u8tDbhvMKwnUHdJLcuIsycts9rwJVapUtkCQQDvDpx2JMun0YKG +uUttjmL8oJ3U0m3ZvMdVwBecA0eebZb1l2J5PvI3EJD97eKe91Nsw8T3lwpoN40k +IocSVDklAkEAzi1HLHE6EzVPOe5+Y0kGvrIYRRhncOb72vCvBZvD6wLZpQgqo6c4 +d3XHFBBQWA6xcvQb5w+VVEJZzw64y25sHwJBAMYReRl6SzL0qA0wIYrYWrOt8JeQ +8mthulcWHXmqTgC6FEXP9Es5GD7/fuKl4wqLKZgIbH4nqvvGay7xXLCXD/ECQH9a +1JYNMtRen5unSAbIOxRcKkWz92F0LKpm9ZW/S9vFHO+mBcClMGoKJHiuQxLBsLbT +NtEZfSJZAeS2sUtn3/0CQDb2M2zNBTF8LlM0nxmh0k9VGm5TVIyBEMcipmvOgqIs +HKukWBcq9f/UOmS0oEhai/6g+Uf7VHJdWaeO5LzuvwU= +-----END RSA PRIVATE KEY-----''', + # Plaintext + '''THIS IS PLAINTEXT\x0A''', + # Ciphertext + '''3f dc fd 3c cd 5c 9b 12 af 65 32 e3 f7 d0 da 36 + 8f 8f d9 e3 13 1c 7f c8 b3 f9 c1 08 e4 eb 79 9c + 91 89 1f 96 3b 94 77 61 99 a4 b1 ee 5d e6 17 c9 + 5d 0a b5 63 52 0a eb 00 45 38 2a fb b0 71 3d 11 + f7 a1 9e a7 69 b3 af 61 c0 bb 04 5b 5d 4b 27 44 + 1f 5b 97 89 ba 6a 08 95 ee 4f a2 eb 56 64 e5 0f + da 7c f9 9a 61 61 06 62 ed a0 bc 5f aa 6c 31 78 + 70 28 1a bb 98 3c e3 6a 60 3c d1 0b 0f 5a f4 75''', + # Random data + '''eb d7 7d 86 a4 35 23 a3 54 7e 02 0b 42 1d + 61 6c af 67 b8 4e 17 56 80 66 36 04 64 34 26 8a + 47 dd 44 b3 1a b2 17 60 f4 91 2e e2 b5 95 64 cc + f9 da c8 70 94 54 86 4c ef 5b 08 7d 18 c4 ab 8d + 04 06 33 8f ca 15 5f 52 60 8a a1 0c f5 08 b5 4c + bb 99 b8 94 25 04 9c e6 01 75 e6 f9 63 7a 65 61 + 13 8a a7 47 77 81 ae 0d b8 2c 4d 50 a5''' + ), + ) + + def testEncrypt1(self): + for test in self._testData: + # Build the key + key = RSA.importKey(test[0]) + # RNG that takes its random numbers from a pool given + # at initialization + class randGen: + def __init__(self, data): + self.data = data + self.idx = 0 + def __call__(self, N): + r = self.data[self.idx:self.idx+N] + self.idx += N + return r + # The real test + cipher = PKCS.new(key, randfunc=randGen(t2b(test[3]))) + ct = cipher.encrypt(b(test[1])) + self.assertEqual(ct, t2b(test[2])) + + def testEncrypt2(self): + # Verify that encryption fail if plaintext is too long + pt = '\x00'*(128-11+1) + cipher = PKCS.new(self.key1024) + self.assertRaises(ValueError, cipher.encrypt, pt) + + def testVerify1(self): + for test in self._testData: + key = RSA.importKey(test[0]) + expected_pt = b(test[1]) + ct = t2b(test[2]) + cipher = PKCS.new(key) + + # The real test + pt = cipher.decrypt(ct, None) + self.assertEqual(pt, expected_pt) + + pt = cipher.decrypt(ct, b'\xFF' * len(expected_pt)) + self.assertEqual(pt, expected_pt) + + def testVerify2(self): + # Verify that decryption fails if ciphertext is not as long as + # RSA modulus + cipher = PKCS.new(self.key1024) + self.assertRaises(ValueError, cipher.decrypt, '\x00'*127, "---") + self.assertRaises(ValueError, cipher.decrypt, '\x00'*129, "---") + + # Verify that decryption fails if there are less then 8 non-zero padding + # bytes + pt = b('\x00\x02' + '\xFF'*7 + '\x00' + '\x45'*118) + pt_int = bytes_to_long(pt) + ct_int = self.key1024._encrypt(pt_int) + ct = long_to_bytes(ct_int, 128) + self.assertEqual(b"---", cipher.decrypt(ct, b"---")) + + def testEncryptVerify1(self): + # Encrypt/Verify messages of length [0..RSAlen-11] + # and therefore padding [8..117] + for pt_len in range(0, 128 - 11 + 1): + pt = self.rng(pt_len) + cipher = PKCS.new(self.key1024) + ct = cipher.encrypt(pt) + pt2 = cipher.decrypt(ct, b'\xAA' * pt_len) + self.assertEqual(pt, pt2) + + def test_encrypt_verify_exp_pt_len(self): + + cipher = PKCS.new(self.key1024) + pt = b'5' * 16 + ct = cipher.encrypt(pt) + sentinel = b'\xAA' * 16 + + pt_A = cipher.decrypt(ct, sentinel, 16) + self.assertEqual(pt, pt_A) + + pt_B = cipher.decrypt(ct, sentinel, 15) + self.assertEqual(sentinel, pt_B) + + pt_C = cipher.decrypt(ct, sentinel, 17) + self.assertEqual(sentinel, pt_C) + + def testByteArray(self): + pt = b"XER" + cipher = PKCS.new(self.key1024) + ct = cipher.encrypt(bytearray(pt)) + pt2 = cipher.decrypt(bytearray(ct), '\xFF' * len(pt)) + self.assertEqual(pt, pt2) + + def testMemoryview(self): + pt = b"XER" + cipher = PKCS.new(self.key1024) + ct = cipher.encrypt(memoryview(bytearray(pt))) + pt2 = cipher.decrypt(memoryview(bytearray(ct)), b'\xFF' * len(pt)) + self.assertEqual(pt, pt2) + + def test_return_type(self): + pt = b"XYZ" + cipher = PKCS.new(self.key1024) + ct = cipher.encrypt(pt) + self.assertTrue(isinstance(ct, bytes)) + pt2 = cipher.decrypt(ct, b'\xAA' * 3) + self.assertTrue(isinstance(pt2, bytes)) + + +class TestVectorsWycheproof(unittest.TestCase): + + def __init__(self, wycheproof_warnings, skip_slow_tests): + unittest.TestCase.__init__(self) + self._wycheproof_warnings = wycheproof_warnings + self._skip_slow_tests = skip_slow_tests + self._id = "None" + + def load_tests(self, filename): + + def filter_rsa(group): + return RSA.import_key(group['privateKeyPem']) + + result = load_test_vectors_wycheproof(("Cipher", "wycheproof"), + filename, + "Wycheproof PKCS#1v1.5 (%s)" % filename, + group_tag={'rsa_key': filter_rsa} + ) + return result + + def setUp(self): + self.tv = [] + self.tv.extend(self.load_tests("rsa_pkcs1_2048_test.json")) + if not self._skip_slow_tests: + self.tv.extend(self.load_tests("rsa_pkcs1_3072_test.json")) + self.tv.extend(self.load_tests("rsa_pkcs1_4096_test.json")) + + def shortDescription(self): + return self._id + + def warn(self, tv): + if tv.warning and self._wycheproof_warnings: + import warnings + warnings.warn("Wycheproof warning: %s (%s)" % (self._id, tv.comment)) + + def test_decrypt(self, tv): + self._id = "Wycheproof Decrypt PKCS#1v1.5 Test #%s" % tv.id + sentinel = b'\xAA' * max(3, len(tv.msg)) + cipher = PKCS.new(tv.rsa_key) + try: + pt = cipher.decrypt(tv.ct, sentinel=sentinel) + except ValueError: + assert not tv.valid + else: + if pt == sentinel: + assert not tv.valid + else: + assert tv.valid + self.assertEqual(pt, tv.msg) + self.warn(tv) + + def runTest(self): + + for tv in self.tv: + self.test_decrypt(tv) + + +def get_tests(config={}): + skip_slow_tests = not config.get('slow_tests') + wycheproof_warnings = config.get('wycheproof_warnings') + + tests = [] + tests += list_test_cases(PKCS1_15_Tests) + tests += [TestVectorsWycheproof(wycheproof_warnings, skip_slow_tests)] + return tests + + +if __name__ == '__main__': + def suite(): + return unittest.TestSuite(get_tests()) + unittest.main(defaultTest='suite') + +# vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/test_pkcs1_oaep.py b/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/test_pkcs1_oaep.py new file mode 100644 index 0000000..aa00c9c --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/SelfTest/Cipher/test_pkcs1_oaep.py @@ -0,0 +1,506 @@ +# -*- coding: utf-8 -*- +# +# SelfTest/Cipher/test_pkcs1_oaep.py: Self-test for PKCS#1 OAEP encryption +# +# =================================================================== +# The contents of this file are dedicated to the public domain. To +# the extent that dedication to the public domain is not available, +# everyone is granted a worldwide, perpetual, royalty-free, +# non-exclusive license to exercise all rights associated with the +# contents of this file for any purpose whatsoever. +# No rights are reserved. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# =================================================================== + +import unittest + +from Cryptodome.SelfTest.st_common import list_test_cases, a2b_hex +from Cryptodome.SelfTest.loader import load_test_vectors_wycheproof + +from Cryptodome.PublicKey import RSA +from Cryptodome.Cipher import PKCS1_OAEP as PKCS +from Cryptodome.Hash import MD2, MD5, SHA1, SHA256, RIPEMD160, SHA224, SHA384, SHA512 +from Cryptodome import Random +from Cryptodome.Signature.pss import MGF1 + +from Cryptodome.Util.py3compat import b, bchr + + +def rws(t): + """Remove white spaces, tabs, and new lines from a string""" + for c in ['\n', '\t', ' ']: + t = t.replace(c, '') + return t + + +def t2b(t): + """Convert a text string with bytes in hex form to a byte string""" + clean = rws(t) + if len(clean) % 2 == 1: + raise ValueError("Even number of characters expected") + return a2b_hex(clean) + + +class PKCS1_OAEP_Tests(unittest.TestCase): + + def setUp(self): + self.rng = Random.new().read + self.key1024 = RSA.generate(1024, self.rng) + + # List of tuples with test data for PKCS#1 OAEP + # Each tuple is made up by: + # Item #0: dictionary with RSA key component + # Item #1: plaintext + # Item #2: ciphertext + # Item #3: random data (=seed) + # Item #4: hash object + + _testData = ( + + # + # From in oaep-int.txt to be found in + # ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1-vec.zip + # + ( + # Private key + { + 'n':'''bb f8 2f 09 06 82 ce 9c 23 38 ac 2b 9d a8 71 f7 + 36 8d 07 ee d4 10 43 a4 40 d6 b6 f0 74 54 f5 1f + b8 df ba af 03 5c 02 ab 61 ea 48 ce eb 6f cd 48 + 76 ed 52 0d 60 e1 ec 46 19 71 9d 8a 5b 8b 80 7f + af b8 e0 a3 df c7 37 72 3e e6 b4 b7 d9 3a 25 84 + ee 6a 64 9d 06 09 53 74 88 34 b2 45 45 98 39 4e + e0 aa b1 2d 7b 61 a5 1f 52 7a 9a 41 f6 c1 68 7f + e2 53 72 98 ca 2a 8f 59 46 f8 e5 fd 09 1d bd cb''', + # Public key + 'e':'11', + # In the test vector, only p and q were given... + # d is computed offline as e^{-1} mod (p-1)(q-1) + 'd':'''a5dafc5341faf289c4b988db30c1cdf83f31251e0 + 668b42784813801579641b29410b3c7998d6bc465745e5c3 + 92669d6870da2c082a939e37fdcb82ec93edac97ff3ad595 + 0accfbc111c76f1a9529444e56aaf68c56c092cd38dc3bef + 5d20a939926ed4f74a13eddfbe1a1cecc4894af9428c2b7b + 8883fe4463a4bc85b1cb3c1''' + } + , + # Plaintext + '''d4 36 e9 95 69 fd 32 a7 c8 a0 5b bc 90 d3 2c 49''', + # Ciphertext + '''12 53 e0 4d c0 a5 39 7b b4 4a 7a b8 7e 9b f2 a0 + 39 a3 3d 1e 99 6f c8 2a 94 cc d3 00 74 c9 5d f7 + 63 72 20 17 06 9e 52 68 da 5d 1c 0b 4f 87 2c f6 + 53 c1 1d f8 23 14 a6 79 68 df ea e2 8d ef 04 bb + 6d 84 b1 c3 1d 65 4a 19 70 e5 78 3b d6 eb 96 a0 + 24 c2 ca 2f 4a 90 fe 9f 2e f5 c9 c1 40 e5 bb 48 + da 95 36 ad 87 00 c8 4f c9 13 0a de a7 4e 55 8d + 51 a7 4d df 85 d8 b5 0d e9 68 38 d6 06 3e 09 55''', + # Random + '''aa fd 12 f6 59 ca e6 34 89 b4 79 e5 07 6d de c2 + f0 6c b5 8f''', + # Hash + SHA1, + ), + + # + # From in oaep-vect.txt to be found in Example 1.1 + # ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1-vec.zip + # + ( + # Private key + { + 'n':'''a8 b3 b2 84 af 8e b5 0b 38 70 34 a8 60 f1 46 c4 + 91 9f 31 87 63 cd 6c 55 98 c8 ae 48 11 a1 e0 ab + c4 c7 e0 b0 82 d6 93 a5 e7 fc ed 67 5c f4 66 85 + 12 77 2c 0c bc 64 a7 42 c6 c6 30 f5 33 c8 cc 72 + f6 2a e8 33 c4 0b f2 58 42 e9 84 bb 78 bd bf 97 + c0 10 7d 55 bd b6 62 f5 c4 e0 fa b9 84 5c b5 14 + 8e f7 39 2d d3 aa ff 93 ae 1e 6b 66 7b b3 d4 24 + 76 16 d4 f5 ba 10 d4 cf d2 26 de 88 d3 9f 16 fb''', + 'e':'''01 00 01''', + 'd':'''53 33 9c fd b7 9f c8 46 6a 65 5c 73 16 ac a8 5c + 55 fd 8f 6d d8 98 fd af 11 95 17 ef 4f 52 e8 fd + 8e 25 8d f9 3f ee 18 0f a0 e4 ab 29 69 3c d8 3b + 15 2a 55 3d 4a c4 d1 81 2b 8b 9f a5 af 0e 7f 55 + fe 73 04 df 41 57 09 26 f3 31 1f 15 c4 d6 5a 73 + 2c 48 31 16 ee 3d 3d 2d 0a f3 54 9a d9 bf 7c bf + b7 8a d8 84 f8 4d 5b eb 04 72 4d c7 36 9b 31 de + f3 7d 0c f5 39 e9 cf cd d3 de 65 37 29 ea d5 d1 ''' + } + , + # Plaintext + '''66 28 19 4e 12 07 3d b0 3b a9 4c da 9e f9 53 23 + 97 d5 0d ba 79 b9 87 00 4a fe fe 34''', + # Ciphertext + '''35 4f e6 7b 4a 12 6d 5d 35 fe 36 c7 77 79 1a 3f + 7b a1 3d ef 48 4e 2d 39 08 af f7 22 fa d4 68 fb + 21 69 6d e9 5d 0b e9 11 c2 d3 17 4f 8a fc c2 01 + 03 5f 7b 6d 8e 69 40 2d e5 45 16 18 c2 1a 53 5f + a9 d7 bf c5 b8 dd 9f c2 43 f8 cf 92 7d b3 13 22 + d6 e8 81 ea a9 1a 99 61 70 e6 57 a0 5a 26 64 26 + d9 8c 88 00 3f 84 77 c1 22 70 94 a0 d9 fa 1e 8c + 40 24 30 9c e1 ec cc b5 21 00 35 d4 7a c7 2e 8a''', + # Random + '''18 b7 76 ea 21 06 9d 69 77 6a 33 e9 6b ad 48 e1 + dd a0 a5 ef''', + SHA1 + ), + + # + # From in oaep-vect.txt to be found in Example 2.1 + # ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1-vec.zip + # + ( + # Private key + { + 'n':'''01 94 7c 7f ce 90 42 5f 47 27 9e 70 85 1f 25 d5 + e6 23 16 fe 8a 1d f1 93 71 e3 e6 28 e2 60 54 3e + 49 01 ef 60 81 f6 8c 0b 81 41 19 0d 2a e8 da ba + 7d 12 50 ec 6d b6 36 e9 44 ec 37 22 87 7c 7c 1d + 0a 67 f1 4b 16 94 c5 f0 37 94 51 a4 3e 49 a3 2d + de 83 67 0b 73 da 91 a1 c9 9b c2 3b 43 6a 60 05 + 5c 61 0f 0b af 99 c1 a0 79 56 5b 95 a3 f1 52 66 + 32 d1 d4 da 60 f2 0e da 25 e6 53 c4 f0 02 76 6f + 45''', + 'e':'''01 00 01''', + 'd':'''08 23 f2 0f ad b5 da 89 08 8a 9d 00 89 3e 21 fa + 4a 1b 11 fb c9 3c 64 a3 be 0b aa ea 97 fb 3b 93 + c3 ff 71 37 04 c1 9c 96 3c 1d 10 7a ae 99 05 47 + 39 f7 9e 02 e1 86 de 86 f8 7a 6d de fe a6 d8 cc + d1 d3 c8 1a 47 bf a7 25 5b e2 06 01 a4 a4 b2 f0 + 8a 16 7b 5e 27 9d 71 5b 1b 45 5b dd 7e ab 24 59 + 41 d9 76 8b 9a ce fb 3c cd a5 95 2d a3 ce e7 25 + 25 b4 50 16 63 a8 ee 15 c9 e9 92 d9 24 62 fe 39''' + }, + # Plaintext + '''8f f0 0c aa 60 5c 70 28 30 63 4d 9a 6c 3d 42 c6 + 52 b5 8c f1 d9 2f ec 57 0b ee e7''', + # Ciphertext + '''01 81 af 89 22 b9 fc b4 d7 9d 92 eb e1 98 15 99 + 2f c0 c1 43 9d 8b cd 49 13 98 a0 f4 ad 3a 32 9a + 5b d9 38 55 60 db 53 26 83 c8 b7 da 04 e4 b1 2a + ed 6a ac df 47 1c 34 c9 cd a8 91 ad dc c2 df 34 + 56 65 3a a6 38 2e 9a e5 9b 54 45 52 57 eb 09 9d + 56 2b be 10 45 3f 2b 6d 13 c5 9c 02 e1 0f 1f 8a + bb 5d a0 d0 57 09 32 da cf 2d 09 01 db 72 9d 0f + ef cc 05 4e 70 96 8e a5 40 c8 1b 04 bc ae fe 72 + 0e''', + # Random + '''8c 40 7b 5e c2 89 9e 50 99 c5 3e 8c e7 93 bf 94 + e7 1b 17 82''', + SHA1 + ), + + # + # From in oaep-vect.txt to be found in Example 10.1 + # ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1-vec.zip + # + ( + # Private key + { + 'n':'''ae 45 ed 56 01 ce c6 b8 cc 05 f8 03 93 5c 67 4d + db e0 d7 5c 4c 09 fd 79 51 fc 6b 0c ae c3 13 a8 + df 39 97 0c 51 8b ff ba 5e d6 8f 3f 0d 7f 22 a4 + 02 9d 41 3f 1a e0 7e 4e be 9e 41 77 ce 23 e7 f5 + 40 4b 56 9e 4e e1 bd cf 3c 1f b0 3e f1 13 80 2d + 4f 85 5e b9 b5 13 4b 5a 7c 80 85 ad ca e6 fa 2f + a1 41 7e c3 76 3b e1 71 b0 c6 2b 76 0e de 23 c1 + 2a d9 2b 98 08 84 c6 41 f5 a8 fa c2 6b da d4 a0 + 33 81 a2 2f e1 b7 54 88 50 94 c8 25 06 d4 01 9a + 53 5a 28 6a fe b2 71 bb 9b a5 92 de 18 dc f6 00 + c2 ae ea e5 6e 02 f7 cf 79 fc 14 cf 3b dc 7c d8 + 4f eb bb f9 50 ca 90 30 4b 22 19 a7 aa 06 3a ef + a2 c3 c1 98 0e 56 0c d6 4a fe 77 95 85 b6 10 76 + 57 b9 57 85 7e fd e6 01 09 88 ab 7d e4 17 fc 88 + d8 f3 84 c4 e6 e7 2c 3f 94 3e 0c 31 c0 c4 a5 cc + 36 f8 79 d8 a3 ac 9d 7d 59 86 0e aa da 6b 83 bb''', + 'e':'''01 00 01''', + 'd':'''05 6b 04 21 6f e5 f3 54 ac 77 25 0a 4b 6b 0c 85 + 25 a8 5c 59 b0 bd 80 c5 64 50 a2 2d 5f 43 8e 59 + 6a 33 3a a8 75 e2 91 dd 43 f4 8c b8 8b 9d 5f c0 + d4 99 f9 fc d1 c3 97 f9 af c0 70 cd 9e 39 8c 8d + 19 e6 1d b7 c7 41 0a 6b 26 75 df bf 5d 34 5b 80 + 4d 20 1a dd 50 2d 5c e2 df cb 09 1c e9 99 7b be + be 57 30 6f 38 3e 4d 58 81 03 f0 36 f7 e8 5d 19 + 34 d1 52 a3 23 e4 a8 db 45 1d 6f 4a 5b 1b 0f 10 + 2c c1 50 e0 2f ee e2 b8 8d ea 4a d4 c1 ba cc b2 + 4d 84 07 2d 14 e1 d2 4a 67 71 f7 40 8e e3 05 64 + fb 86 d4 39 3a 34 bc f0 b7 88 50 1d 19 33 03 f1 + 3a 22 84 b0 01 f0 f6 49 ea f7 93 28 d4 ac 5c 43 + 0a b4 41 49 20 a9 46 0e d1 b7 bc 40 ec 65 3e 87 + 6d 09 ab c5 09 ae 45 b5 25 19 01 16 a0 c2 61 01 + 84 82 98 50 9c 1c 3b f3 a4 83 e7 27 40 54 e1 5e + 97 07 50 36 e9 89 f6 09 32 80 7b 52 57 75 1e 79''' + }, + # Plaintext + '''8b ba 6b f8 2a 6c 0f 86 d5 f1 75 6e 97 95 68 70 + b0 89 53 b0 6b 4e b2 05 bc 16 94 ee''', + # Ciphertext + '''53 ea 5d c0 8c d2 60 fb 3b 85 85 67 28 7f a9 15 + 52 c3 0b 2f eb fb a2 13 f0 ae 87 70 2d 06 8d 19 + ba b0 7f e5 74 52 3d fb 42 13 9d 68 c3 c5 af ee + e0 bf e4 cb 79 69 cb f3 82 b8 04 d6 e6 13 96 14 + 4e 2d 0e 60 74 1f 89 93 c3 01 4b 58 b9 b1 95 7a + 8b ab cd 23 af 85 4f 4c 35 6f b1 66 2a a7 2b fc + c7 e5 86 55 9d c4 28 0d 16 0c 12 67 85 a7 23 eb + ee be ff 71 f1 15 94 44 0a ae f8 7d 10 79 3a 87 + 74 a2 39 d4 a0 4c 87 fe 14 67 b9 da f8 52 08 ec + 6c 72 55 79 4a 96 cc 29 14 2f 9a 8b d4 18 e3 c1 + fd 67 34 4b 0c d0 82 9d f3 b2 be c6 02 53 19 62 + 93 c6 b3 4d 3f 75 d3 2f 21 3d d4 5c 62 73 d5 05 + ad f4 cc ed 10 57 cb 75 8f c2 6a ee fa 44 12 55 + ed 4e 64 c1 99 ee 07 5e 7f 16 64 61 82 fd b4 64 + 73 9b 68 ab 5d af f0 e6 3e 95 52 01 68 24 f0 54 + bf 4d 3c 8c 90 a9 7b b6 b6 55 32 84 eb 42 9f cc''', + # Random + '''47 e1 ab 71 19 fe e5 6c 95 ee 5e aa d8 6f 40 d0 + aa 63 bd 33''', + SHA1 + ), + ) + + def testEncrypt1(self): + # Verify encryption using all test vectors + for test in self._testData: + # Build the key + comps = [int(rws(test[0][x]), 16) for x in ('n', 'e')] + key = RSA.construct(comps) + + # RNG that takes its random numbers from a pool given + # at initialization + class randGen: + + def __init__(self, data): + self.data = data + self.idx = 0 + + def __call__(self, N): + r = self.data[self.idx:N] + self.idx += N + return r + + # The real test + cipher = PKCS.new(key, test[4], randfunc=randGen(t2b(test[3]))) + ct = cipher.encrypt(t2b(test[1])) + self.assertEqual(ct, t2b(test[2])) + + def testEncrypt2(self): + # Verify that encryption fails if plaintext is too long + pt = '\x00'*(128-2*20-2+1) + cipher = PKCS.new(self.key1024) + self.assertRaises(ValueError, cipher.encrypt, pt) + + def testDecrypt1(self): + # Verify decryption using all test vectors + for test in self._testData: + # Build the key + comps = [int(rws(test[0][x]),16) for x in ('n', 'e', 'd')] + key = RSA.construct(comps) + # The real test + cipher = PKCS.new(key, test[4]) + pt = cipher.decrypt(t2b(test[2])) + self.assertEqual(pt, t2b(test[1])) + + def testDecrypt2(self): + # Simplest possible negative tests + for ct_size in (127, 128, 129): + cipher = PKCS.new(self.key1024) + self.assertRaises(ValueError, cipher.decrypt, bchr(0x00)*ct_size) + + def testEncryptDecrypt1(self): + # Encrypt/Decrypt messages of length [0..128-2*20-2] + for pt_len in range(0, 128-2*20-2): + pt = self.rng(pt_len) + cipher = PKCS.new(self.key1024) + ct = cipher.encrypt(pt) + pt2 = cipher.decrypt(ct) + self.assertEqual(pt, pt2) + + def testEncryptDecrypt2(self): + # Helper function to monitor what's requested from RNG + global asked + + def localRng(N): + global asked + asked += N + return self.rng(N) + + # Verify that OAEP is friendly to all hashes + for hashmod in (MD2, MD5, SHA1, SHA256, RIPEMD160): + # Verify that encrypt() asks for as many random bytes + # as the hash output size + asked = 0 + pt = self.rng(40) + cipher = PKCS.new(self.key1024, hashmod, randfunc=localRng) + ct = cipher.encrypt(pt) + self.assertEqual(cipher.decrypt(ct), pt) + self.assertEqual(asked, hashmod.digest_size) + + def testEncryptDecrypt3(self): + # Verify that OAEP supports labels + pt = self.rng(35) + xlabel = self.rng(22) + cipher = PKCS.new(self.key1024, label=xlabel) + ct = cipher.encrypt(pt) + self.assertEqual(cipher.decrypt(ct), pt) + + def testEncryptDecrypt4(self): + # Verify that encrypt() uses the custom MGF + global mgfcalls + # Helper function to monitor what's requested from MGF + + def newMGF(seed, maskLen): + global mgfcalls + mgfcalls += 1 + return b'\x00' * maskLen + + mgfcalls = 0 + pt = self.rng(32) + cipher = PKCS.new(self.key1024, mgfunc=newMGF) + ct = cipher.encrypt(pt) + self.assertEqual(mgfcalls, 2) + self.assertEqual(cipher.decrypt(ct), pt) + + def testByteArray(self): + pt = b("XER") + cipher = PKCS.new(self.key1024) + ct = cipher.encrypt(bytearray(pt)) + pt2 = cipher.decrypt(bytearray(ct)) + self.assertEqual(pt, pt2) + + def testMemoryview(self): + pt = b("XER") + cipher = PKCS.new(self.key1024) + ct = cipher.encrypt(memoryview(bytearray(pt))) + pt2 = cipher.decrypt(memoryview(bytearray(ct))) + self.assertEqual(pt, pt2) + + +class TestVectorsWycheproof(unittest.TestCase): + + def __init__(self, wycheproof_warnings, skip_slow_tests): + unittest.TestCase.__init__(self) + self._wycheproof_warnings = wycheproof_warnings + self._skip_slow_tests = skip_slow_tests + self._id = "None" + + def load_tests(self, filename): + + def filter_rsa(group): + return RSA.import_key(group['privateKeyPem']) + + def filter_sha(group): + if group['sha'] == "SHA-1": + return SHA1 + elif group['sha'] == "SHA-224": + return SHA224 + elif group['sha'] == "SHA-256": + return SHA256 + elif group['sha'] == "SHA-384": + return SHA384 + elif group['sha'] == "SHA-512": + return SHA512 + else: + raise ValueError("Unknown sha " + group['sha']) + + def filter_mgf(group): + if group['mgfSha'] == "SHA-1": + return lambda x, y: MGF1(x, y, SHA1) + elif group['mgfSha'] == "SHA-224": + return lambda x, y: MGF1(x, y, SHA224) + elif group['mgfSha'] == "SHA-256": + return lambda x, y: MGF1(x, y, SHA256) + elif group['mgfSha'] == "SHA-384": + return lambda x, y: MGF1(x, y, SHA384) + elif group['mgfSha'] == "SHA-512": + return lambda x, y: MGF1(x, y, SHA512) + else: + raise ValueError("Unknown mgf/sha " + group['mgfSha']) + + def filter_algo(group): + return "%s with MGF1/%s" % (group['sha'], group['mgfSha']) + + result = load_test_vectors_wycheproof(("Cipher", "wycheproof"), + filename, + "Wycheproof PKCS#1 OAEP (%s)" % filename, + group_tag={'rsa_key': filter_rsa, + 'hash_mod': filter_sha, + 'mgf': filter_mgf, + 'algo': filter_algo} + ) + return result + + def setUp(self): + self.tv = [] + self.tv.extend(self.load_tests("rsa_oaep_2048_sha1_mgf1sha1_test.json")) + self.tv.extend(self.load_tests("rsa_oaep_2048_sha224_mgf1sha1_test.json")) + self.tv.extend(self.load_tests("rsa_oaep_2048_sha224_mgf1sha224_test.json")) + self.tv.extend(self.load_tests("rsa_oaep_2048_sha256_mgf1sha1_test.json")) + self.tv.extend(self.load_tests("rsa_oaep_2048_sha256_mgf1sha256_test.json")) + self.tv.extend(self.load_tests("rsa_oaep_2048_sha384_mgf1sha1_test.json")) + self.tv.extend(self.load_tests("rsa_oaep_2048_sha384_mgf1sha384_test.json")) + self.tv.extend(self.load_tests("rsa_oaep_2048_sha512_mgf1sha1_test.json")) + self.tv.extend(self.load_tests("rsa_oaep_2048_sha512_mgf1sha512_test.json")) + if not self._skip_slow_tests: + self.tv.extend(self.load_tests("rsa_oaep_3072_sha256_mgf1sha1_test.json")) + self.tv.extend(self.load_tests("rsa_oaep_3072_sha256_mgf1sha256_test.json")) + self.tv.extend(self.load_tests("rsa_oaep_3072_sha512_mgf1sha1_test.json")) + self.tv.extend(self.load_tests("rsa_oaep_3072_sha512_mgf1sha512_test.json")) + self.tv.extend(self.load_tests("rsa_oaep_4096_sha256_mgf1sha1_test.json")) + self.tv.extend(self.load_tests("rsa_oaep_4096_sha256_mgf1sha256_test.json")) + self.tv.extend(self.load_tests("rsa_oaep_4096_sha512_mgf1sha1_test.json")) + self.tv.extend(self.load_tests("rsa_oaep_4096_sha512_mgf1sha512_test.json")) + self.tv.extend(self.load_tests("rsa_oaep_4096_sha512_mgf1sha512_test.json")) + self.tv.extend(self.load_tests("rsa_oaep_misc_test.json")) + + def shortDescription(self): + return self._id + + def warn(self, tv): + if tv.warning and self._wycheproof_warnings: + import warnings + warnings.warn("Wycheproof warning: %s (%s)" % (self._id, tv.comment)) + + def test_decrypt(self, tv): + self._id = "Wycheproof Decrypt %s Test #%s" % (tv.algo, tv.id) + + cipher = PKCS.new(tv.rsa_key, hashAlgo=tv.hash_mod, mgfunc=tv.mgf, label=tv.label) + try: + pt = cipher.decrypt(tv.ct) + except ValueError: + assert not tv.valid + else: + assert tv.valid + self.assertEqual(pt, tv.msg) + self.warn(tv) + + def runTest(self): + + for tv in self.tv: + self.test_decrypt(tv) + + +def get_tests(config={}): + skip_slow_tests = not config.get('slow_tests') + wycheproof_warnings = config.get('wycheproof_warnings') + + tests = [] + tests += list_test_cases(PKCS1_OAEP_Tests) + tests += [TestVectorsWycheproof(wycheproof_warnings, skip_slow_tests)] + return tests + + +if __name__ == '__main__': + def suite(): + unittest.TestSuite(get_tests()) + unittest.main(defaultTest='suite') + +# vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/__init__.py b/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/__init__.py new file mode 100644 index 0000000..5f5b999 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/__init__.py @@ -0,0 +1,62 @@ +# -*- coding: utf-8 -*- +# +# SelfTest/Hash/__init__.py: Self-test for hash modules +# +# Written in 2008 by Dwayne C. Litzenberger +# +# =================================================================== +# The contents of this file are dedicated to the public domain. To +# the extent that dedication to the public domain is not available, +# everyone is granted a worldwide, perpetual, royalty-free, +# non-exclusive license to exercise all rights associated with the +# contents of this file for any purpose whatsoever. +# No rights are reserved. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# =================================================================== + +"""Self-test for hash modules""" + +__revision__ = "$Id$" + +def get_tests(config={}): + tests = [] + from Cryptodome.SelfTest.Hash import test_HMAC; tests += test_HMAC.get_tests(config=config) + from Cryptodome.SelfTest.Hash import test_CMAC; tests += test_CMAC.get_tests(config=config) + from Cryptodome.SelfTest.Hash import test_MD2; tests += test_MD2.get_tests(config=config) + from Cryptodome.SelfTest.Hash import test_MD4; tests += test_MD4.get_tests(config=config) + from Cryptodome.SelfTest.Hash import test_MD5; tests += test_MD5.get_tests(config=config) + from Cryptodome.SelfTest.Hash import test_RIPEMD160; tests += test_RIPEMD160.get_tests(config=config) + from Cryptodome.SelfTest.Hash import test_SHA1; tests += test_SHA1.get_tests(config=config) + from Cryptodome.SelfTest.Hash import test_SHA224; tests += test_SHA224.get_tests(config=config) + from Cryptodome.SelfTest.Hash import test_SHA256; tests += test_SHA256.get_tests(config=config) + from Cryptodome.SelfTest.Hash import test_SHA384; tests += test_SHA384.get_tests(config=config) + from Cryptodome.SelfTest.Hash import test_SHA512; tests += test_SHA512.get_tests(config=config) + from Cryptodome.SelfTest.Hash import test_SHA3_224; tests += test_SHA3_224.get_tests(config=config) + from Cryptodome.SelfTest.Hash import test_SHA3_256; tests += test_SHA3_256.get_tests(config=config) + from Cryptodome.SelfTest.Hash import test_SHA3_384; tests += test_SHA3_384.get_tests(config=config) + from Cryptodome.SelfTest.Hash import test_SHA3_512; tests += test_SHA3_512.get_tests(config=config) + from Cryptodome.SelfTest.Hash import test_keccak; tests += test_keccak.get_tests(config=config) + from Cryptodome.SelfTest.Hash import test_SHAKE; tests += test_SHAKE.get_tests(config=config) + from Cryptodome.SelfTest.Hash import test_BLAKE2; tests += test_BLAKE2.get_tests(config=config) + from Cryptodome.SelfTest.Hash import test_Poly1305; tests += test_Poly1305.get_tests(config=config) + from Cryptodome.SelfTest.Hash import test_cSHAKE; tests += test_cSHAKE.get_tests(config=config) + from Cryptodome.SelfTest.Hash import test_KMAC; tests += test_KMAC.get_tests(config=config) + from Cryptodome.SelfTest.Hash import test_TupleHash; tests += test_TupleHash.get_tests(config=config) + from Cryptodome.SelfTest.Hash import test_KangarooTwelve; tests += test_KangarooTwelve.get_tests(config=config) + from Cryptodome.SelfTest.Hash import test_TurboSHAKE; tests += test_TurboSHAKE.get_tests(config=config) + return tests + +if __name__ == '__main__': + import unittest + suite = lambda: unittest.TestSuite(get_tests()) + unittest.main(defaultTest='suite') + +# vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000..0d43581 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/__pycache__/common.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/__pycache__/common.cpython-312.pyc new file mode 100644 index 0000000..399b043 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/__pycache__/common.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/__pycache__/test_BLAKE2.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/__pycache__/test_BLAKE2.cpython-312.pyc new file mode 100644 index 0000000..708d0e7 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/__pycache__/test_BLAKE2.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/__pycache__/test_CMAC.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/__pycache__/test_CMAC.cpython-312.pyc new file mode 100644 index 0000000..8536750 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/__pycache__/test_CMAC.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/__pycache__/test_HMAC.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/__pycache__/test_HMAC.cpython-312.pyc new file mode 100644 index 0000000..3792030 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/__pycache__/test_HMAC.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/__pycache__/test_KMAC.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/__pycache__/test_KMAC.cpython-312.pyc new file mode 100644 index 0000000..4c0192b Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/__pycache__/test_KMAC.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/__pycache__/test_KangarooTwelve.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/__pycache__/test_KangarooTwelve.cpython-312.pyc new file mode 100644 index 0000000..4367df7 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/__pycache__/test_KangarooTwelve.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/__pycache__/test_MD2.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/__pycache__/test_MD2.cpython-312.pyc new file mode 100644 index 0000000..f1129c1 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/__pycache__/test_MD2.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/__pycache__/test_MD4.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/__pycache__/test_MD4.cpython-312.pyc new file mode 100644 index 0000000..4e81b8f Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/__pycache__/test_MD4.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/__pycache__/test_MD5.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/__pycache__/test_MD5.cpython-312.pyc new file mode 100644 index 0000000..524e1e0 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/__pycache__/test_MD5.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/__pycache__/test_Poly1305.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/__pycache__/test_Poly1305.cpython-312.pyc new file mode 100644 index 0000000..f21d059 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/__pycache__/test_Poly1305.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/__pycache__/test_RIPEMD160.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/__pycache__/test_RIPEMD160.cpython-312.pyc new file mode 100644 index 0000000..5fad895 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/__pycache__/test_RIPEMD160.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/__pycache__/test_SHA1.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/__pycache__/test_SHA1.cpython-312.pyc new file mode 100644 index 0000000..0a27429 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/__pycache__/test_SHA1.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/__pycache__/test_SHA224.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/__pycache__/test_SHA224.cpython-312.pyc new file mode 100644 index 0000000..c5ca261 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/__pycache__/test_SHA224.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/__pycache__/test_SHA256.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/__pycache__/test_SHA256.cpython-312.pyc new file mode 100644 index 0000000..7650611 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/__pycache__/test_SHA256.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/__pycache__/test_SHA384.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/__pycache__/test_SHA384.cpython-312.pyc new file mode 100644 index 0000000..21e6f00 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/__pycache__/test_SHA384.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/__pycache__/test_SHA3_224.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/__pycache__/test_SHA3_224.cpython-312.pyc new file mode 100644 index 0000000..cc54034 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/__pycache__/test_SHA3_224.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/__pycache__/test_SHA3_256.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/__pycache__/test_SHA3_256.cpython-312.pyc new file mode 100644 index 0000000..392e0c1 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/__pycache__/test_SHA3_256.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/__pycache__/test_SHA3_384.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/__pycache__/test_SHA3_384.cpython-312.pyc new file mode 100644 index 0000000..60cc4c2 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/__pycache__/test_SHA3_384.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/__pycache__/test_SHA3_512.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/__pycache__/test_SHA3_512.cpython-312.pyc new file mode 100644 index 0000000..3f471ed Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/__pycache__/test_SHA3_512.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/__pycache__/test_SHA512.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/__pycache__/test_SHA512.cpython-312.pyc new file mode 100644 index 0000000..2197196 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/__pycache__/test_SHA512.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/__pycache__/test_SHAKE.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/__pycache__/test_SHAKE.cpython-312.pyc new file mode 100644 index 0000000..beb7663 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/__pycache__/test_SHAKE.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/__pycache__/test_TupleHash.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/__pycache__/test_TupleHash.cpython-312.pyc new file mode 100644 index 0000000..cb6b63c Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/__pycache__/test_TupleHash.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/__pycache__/test_TurboSHAKE.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/__pycache__/test_TurboSHAKE.cpython-312.pyc new file mode 100644 index 0000000..f12b7f6 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/__pycache__/test_TurboSHAKE.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/__pycache__/test_cSHAKE.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/__pycache__/test_cSHAKE.cpython-312.pyc new file mode 100644 index 0000000..874e3ba Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/__pycache__/test_cSHAKE.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/__pycache__/test_keccak.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/__pycache__/test_keccak.cpython-312.pyc new file mode 100644 index 0000000..96263ad Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/__pycache__/test_keccak.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/common.py b/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/common.py new file mode 100644 index 0000000..4ed9234 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/common.py @@ -0,0 +1,290 @@ +# -*- coding: utf-8 -*- +# +# SelfTest/Hash/common.py: Common code for Cryptodome.SelfTest.Hash +# +# Written in 2008 by Dwayne C. Litzenberger +# +# =================================================================== +# The contents of this file are dedicated to the public domain. To +# the extent that dedication to the public domain is not available, +# everyone is granted a worldwide, perpetual, royalty-free, +# non-exclusive license to exercise all rights associated with the +# contents of this file for any purpose whatsoever. +# No rights are reserved. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# =================================================================== + +"""Self-testing for PyCryptodome hash modules""" + +import re +import sys +import unittest +import binascii +import Cryptodome.Hash +from binascii import hexlify, unhexlify +from Cryptodome.Util.py3compat import b, tobytes +from Cryptodome.Util.strxor import strxor_c + +def t2b(hex_string): + shorter = re.sub(br'\s+', b'', tobytes(hex_string)) + return unhexlify(shorter) + + +class HashDigestSizeSelfTest(unittest.TestCase): + + def __init__(self, hashmod, description, expected, extra_params): + unittest.TestCase.__init__(self) + self.hashmod = hashmod + self.expected = expected + self.description = description + self.extra_params = extra_params + + def shortDescription(self): + return self.description + + def runTest(self): + if "truncate" not in self.extra_params: + self.assertTrue(hasattr(self.hashmod, "digest_size")) + self.assertEqual(self.hashmod.digest_size, self.expected) + h = self.hashmod.new(**self.extra_params) + self.assertTrue(hasattr(h, "digest_size")) + self.assertEqual(h.digest_size, self.expected) + + +class HashSelfTest(unittest.TestCase): + + def __init__(self, hashmod, description, expected, input, extra_params): + unittest.TestCase.__init__(self) + self.hashmod = hashmod + self.expected = expected.lower() + self.input = input + self.description = description + self.extra_params = extra_params + + def shortDescription(self): + return self.description + + def runTest(self): + h = self.hashmod.new(**self.extra_params) + h.update(self.input) + + out1 = binascii.b2a_hex(h.digest()) + out2 = h.hexdigest() + + h = self.hashmod.new(self.input, **self.extra_params) + + out3 = h.hexdigest() + out4 = binascii.b2a_hex(h.digest()) + + # PY3K: hexdigest() should return str(), and digest() bytes + self.assertEqual(self.expected, out1) # h = .new(); h.update(data); h.digest() + if sys.version_info[0] == 2: + self.assertEqual(self.expected, out2) # h = .new(); h.update(data); h.hexdigest() + self.assertEqual(self.expected, out3) # h = .new(data); h.hexdigest() + else: + self.assertEqual(self.expected.decode(), out2) # h = .new(); h.update(data); h.hexdigest() + self.assertEqual(self.expected.decode(), out3) # h = .new(data); h.hexdigest() + self.assertEqual(self.expected, out4) # h = .new(data); h.digest() + + # Verify that the .new() method produces a fresh hash object, except + # for MD5 and SHA1, which are hashlib objects. (But test any .new() + # method that does exist.) + if self.hashmod.__name__ not in ('Cryptodome.Hash.MD5', 'Cryptodome.Hash.SHA1') or hasattr(h, 'new'): + h2 = h.new() + h2.update(self.input) + out5 = binascii.b2a_hex(h2.digest()) + self.assertEqual(self.expected, out5) + + +class HashTestOID(unittest.TestCase): + def __init__(self, hashmod, oid, extra_params): + unittest.TestCase.__init__(self) + self.hashmod = hashmod + self.oid = oid + self.extra_params = extra_params + + def runTest(self): + h = self.hashmod.new(**self.extra_params) + self.assertEqual(h.oid, self.oid) + + +class ByteArrayTest(unittest.TestCase): + + def __init__(self, module, extra_params): + unittest.TestCase.__init__(self) + self.module = module + self.extra_params = extra_params + + def runTest(self): + data = b("\x00\x01\x02") + + # Data can be a bytearray (during initialization) + ba = bytearray(data) + + h1 = self.module.new(data, **self.extra_params) + h2 = self.module.new(ba, **self.extra_params) + ba[:1] = b'\xFF' + self.assertEqual(h1.digest(), h2.digest()) + + # Data can be a bytearray (during operation) + ba = bytearray(data) + + h1 = self.module.new(**self.extra_params) + h2 = self.module.new(**self.extra_params) + + h1.update(data) + h2.update(ba) + + ba[:1] = b'\xFF' + self.assertEqual(h1.digest(), h2.digest()) + + +class MemoryViewTest(unittest.TestCase): + + def __init__(self, module, extra_params): + unittest.TestCase.__init__(self) + self.module = module + self.extra_params = extra_params + + def runTest(self): + + data = b"\x00\x01\x02" + + def get_mv_ro(data): + return memoryview(data) + + def get_mv_rw(data): + return memoryview(bytearray(data)) + + for get_mv in get_mv_ro, get_mv_rw: + + # Data can be a memoryview (during initialization) + mv = get_mv(data) + + h1 = self.module.new(data, **self.extra_params) + h2 = self.module.new(mv, **self.extra_params) + if not mv.readonly: + mv[:1] = b'\xFF' + self.assertEqual(h1.digest(), h2.digest()) + + # Data can be a memoryview (during operation) + mv = get_mv(data) + + h1 = self.module.new(**self.extra_params) + h2 = self.module.new(**self.extra_params) + h1.update(data) + h2.update(mv) + if not mv.readonly: + mv[:1] = b'\xFF' + self.assertEqual(h1.digest(), h2.digest()) + + +class MACSelfTest(unittest.TestCase): + + def __init__(self, module, description, result, data, key, params): + unittest.TestCase.__init__(self) + self.module = module + self.result = t2b(result) + self.data = t2b(data) + self.key = t2b(key) + self.params = params + self.description = description + + def shortDescription(self): + return self.description + + def runTest(self): + + result_hex = hexlify(self.result) + + # Verify result + h = self.module.new(self.key, **self.params) + h.update(self.data) + self.assertEqual(self.result, h.digest()) + self.assertEqual(hexlify(self.result).decode('ascii'), h.hexdigest()) + + # Verify that correct MAC does not raise any exception + h.verify(self.result) + h.hexverify(result_hex) + + # Verify that incorrect MAC does raise ValueError exception + wrong_mac = strxor_c(self.result, 255) + self.assertRaises(ValueError, h.verify, wrong_mac) + self.assertRaises(ValueError, h.hexverify, "4556") + + # Verify again, with data passed to new() + h = self.module.new(self.key, self.data, **self.params) + self.assertEqual(self.result, h.digest()) + self.assertEqual(hexlify(self.result).decode('ascii'), h.hexdigest()) + + # Test .copy() + try: + h = self.module.new(self.key, self.data, **self.params) + h2 = h.copy() + h3 = h.copy() + + # Verify that changing the copy does not change the original + h2.update(b"bla") + self.assertEqual(h3.digest(), self.result) + + # Verify that both can reach the same state + h.update(b"bla") + self.assertEqual(h.digest(), h2.digest()) + except NotImplementedError: + pass + + # PY3K: Check that hexdigest() returns str and digest() returns bytes + self.assertTrue(isinstance(h.digest(), type(b""))) + self.assertTrue(isinstance(h.hexdigest(), type(""))) + + # PY3K: Check that .hexverify() accepts bytes or str + h.hexverify(h.hexdigest()) + h.hexverify(h.hexdigest().encode('ascii')) + + +def make_hash_tests(module, module_name, test_data, digest_size, oid=None, + extra_params={}): + tests = [] + for i in range(len(test_data)): + row = test_data[i] + (expected, input) = map(tobytes,row[0:2]) + if len(row) < 3: + description = repr(input) + else: + description = row[2] + name = "%s #%d: %s" % (module_name, i+1, description) + tests.append(HashSelfTest(module, name, expected, input, extra_params)) + + name = "%s #%d: digest_size" % (module_name, len(test_data) + 1) + tests.append(HashDigestSizeSelfTest(module, name, digest_size, extra_params)) + + if oid is not None: + tests.append(HashTestOID(module, oid, extra_params)) + + tests.append(ByteArrayTest(module, extra_params)) + + tests.append(MemoryViewTest(module, extra_params)) + + return tests + + +def make_mac_tests(module, module_name, test_data): + tests = [] + for i, row in enumerate(test_data): + if len(row) == 4: + (key, data, results, description, params) = list(row) + [ {} ] + else: + (key, data, results, description, params) = row + name = "%s #%d: %s" % (module_name, i+1, description) + tests.append(MACSelfTest(module, name, results, data, key, params)) + return tests + +# vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/test_BLAKE2.py b/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/test_BLAKE2.py new file mode 100644 index 0000000..e5ed63b --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/test_BLAKE2.py @@ -0,0 +1,482 @@ +# =================================================================== +# +# Copyright (c) 2014, Legrandin +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# =================================================================== + +import os +import re +import unittest +import warnings +from binascii import unhexlify, hexlify + +from Cryptodome.Util.py3compat import tobytes +from Cryptodome.Util.strxor import strxor_c +from Cryptodome.SelfTest.st_common import list_test_cases + +from Cryptodome.Hash import BLAKE2b, BLAKE2s + + +class Blake2Test(unittest.TestCase): + + def test_new_positive(self): + + h = self.BLAKE2.new(digest_bits=self.max_bits) + for new_func in self.BLAKE2.new, h.new: + + for dbits in range(8, self.max_bits + 1, 8): + hobj = new_func(digest_bits=dbits) + self.assertEqual(hobj.digest_size, dbits // 8) + + for dbytes in range(1, self.max_bytes + 1): + hobj = new_func(digest_bytes=dbytes) + self.assertEqual(hobj.digest_size, dbytes) + + digest1 = new_func(data=b"\x90", digest_bytes=self.max_bytes).digest() + digest2 = new_func(digest_bytes=self.max_bytes).update(b"\x90").digest() + self.assertEqual(digest1, digest2) + + new_func(data=b"A", key=b"5", digest_bytes=self.max_bytes) + + hobj = h.new() + self.assertEqual(hobj.digest_size, self.max_bytes) + + def test_new_negative(self): + + h = self.BLAKE2.new(digest_bits=self.max_bits) + for new_func in self.BLAKE2.new, h.new: + self.assertRaises(TypeError, new_func, + digest_bytes=self.max_bytes, + digest_bits=self.max_bits) + self.assertRaises(ValueError, new_func, digest_bytes=0) + self.assertRaises(ValueError, new_func, + digest_bytes=self.max_bytes + 1) + self.assertRaises(ValueError, new_func, digest_bits=7) + self.assertRaises(ValueError, new_func, digest_bits=15) + self.assertRaises(ValueError, new_func, + digest_bits=self.max_bits + 1) + self.assertRaises(TypeError, new_func, + digest_bytes=self.max_bytes, + key=u"string") + self.assertRaises(TypeError, new_func, + digest_bytes=self.max_bytes, + data=u"string") + + def test_default_digest_size(self): + digest = self.BLAKE2.new(data=b'abc').digest() + self.assertEqual(len(digest), self.max_bytes) + + def test_update(self): + pieces = [b"\x0A" * 200, b"\x14" * 300] + h = self.BLAKE2.new(digest_bytes=self.max_bytes) + h.update(pieces[0]).update(pieces[1]) + digest = h.digest() + h = self.BLAKE2.new(digest_bytes=self.max_bytes) + h.update(pieces[0] + pieces[1]) + self.assertEqual(h.digest(), digest) + + def test_update_negative(self): + h = self.BLAKE2.new(digest_bytes=self.max_bytes) + self.assertRaises(TypeError, h.update, u"string") + + def test_digest(self): + h = self.BLAKE2.new(digest_bytes=self.max_bytes) + digest = h.digest() + + # hexdigest does not change the state + self.assertEqual(h.digest(), digest) + # digest returns a byte string + self.assertTrue(isinstance(digest, type(b"digest"))) + + def test_update_after_digest(self): + msg = b"rrrrttt" + + # Normally, update() cannot be done after digest() + h = self.BLAKE2.new(digest_bits=256, data=msg[:4]) + dig1 = h.digest() + self.assertRaises(TypeError, h.update, msg[4:]) + dig2 = self.BLAKE2.new(digest_bits=256, data=msg).digest() + + # With the proper flag, it is allowed + h = self.BLAKE2.new(digest_bits=256, data=msg[:4], update_after_digest=True) + self.assertEqual(h.digest(), dig1) + # ... and the subsequent digest applies to the entire message + # up to that point + h.update(msg[4:]) + self.assertEqual(h.digest(), dig2) + + def test_hex_digest(self): + mac = self.BLAKE2.new(digest_bits=self.max_bits) + digest = mac.digest() + hexdigest = mac.hexdigest() + + # hexdigest is equivalent to digest + self.assertEqual(hexlify(digest), tobytes(hexdigest)) + # hexdigest does not change the state + self.assertEqual(mac.hexdigest(), hexdigest) + # hexdigest returns a string + self.assertTrue(isinstance(hexdigest, type("digest"))) + + def test_verify(self): + h = self.BLAKE2.new(digest_bytes=self.max_bytes, key=b"4") + mac = h.digest() + h.verify(mac) + wrong_mac = strxor_c(mac, 255) + self.assertRaises(ValueError, h.verify, wrong_mac) + + def test_hexverify(self): + h = self.BLAKE2.new(digest_bytes=self.max_bytes, key=b"4") + mac = h.hexdigest() + h.hexverify(mac) + self.assertRaises(ValueError, h.hexverify, "4556") + + def test_oid(self): + + prefix = "1.3.6.1.4.1.1722.12.2." + self.oid_variant + "." + + for digest_bits in self.digest_bits_oid: + h = self.BLAKE2.new(digest_bits=digest_bits) + self.assertEqual(h.oid, prefix + str(digest_bits // 8)) + + h = self.BLAKE2.new(digest_bits=digest_bits, key=b"secret") + self.assertRaises(AttributeError, lambda: h.oid) + + for digest_bits in (8, self.max_bits): + if digest_bits in self.digest_bits_oid: + continue + self.assertRaises(AttributeError, lambda: h.oid) + + def test_bytearray(self): + + key = b'0' * 16 + data = b"\x00\x01\x02" + + # Data and key can be a bytearray (during initialization) + key_ba = bytearray(key) + data_ba = bytearray(data) + + h1 = self.BLAKE2.new(data=data, key=key) + h2 = self.BLAKE2.new(data=data_ba, key=key_ba) + key_ba[:1] = b'\xFF' + data_ba[:1] = b'\xFF' + + self.assertEqual(h1.digest(), h2.digest()) + + # Data can be a bytearray (during operation) + data_ba = bytearray(data) + + h1 = self.BLAKE2.new() + h2 = self.BLAKE2.new() + h1.update(data) + h2.update(data_ba) + data_ba[:1] = b'\xFF' + + self.assertEqual(h1.digest(), h2.digest()) + + def test_memoryview(self): + + key = b'0' * 16 + data = b"\x00\x01\x02" + + def get_mv_ro(data): + return memoryview(data) + + def get_mv_rw(data): + return memoryview(bytearray(data)) + + for get_mv in (get_mv_ro, get_mv_rw): + + # Data and key can be a memoryview (during initialization) + key_mv = get_mv(key) + data_mv = get_mv(data) + + h1 = self.BLAKE2.new(data=data, key=key) + h2 = self.BLAKE2.new(data=data_mv, key=key_mv) + if not data_mv.readonly: + data_mv[:1] = b'\xFF' + key_mv[:1] = b'\xFF' + + self.assertEqual(h1.digest(), h2.digest()) + + # Data can be a memoryview (during operation) + data_mv = get_mv(data) + + h1 = self.BLAKE2.new() + h2 = self.BLAKE2.new() + h1.update(data) + h2.update(data_mv) + if not data_mv.readonly: + data_mv[:1] = b'\xFF' + + self.assertEqual(h1.digest(), h2.digest()) + + +class Blake2bTest(Blake2Test): + #: Module + BLAKE2 = BLAKE2b + #: Max output size (in bits) + max_bits = 512 + #: Max output size (in bytes) + max_bytes = 64 + #: Bit size of the digests for which an ASN OID exists + digest_bits_oid = (160, 256, 384, 512) + # http://tools.ietf.org/html/draft-saarinen-blake2-02 + oid_variant = "1" + + +class Blake2sTest(Blake2Test): + #: Module + BLAKE2 = BLAKE2s + #: Max output size (in bits) + max_bits = 256 + #: Max output size (in bytes) + max_bytes = 32 + #: Bit size of the digests for which an ASN OID exists + digest_bits_oid = (128, 160, 224, 256) + # http://tools.ietf.org/html/draft-saarinen-blake2-02 + oid_variant = "2" + + +class Blake2OfficialTestVector(unittest.TestCase): + + def _load_tests(self, test_vector_file): + expected = "in" + test_vectors = [] + with open(test_vector_file, "rt") as test_vector_fd: + for line_number, line in enumerate(test_vector_fd): + + if line.strip() == "" or line.startswith("#"): + continue + + res = re.match("%s:\t([0-9A-Fa-f]*)" % expected, line) + if not res: + raise ValueError("Incorrect test vector format (line %d)" + % line_number) + + if res.group(1): + bin_value = unhexlify(tobytes(res.group(1))) + else: + bin_value = b"" + if expected == "in": + input_data = bin_value + expected = "key" + elif expected == "key": + key = bin_value + expected = "hash" + else: + result = bin_value + expected = "in" + test_vectors.append((input_data, key, result)) + return test_vectors + + def setUp(self): + + dir_comps = ("Hash", self.name) + file_name = self.name.lower() + "-test.txt" + self.description = "%s tests" % self.name + + try: + import pycryptodome_test_vectors # type: ignore + except ImportError: + warnings.warn("Warning: skipping extended tests for %s" % self.name, + UserWarning) + self.test_vectors = [] + return + + init_dir = os.path.dirname(pycryptodome_test_vectors.__file__) + full_file_name = os.path.join(os.path.join(init_dir, *dir_comps), file_name) + self.test_vectors = self._load_tests(full_file_name) + + def runTest(self): + for (input_data, key, result) in self.test_vectors: + mac = self.BLAKE2.new(key=key, digest_bytes=self.max_bytes) + mac.update(input_data) + self.assertEqual(mac.digest(), result) + + +class Blake2bOfficialTestVector(Blake2OfficialTestVector): + #: Module + BLAKE2 = BLAKE2b + #: Hash name + name = "BLAKE2b" + #: Max digest size + max_bytes = 64 + + +class Blake2sOfficialTestVector(Blake2OfficialTestVector): + #: Module + BLAKE2 = BLAKE2s + #: Hash name + name = "BLAKE2s" + #: Max digest size + max_bytes = 32 + + +class Blake2TestVector1(unittest.TestCase): + + def _load_tests(self, test_vector_file): + test_vectors = [] + with open(test_vector_file, "rt") as test_vector_fd: + for line_number, line in enumerate(test_vector_fd): + if line.strip() == "" or line.startswith("#"): + continue + res = re.match("digest: ([0-9A-Fa-f]*)", line) + if not res: + raise ValueError("Incorrect test vector format (line %d)" + % line_number) + + test_vectors.append(unhexlify(tobytes(res.group(1)))) + return test_vectors + + def setUp(self): + dir_comps = ("Hash", self.name) + file_name = "tv1.txt" + self.description = "%s tests" % self.name + + try: + import pycryptodome_test_vectors + except ImportError: + warnings.warn("Warning: skipping extended tests for %s" % self.name, + UserWarning) + self.test_vectors = [] + return + + init_dir = os.path.dirname(pycryptodome_test_vectors.__file__) + full_file_name = os.path.join(os.path.join(init_dir, *dir_comps), file_name) + self.test_vectors = self._load_tests(full_file_name) + + def runTest(self): + + for tv in self.test_vectors: + digest_bytes = len(tv) + next_data = b"" + for _ in range(100): + h = self.BLAKE2.new(digest_bytes=digest_bytes) + h.update(next_data) + next_data = h.digest() + next_data + self.assertEqual(h.digest(), tv) + + +class Blake2bTestVector1(Blake2TestVector1): + #: Module + BLAKE2 = BLAKE2b + #: Hash name + name = "BLAKE2b" + + +class Blake2sTestVector1(Blake2TestVector1): + #: Module + BLAKE2 = BLAKE2s + #: Hash name + name = "BLAKE2s" + + +class Blake2TestVector2(unittest.TestCase): + + def _load_tests(self, test_vector_file): + test_vectors = [] + with open(test_vector_file, "rt") as test_vector_fd: + for line_number, line in enumerate(test_vector_fd): + if line.strip() == "" or line.startswith("#"): + continue + res = re.match(r"digest\(([0-9]+)\): ([0-9A-Fa-f]*)", line) + if not res: + raise ValueError("Incorrect test vector format (line %d)" + % line_number) + key_size = int(res.group(1)) + result = unhexlify(tobytes(res.group(2))) + test_vectors.append((key_size, result)) + return test_vectors + + def setUp(self): + dir_comps = ("Hash", self.name) + file_name = "tv2.txt" + self.description = "%s tests" % self.name + + try: + import pycryptodome_test_vectors # type: ignore + except ImportError: + warnings.warn("Warning: skipping extended tests for %s" % self.name, + UserWarning) + self.test_vectors = [] + return + + init_dir = os.path.dirname(pycryptodome_test_vectors.__file__) + full_file_name = os.path.join(os.path.join(init_dir, *dir_comps), file_name) + self.test_vectors = self._load_tests(full_file_name) + + def runTest(self): + + for key_size, result in self.test_vectors: + next_data = b"" + for _ in range(100): + h = self.BLAKE2.new(digest_bytes=self.max_bytes, + key=b"A" * key_size) + h.update(next_data) + next_data = h.digest() + next_data + self.assertEqual(h.digest(), result) + + +class Blake2bTestVector2(Blake2TestVector1): + #: Module + BLAKE2 = BLAKE2b + #: Hash name + name = "BLAKE2b" + #: Max digest size in bytes + max_bytes = 64 + + +class Blake2sTestVector2(Blake2TestVector1): + #: Module + BLAKE2 = BLAKE2s + #: Hash name + name = "BLAKE2s" + #: Max digest size in bytes + max_bytes = 32 + + +def get_tests(config={}): + tests = [] + + tests += list_test_cases(Blake2bTest) + tests.append(Blake2bOfficialTestVector()) + tests.append(Blake2bTestVector1()) + tests.append(Blake2bTestVector2()) + + tests += list_test_cases(Blake2sTest) + tests.append(Blake2sOfficialTestVector()) + tests.append(Blake2sTestVector1()) + tests.append(Blake2sTestVector2()) + + return tests + + +if __name__ == '__main__': + import unittest + def suite(): + return unittest.TestSuite(get_tests()) + unittest.main(defaultTest='suite') diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/test_CMAC.py b/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/test_CMAC.py new file mode 100644 index 0000000..f88f1cd --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/test_CMAC.py @@ -0,0 +1,448 @@ +# +# SelfTest/Hash/CMAC.py: Self-test for the CMAC module +# +# =================================================================== +# +# Copyright (c) 2014, Legrandin +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# =================================================================== + +"""Self-test suite for Cryptodome.Hash.CMAC""" + +import json +import unittest +from binascii import unhexlify + +from Cryptodome.Util.py3compat import tobytes + +from Cryptodome.Hash import CMAC +from Cryptodome.Cipher import AES, DES3 +from Cryptodome.Hash import SHAKE128 + +from Cryptodome.Util.strxor import strxor + +from Cryptodome.SelfTest.st_common import list_test_cases +from Cryptodome.SelfTest.loader import load_test_vectors_wycheproof + +# This is a list of (key, data, result, description, module) tuples. +test_data = [ + + ## Test vectors from RFC 4493 ## + ## The are also in NIST SP 800 38B D.2 ## + ( '2b7e151628aed2a6abf7158809cf4f3c', + '', + 'bb1d6929e95937287fa37d129b756746', + 'RFC 4493 #1', + AES + ), + + ( '2b7e151628aed2a6abf7158809cf4f3c', + '6bc1bee22e409f96e93d7e117393172a', + '070a16b46b4d4144f79bdd9dd04a287c', + 'RFC 4493 #2', + AES + ), + + ( '2b7e151628aed2a6abf7158809cf4f3c', + '6bc1bee22e409f96e93d7e117393172a'+ + 'ae2d8a571e03ac9c9eb76fac45af8e51'+ + '30c81c46a35ce411', + 'dfa66747de9ae63030ca32611497c827', + 'RFC 4493 #3', + AES + ), + + ( '2b7e151628aed2a6abf7158809cf4f3c', + '6bc1bee22e409f96e93d7e117393172a'+ + 'ae2d8a571e03ac9c9eb76fac45af8e51'+ + '30c81c46a35ce411e5fbc1191a0a52ef'+ + 'f69f2445df4f9b17ad2b417be66c3710', + '51f0bebf7e3b9d92fc49741779363cfe', + 'RFC 4493 #4', + AES + ), + + ## The rest of Appendix D of NIST SP 800 38B + ## was not totally correct. + ## Values in Examples 14, 15, 18, and 19 were wrong. + ## The updated test values are published in: + ## http://csrc.nist.gov/publications/nistpubs/800-38B/Updated_CMAC_Examples.pdf + + ( '8e73b0f7da0e6452c810f32b809079e5'+ + '62f8ead2522c6b7b', + '', + 'd17ddf46adaacde531cac483de7a9367', + 'NIST SP 800 38B D.2 Example 5', + AES + ), + + ( '8e73b0f7da0e6452c810f32b809079e5'+ + '62f8ead2522c6b7b', + '6bc1bee22e409f96e93d7e117393172a', + '9e99a7bf31e710900662f65e617c5184', + 'NIST SP 800 38B D.2 Example 6', + AES + ), + + ( '8e73b0f7da0e6452c810f32b809079e5'+ + '62f8ead2522c6b7b', + '6bc1bee22e409f96e93d7e117393172a'+ + 'ae2d8a571e03ac9c9eb76fac45af8e51'+ + '30c81c46a35ce411', + '8a1de5be2eb31aad089a82e6ee908b0e', + 'NIST SP 800 38B D.2 Example 7', + AES + ), + + ( '8e73b0f7da0e6452c810f32b809079e5'+ + '62f8ead2522c6b7b', + '6bc1bee22e409f96e93d7e117393172a'+ + 'ae2d8a571e03ac9c9eb76fac45af8e51'+ + '30c81c46a35ce411e5fbc1191a0a52ef'+ + 'f69f2445df4f9b17ad2b417be66c3710', + 'a1d5df0eed790f794d77589659f39a11', + 'NIST SP 800 38B D.2 Example 8', + AES + ), + + ( '603deb1015ca71be2b73aef0857d7781'+ + '1f352c073b6108d72d9810a30914dff4', + '', + '028962f61b7bf89efc6b551f4667d983', + 'NIST SP 800 38B D.3 Example 9', + AES + ), + + ( '603deb1015ca71be2b73aef0857d7781'+ + '1f352c073b6108d72d9810a30914dff4', + '6bc1bee22e409f96e93d7e117393172a', + '28a7023f452e8f82bd4bf28d8c37c35c', + 'NIST SP 800 38B D.3 Example 10', + AES + ), + + ( '603deb1015ca71be2b73aef0857d7781'+ + '1f352c073b6108d72d9810a30914dff4', + '6bc1bee22e409f96e93d7e117393172a'+ + 'ae2d8a571e03ac9c9eb76fac45af8e51'+ + '30c81c46a35ce411', + 'aaf3d8f1de5640c232f5b169b9c911e6', + 'NIST SP 800 38B D.3 Example 11', + AES + ), + + ( '603deb1015ca71be2b73aef0857d7781'+ + '1f352c073b6108d72d9810a30914dff4', + '6bc1bee22e409f96e93d7e117393172a'+ + 'ae2d8a571e03ac9c9eb76fac45af8e51'+ + '30c81c46a35ce411e5fbc1191a0a52ef'+ + 'f69f2445df4f9b17ad2b417be66c3710', + 'e1992190549f6ed5696a2c056c315410', + 'NIST SP 800 38B D.3 Example 12', + AES + ), + + ( '8aa83bf8cbda1062'+ + '0bc1bf19fbb6cd58'+ + 'bc313d4a371ca8b5', + '', + 'b7a688e122ffaf95', + 'NIST SP 800 38B D.4 Example 13', + DES3 + ), + + ( '8aa83bf8cbda1062'+ + '0bc1bf19fbb6cd58'+ + 'bc313d4a371ca8b5', + '6bc1bee22e409f96', + '8e8f293136283797', + 'NIST SP 800 38B D.4 Example 14', + DES3 + ), + + ( '8aa83bf8cbda1062'+ + '0bc1bf19fbb6cd58'+ + 'bc313d4a371ca8b5', + '6bc1bee22e409f96'+ + 'e93d7e117393172a'+ + 'ae2d8a57', + '743ddbe0ce2dc2ed', + 'NIST SP 800 38B D.4 Example 15', + DES3 + ), + + ( '8aa83bf8cbda1062'+ + '0bc1bf19fbb6cd58'+ + 'bc313d4a371ca8b5', + '6bc1bee22e409f96'+ + 'e93d7e117393172a'+ + 'ae2d8a571e03ac9c'+ + '9eb76fac45af8e51', + '33e6b1092400eae5', + 'NIST SP 800 38B D.4 Example 16', + DES3 + ), + + ( '4cf15134a2850dd5'+ + '8a3d10ba80570d38', + '', + 'bd2ebf9a3ba00361', + 'NIST SP 800 38B D.7 Example 17', + DES3 + ), + + ( '4cf15134a2850dd5'+ + '8a3d10ba80570d38', + '6bc1bee22e409f96', + '4ff2ab813c53ce83', + 'NIST SP 800 38B D.7 Example 18', + DES3 + ), + + ( '4cf15134a2850dd5'+ + '8a3d10ba80570d38', + '6bc1bee22e409f96'+ + 'e93d7e117393172a'+ + 'ae2d8a57', + '62dd1b471902bd4e', + 'NIST SP 800 38B D.7 Example 19', + DES3 + ), + + ( '4cf15134a2850dd5'+ + '8a3d10ba80570d38', + '6bc1bee22e409f96'+ + 'e93d7e117393172a'+ + 'ae2d8a571e03ac9c'+ + '9eb76fac45af8e51', + '31b1e431dabc4eb8', + 'NIST SP 800 38B D.7 Example 20', + DES3 + ), + +] + + +def get_tag_random(tag, length): + return SHAKE128.new(data=tobytes(tag)).read(length) + + +class TestCMAC(unittest.TestCase): + + def test_internal_caching(self): + """Verify that internal caching is implemented correctly""" + + data_to_mac = get_tag_random("data_to_mac", 128) + key = get_tag_random("key", 16) + ref_mac = CMAC.new(key, msg=data_to_mac, ciphermod=AES).digest() + + # Break up in chunks of different length + # The result must always be the same + for chunk_length in 1, 2, 3, 7, 10, 13, 16, 40, 80, 128: + + chunks = [data_to_mac[i:i+chunk_length] for i in + range(0, len(data_to_mac), chunk_length)] + + mac = CMAC.new(key, ciphermod=AES) + for chunk in chunks: + mac.update(chunk) + self.assertEqual(ref_mac, mac.digest()) + + def test_update_after_digest(self): + msg = b"rrrrttt" + key = b"4" * 16 + + # Normally, update() cannot be done after digest() + h = CMAC.new(key, msg[:4], ciphermod=AES) + dig1 = h.digest() + self.assertRaises(TypeError, h.update, msg[4:]) + dig2 = CMAC.new(key, msg, ciphermod=AES).digest() + + # With the proper flag, it is allowed + h2 = CMAC.new(key, msg[:4], ciphermod=AES, update_after_digest=True) + self.assertEqual(h2.digest(), dig1) + # ... and the subsequent digest applies to the entire message + # up to that point + h2.update(msg[4:]) + self.assertEqual(h2.digest(), dig2) + + +class ByteArrayTests(unittest.TestCase): + + def runTest(self): + + key = b"0" * 16 + data = b"\x00\x01\x02" + + # Data and key can be a bytearray (during initialization) + key_ba = bytearray(key) + data_ba = bytearray(data) + + h1 = CMAC.new(key, data, ciphermod=AES) + h2 = CMAC.new(key_ba, data_ba, ciphermod=AES) + key_ba[:1] = b'\xFF' + data_ba[:1] = b'\xFF' + self.assertEqual(h1.digest(), h2.digest()) + + # Data can be a bytearray (during operation) + key_ba = bytearray(key) + data_ba = bytearray(data) + + h1 = CMAC.new(key, ciphermod=AES) + h2 = CMAC.new(key, ciphermod=AES) + h1.update(data) + h2.update(data_ba) + data_ba[:1] = b'\xFF' + self.assertEqual(h1.digest(), h2.digest()) + + +class MemoryViewTests(unittest.TestCase): + + def runTest(self): + + key = b"0" * 16 + data = b"\x00\x01\x02" + + def get_mv_ro(data): + return memoryview(data) + + def get_mv_rw(data): + return memoryview(bytearray(data)) + + for get_mv in (get_mv_ro, get_mv_rw): + + # Data and key can be a memoryview (during initialization) + key_mv = get_mv(key) + data_mv = get_mv(data) + + h1 = CMAC.new(key, data, ciphermod=AES) + h2 = CMAC.new(key_mv, data_mv, ciphermod=AES) + if not data_mv.readonly: + key_mv[:1] = b'\xFF' + data_mv[:1] = b'\xFF' + self.assertEqual(h1.digest(), h2.digest()) + + # Data can be a memoryview (during operation) + data_mv = get_mv(data) + + h1 = CMAC.new(key, ciphermod=AES) + h2 = CMAC.new(key, ciphermod=AES) + h1.update(data) + h2.update(data_mv) + if not data_mv.readonly: + data_mv[:1] = b'\xFF' + self.assertEqual(h1.digest(), h2.digest()) + + +class TestVectorsWycheproof(unittest.TestCase): + + def __init__(self, wycheproof_warnings): + unittest.TestCase.__init__(self) + self._wycheproof_warnings = wycheproof_warnings + self._id = "None" + + def setUp(self): + + def filter_tag(group): + return group['tagSize'] // 8 + + self.tv = load_test_vectors_wycheproof(("Hash", "wycheproof"), + "aes_cmac_test.json", + "Wycheproof CMAC", + group_tag={'tag_size': filter_tag}) + + def shortDescription(self): + return self._id + + def warn(self, tv): + if tv.warning and self._wycheproof_warnings: + import warnings + warnings.warn("Wycheproof warning: %s (%s)" % (self._id, tv.comment)) + + def test_create_mac(self, tv): + self._id = "Wycheproof MAC creation Test #" + str(tv.id) + + try: + tag = CMAC.new(tv.key, tv.msg, ciphermod=AES, mac_len=tv.tag_size).digest() + except ValueError as e: + if len(tv.key) not in (16, 24, 32) and "key length" in str(e): + return + raise e + if tv.valid: + self.assertEqual(tag, tv.tag) + self.warn(tv) + + def test_verify_mac(self, tv): + self._id = "Wycheproof MAC verification Test #" + str(tv.id) + + try: + mac = CMAC.new(tv.key, tv.msg, ciphermod=AES, mac_len=tv.tag_size) + except ValueError as e: + if len(tv.key) not in (16, 24, 32) and "key length" in str(e): + return + raise e + try: + mac.verify(tv.tag) + except ValueError: + assert not tv.valid + else: + assert tv.valid + self.warn(tv) + + def runTest(self): + + for tv in self.tv: + self.test_create_mac(tv) + self.test_verify_mac(tv) + + +def get_tests(config={}): + global test_data + import types + from .common import make_mac_tests + + wycheproof_warnings = config.get('wycheproof_warnings') + + # Add new() parameters to the back of each test vector + params_test_data = [] + for row in test_data: + t = list(row) + t[4] = dict(ciphermod=t[4]) + params_test_data.append(t) + + tests = make_mac_tests(CMAC, "CMAC", params_test_data) + tests.append(ByteArrayTests()) + tests.append(list_test_cases(TestCMAC)) + tests.append(MemoryViewTests()) + tests += [ TestVectorsWycheproof(wycheproof_warnings) ] + return tests + + +if __name__ == '__main__': + import unittest + suite = lambda: unittest.TestSuite(get_tests()) + unittest.main(defaultTest='suite') diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/test_HMAC.py b/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/test_HMAC.py new file mode 100644 index 0000000..ecec1a8 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/test_HMAC.py @@ -0,0 +1,548 @@ +# -*- coding: utf-8 -*- +# +# SelfTest/Hash/HMAC.py: Self-test for the HMAC module +# +# Written in 2008 by Dwayne C. Litzenberger +# +# =================================================================== +# The contents of this file are dedicated to the public domain. To +# the extent that dedication to the public domain is not available, +# everyone is granted a worldwide, perpetual, royalty-free, +# non-exclusive license to exercise all rights associated with the +# contents of this file for any purpose whatsoever. +# No rights are reserved. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# =================================================================== + +"""Self-test suite for Cryptodome.Hash.HMAC""" + +import unittest +from binascii import hexlify +from Cryptodome.Util.py3compat import tostr, tobytes + +from Cryptodome.Hash import (HMAC, MD5, SHA1, SHA256, + SHA224, SHA384, SHA512, + RIPEMD160, + SHA3_224, SHA3_256, SHA3_384, SHA3_512) + + +hash_modules = dict(MD5=MD5, SHA1=SHA1, SHA256=SHA256, + SHA224=SHA224, SHA384=SHA384, SHA512=SHA512, + RIPEMD160=RIPEMD160, + SHA3_224=SHA3_224, SHA3_256=SHA3_256, + SHA3_384=SHA3_384, SHA3_512=SHA3_512) + +default_hash = None + +def xl(text): + return tostr(hexlify(tobytes(text))) + +# This is a list of (key, data, results, description) tuples. +test_data = [ + ## Test vectors from RFC 2202 ## + # Test that the default hashmod is MD5 + ('0b' * 16, + '4869205468657265', + dict(default_hash='9294727a3638bb1c13f48ef8158bfc9d'), + 'default-is-MD5'), + + # Test case 1 (MD5) + ('0b' * 16, + '4869205468657265', + dict(MD5='9294727a3638bb1c13f48ef8158bfc9d'), + 'RFC 2202 #1-MD5 (HMAC-MD5)'), + + # Test case 1 (SHA1) + ('0b' * 20, + '4869205468657265', + dict(SHA1='b617318655057264e28bc0b6fb378c8ef146be00'), + 'RFC 2202 #1-SHA1 (HMAC-SHA1)'), + + # Test case 2 + ('4a656665', + '7768617420646f2079612077616e7420666f72206e6f7468696e673f', + dict(MD5='750c783e6ab0b503eaa86e310a5db738', + SHA1='effcdf6ae5eb2fa2d27416d5f184df9c259a7c79'), + 'RFC 2202 #2 (HMAC-MD5/SHA1)'), + + # Test case 3 (MD5) + ('aa' * 16, + 'dd' * 50, + dict(MD5='56be34521d144c88dbb8c733f0e8b3f6'), + 'RFC 2202 #3-MD5 (HMAC-MD5)'), + + # Test case 3 (SHA1) + ('aa' * 20, + 'dd' * 50, + dict(SHA1='125d7342b9ac11cd91a39af48aa17b4f63f175d3'), + 'RFC 2202 #3-SHA1 (HMAC-SHA1)'), + + # Test case 4 + ('0102030405060708090a0b0c0d0e0f10111213141516171819', + 'cd' * 50, + dict(MD5='697eaf0aca3a3aea3a75164746ffaa79', + SHA1='4c9007f4026250c6bc8414f9bf50c86c2d7235da'), + 'RFC 2202 #4 (HMAC-MD5/SHA1)'), + + # Test case 5 (MD5) + ('0c' * 16, + '546573742057697468205472756e636174696f6e', + dict(MD5='56461ef2342edc00f9bab995690efd4c'), + 'RFC 2202 #5-MD5 (HMAC-MD5)'), + + # Test case 5 (SHA1) + # NB: We do not implement hash truncation, so we only test the full hash here. + ('0c' * 20, + '546573742057697468205472756e636174696f6e', + dict(SHA1='4c1a03424b55e07fe7f27be1d58bb9324a9a5a04'), + 'RFC 2202 #5-SHA1 (HMAC-SHA1)'), + + # Test case 6 + ('aa' * 80, + '54657374205573696e67204c6172676572205468616e20426c6f636b2d53697a' + + '65204b6579202d2048617368204b6579204669727374', + dict(MD5='6b1ab7fe4bd7bf8f0b62e6ce61b9d0cd', + SHA1='aa4ae5e15272d00e95705637ce8a3b55ed402112'), + 'RFC 2202 #6 (HMAC-MD5/SHA1)'), + + # Test case 7 + ('aa' * 80, + '54657374205573696e67204c6172676572205468616e20426c6f636b2d53697a' + + '65204b657920616e64204c6172676572205468616e204f6e6520426c6f636b2d' + + '53697a652044617461', + dict(MD5='6f630fad67cda0ee1fb1f562db3aa53e', + SHA1='e8e99d0f45237d786d6bbaa7965c7808bbff1a91'), + 'RFC 2202 #7 (HMAC-MD5/SHA1)'), + + ## Test vectors from RFC 4231 ## + # 4.2. Test Case 1 + ('0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b', + '4869205468657265', + dict(SHA256=''' + b0344c61d8db38535ca8afceaf0bf12b + 881dc200c9833da726e9376c2e32cff7 + '''), + 'RFC 4231 #1 (HMAC-SHA256)'), + + # 4.3. Test Case 2 - Test with a key shorter than the length of the HMAC + # output. + ('4a656665', + '7768617420646f2079612077616e7420666f72206e6f7468696e673f', + dict(SHA256=''' + 5bdcc146bf60754e6a042426089575c7 + 5a003f089d2739839dec58b964ec3843 + '''), + 'RFC 4231 #2 (HMAC-SHA256)'), + + # 4.4. Test Case 3 - Test with a combined length of key and data that is + # larger than 64 bytes (= block-size of SHA-224 and SHA-256). + ('aa' * 20, + 'dd' * 50, + dict(SHA256=''' + 773ea91e36800e46854db8ebd09181a7 + 2959098b3ef8c122d9635514ced565fe + '''), + 'RFC 4231 #3 (HMAC-SHA256)'), + + # 4.5. Test Case 4 - Test with a combined length of key and data that is + # larger than 64 bytes (= block-size of SHA-224 and SHA-256). + ('0102030405060708090a0b0c0d0e0f10111213141516171819', + 'cd' * 50, + dict(SHA256=''' + 82558a389a443c0ea4cc819899f2083a + 85f0faa3e578f8077a2e3ff46729665b + '''), + 'RFC 4231 #4 (HMAC-SHA256)'), + + # 4.6. Test Case 5 - Test with a truncation of output to 128 bits. + # + # Not included because we do not implement hash truncation. + # + + # 4.7. Test Case 6 - Test with a key larger than 128 bytes (= block-size of + # SHA-384 and SHA-512). + ('aa' * 131, + '54657374205573696e67204c6172676572205468616e20426c6f636b2d53697a' + + '65204b6579202d2048617368204b6579204669727374', + dict(SHA256=''' + 60e431591ee0b67f0d8a26aacbf5b77f + 8e0bc6213728c5140546040f0ee37f54 + '''), + 'RFC 4231 #6 (HMAC-SHA256)'), + + # 4.8. Test Case 7 - Test with a key and data that is larger than 128 bytes + # (= block-size of SHA-384 and SHA-512). + ('aa' * 131, + '5468697320697320612074657374207573696e672061206c6172676572207468' + + '616e20626c6f636b2d73697a65206b657920616e642061206c61726765722074' + + '68616e20626c6f636b2d73697a6520646174612e20546865206b6579206e6565' + + '647320746f20626520686173686564206265666f7265206265696e6720757365' + + '642062792074686520484d414320616c676f726974686d2e', + dict(SHA256=''' + 9b09ffa71b942fcb27635fbcd5b0e944 + bfdc63644f0713938a7f51535c3a35e2 + '''), + 'RFC 4231 #7 (HMAC-SHA256)'), + + # Test case 8 (SHA224) + ('4a656665', + '7768617420646f2079612077616e74' + + '20666f72206e6f7468696e673f', + dict(SHA224='a30e01098bc6dbbf45690f3a7e9e6d0f8bbea2a39e6148008fd05e44'), + 'RFC 4634 8.4 SHA224 (HMAC-SHA224)'), + + # Test case 9 (SHA384) + ('4a656665', + '7768617420646f2079612077616e74' + + '20666f72206e6f7468696e673f', + dict(SHA384='af45d2e376484031617f78d2b58a6b1b9c7ef464f5a01b47e42ec3736322445e8e2240ca5e69e2c78b3239ecfab21649'), + 'RFC 4634 8.4 SHA384 (HMAC-SHA384)'), + + # Test case 10 (SHA512) + ('4a656665', + '7768617420646f2079612077616e74' + + '20666f72206e6f7468696e673f', + dict(SHA512='164b7a7bfcf819e2e395fbe73b56e0a387bd64222e831fd610270cd7ea2505549758bf75c05a994a6d034f65f8f0e6fdcaeab1a34d4a6b4b636e070a38bce737'), + 'RFC 4634 8.4 SHA512 (HMAC-SHA512)'), + + # Test case 11 (RIPEMD) + ('0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b', + xl("Hi There"), + dict(RIPEMD160='24cb4bd67d20fc1a5d2ed7732dcc39377f0a5668'), + 'RFC 2286 #1 (HMAC-RIPEMD)'), + + # Test case 12 (RIPEMD) + (xl("Jefe"), + xl("what do ya want for nothing?"), + dict(RIPEMD160='dda6c0213a485a9e24f4742064a7f033b43c4069'), + 'RFC 2286 #2 (HMAC-RIPEMD)'), + + # Test case 13 (RIPEMD) + ('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', + 'dd' * 50, + dict(RIPEMD160='b0b105360de759960ab4f35298e116e295d8e7c1'), + 'RFC 2286 #3 (HMAC-RIPEMD)'), + + # Test case 14 (RIPEMD) + ('0102030405060708090a0b0c0d0e0f10111213141516171819', + 'cd' * 50, + dict(RIPEMD160='d5ca862f4d21d5e610e18b4cf1beb97a4365ecf4'), + 'RFC 2286 #4 (HMAC-RIPEMD)'), + + # Test case 15 (RIPEMD) + ('0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c', + xl("Test With Truncation"), + dict(RIPEMD160='7619693978f91d90539ae786500ff3d8e0518e39'), + 'RFC 2286 #5 (HMAC-RIPEMD)'), + + # Test case 16 (RIPEMD) + ('aa' * 80, + xl("Test Using Larger Than Block-Size Key - Hash Key First"), + dict(RIPEMD160='6466ca07ac5eac29e1bd523e5ada7605b791fd8b'), + 'RFC 2286 #6 (HMAC-RIPEMD)'), + + # Test case 17 (RIPEMD) + ('aa' * 80, + xl("Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data"), + dict(RIPEMD160='69ea60798d71616cce5fd0871e23754cd75d5a0a'), + 'RFC 2286 #7 (HMAC-RIPEMD)'), + + # From https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/HMAC_SHA3-224.pdf + ( + '000102030405060708090a0b0c0d0e0f' + '101112131415161718191a1b', + xl('Sample message for keylenblocklen'), + dict(SHA3_224='078695eecc227c636ad31d063a15dd05a7e819a66ec6d8de1e193e59'), + 'NIST CSRC Sample #3 (SHA3-224)' + ), + + # From https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/HMAC_SHA3-256.pdf + ( + '000102030405060708090a0b0c0d0e0f'\ + '101112131415161718191a1b1c1d1e1f', + xl('Sample message for keylenblocklen'), + dict(SHA3_256='9bcf2c238e235c3ce88404e813bd2f3a97185ac6f238c63d6229a00b07974258'), + 'NIST CSRC Sample #3 (SHA3-256)' + ), + + # From https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/HMAC_SHA3-384.pdf + ( + '000102030405060708090a0b0c0d0e0f'\ + '101112131415161718191a1b1c1d1e1f' + '202122232425262728292a2b2c2d2e2f', + xl('Sample message for keylenblocklen'), + dict(SHA3_384='e5ae4c739f455279368ebf36d4f5354c95aa184c899d3870e460ebc288ef1f9470053f73f7c6da2a71bcaec38ce7d6ac'), + 'NIST CSRC Sample #3 (SHA3-384)' + ), + + # From https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/HMAC_SHA3-512.pdf + ( + '000102030405060708090a0b0c0d0e0f'\ + '101112131415161718191a1b1c1d1e1f'\ + '202122232425262728292a2b2c2d2e2f'\ + '303132333435363738393a3b3c3d3e3f', + xl('Sample message for keylenblocklen'), + dict(SHA3_512='5f464f5e5b7848e3885e49b2c385f0694985d0e38966242dc4a5fe3fea4b37d46b65ceced5dcf59438dd840bab22269f0ba7febdb9fcf74602a35666b2a32915'), + 'NIST CSRC Sample #3 (SHA3-512)' + ), + +] + + +class HMAC_Module_and_Instance_Test(unittest.TestCase): + """Test the HMAC construction and verify that it does not + matter if you initialize it with a hash module or + with an hash instance. + + See https://bugs.launchpad.net/pycrypto/+bug/1209399 + """ + + def __init__(self, hashmods): + """Initialize the test with a dictionary of hash modules + indexed by their names""" + + unittest.TestCase.__init__(self) + self.hashmods = hashmods + self.description = "" + + def shortDescription(self): + return self.description + + def runTest(self): + key = b"\x90\x91\x92\x93" * 4 + payload = b"\x00" * 100 + + for hashname, hashmod in self.hashmods.items(): + if hashmod is None: + continue + self.description = "Test HMAC in combination with " + hashname + one = HMAC.new(key, payload, hashmod).digest() + two = HMAC.new(key, payload, hashmod.new()).digest() + self.assertEqual(one, two) + + +class HMAC_None(unittest.TestCase): + + def runTest(self): + + key = b"\x04" * 20 + one = HMAC.new(key, b"", SHA1).digest() + two = HMAC.new(key, None, SHA1).digest() + self.assertEqual(one, two) + + +class ByteArrayTests(unittest.TestCase): + + def runTest(self): + + key = b"0" * 16 + data = b"\x00\x01\x02" + + # Data and key can be a bytearray (during initialization) + key_ba = bytearray(key) + data_ba = bytearray(data) + + h1 = HMAC.new(key, data) + h2 = HMAC.new(key_ba, data_ba) + key_ba[:1] = b'\xFF' + data_ba[:1] = b'\xFF' + self.assertEqual(h1.digest(), h2.digest()) + + # Data can be a bytearray (during operation) + key_ba = bytearray(key) + data_ba = bytearray(data) + + h1 = HMAC.new(key) + h2 = HMAC.new(key) + h1.update(data) + h2.update(data_ba) + data_ba[:1] = b'\xFF' + self.assertEqual(h1.digest(), h2.digest()) + + +class MemoryViewTests(unittest.TestCase): + + def runTest(self): + + key = b"0" * 16 + data = b"\x00\x01\x02" + + def get_mv_ro(data): + return memoryview(data) + + def get_mv_rw(data): + return memoryview(bytearray(data)) + + for get_mv in (get_mv_ro, get_mv_rw): + + # Data and key can be a memoryview (during initialization) + key_mv = get_mv(key) + data_mv = get_mv(data) + + h1 = HMAC.new(key, data) + h2 = HMAC.new(key_mv, data_mv) + if not data_mv.readonly: + key_mv[:1] = b'\xFF' + data_mv[:1] = b'\xFF' + self.assertEqual(h1.digest(), h2.digest()) + + # Data can be a memoryview (during operation) + data_mv = get_mv(data) + + h1 = HMAC.new(key) + h2 = HMAC.new(key) + h1.update(data) + h2.update(data_mv) + if not data_mv.readonly: + data_mv[:1] = b'\xFF' + self.assertEqual(h1.digest(), h2.digest()) + + +def get_tests(config={}): + global test_data + import types + from .common import make_mac_tests + + # A test vector contains multiple results, each one for a + # different hash algorithm. + # Here we expand each test vector into multiple ones, + # and add the relevant parameters that will be passed to new() + exp_test_data = [] + for row in test_data: + for modname in row[2].keys(): + t = list(row) + t[2] = row[2][modname] + t.append(dict(digestmod=globals()[modname])) + exp_test_data.append(t) + tests = make_mac_tests(HMAC, "HMAC", exp_test_data) + tests.append(HMAC_Module_and_Instance_Test(hash_modules)) + tests.append(HMAC_None()) + + tests.append(ByteArrayTests()) + tests.append(MemoryViewTests()) + + return tests + + +if __name__ == '__main__': + suite = lambda: unittest.TestSuite(get_tests()) + unittest.main(defaultTest='suite') diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/test_KMAC.py b/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/test_KMAC.py new file mode 100644 index 0000000..0543a4c --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/test_KMAC.py @@ -0,0 +1,346 @@ +import unittest +from binascii import unhexlify, hexlify + +from Cryptodome.Util.py3compat import tobytes +from Cryptodome.Util.strxor import strxor_c +from Cryptodome.SelfTest.st_common import list_test_cases + +from Cryptodome.Hash import KMAC128, KMAC256 + + +class KMACTest(unittest.TestCase): + + def new(self, *args, **kwargs): + return self.KMAC.new(key=b'X' * (self.minimum_key_bits // 8), *args, **kwargs) + + def test_new_positive(self): + + key = b'X' * 32 + + h = self.new() + for new_func in self.KMAC.new, h.new: + + for dbytes in range(self.minimum_bytes, 128 + 1): + hobj = new_func(key=key, mac_len=dbytes) + self.assertEqual(hobj.digest_size, dbytes) + + digest1 = new_func(key=key, data=b"\x90").digest() + digest2 = new_func(key=key).update(b"\x90").digest() + self.assertEqual(digest1, digest2) + + new_func(data=b"A", key=key, custom=b"g") + + hobj = h.new(key=key) + self.assertEqual(hobj.digest_size, self.default_bytes) + + def test_new_negative(self): + + h = self.new() + for new_func in self.KMAC.new, h.new: + self.assertRaises(ValueError, new_func, key=b'X'*32, + mac_len=0) + self.assertRaises(ValueError, new_func, key=b'X'*32, + mac_len=self.minimum_bytes - 1) + self.assertRaises(TypeError, new_func, + key=u"string") + self.assertRaises(TypeError, new_func, + data=u"string") + + def test_default_digest_size(self): + digest = self.new(data=b'abc').digest() + self.assertEqual(len(digest), self.default_bytes) + + def test_update(self): + pieces = [b"\x0A" * 200, b"\x14" * 300] + h = self.new() + h.update(pieces[0]).update(pieces[1]) + digest = h.digest() + h = self.new() + h.update(pieces[0] + pieces[1]) + self.assertEqual(h.digest(), digest) + + def test_update_negative(self): + h = self.new() + self.assertRaises(TypeError, h.update, u"string") + + def test_digest(self): + h = self.new() + digest = h.digest() + + # hexdigest does not change the state + self.assertEqual(h.digest(), digest) + # digest returns a byte string + self.assertTrue(isinstance(digest, type(b"digest"))) + + def test_update_after_digest(self): + msg = b"rrrrttt" + + # Normally, update() cannot be done after digest() + h = self.new(mac_len=32, data=msg[:4]) + dig1 = h.digest() + self.assertRaises(TypeError, h.update, dig1) + + def test_hex_digest(self): + mac = self.new() + digest = mac.digest() + hexdigest = mac.hexdigest() + + # hexdigest is equivalent to digest + self.assertEqual(hexlify(digest), tobytes(hexdigest)) + # hexdigest does not change the state + self.assertEqual(mac.hexdigest(), hexdigest) + # hexdigest returns a string + self.assertTrue(isinstance(hexdigest, type("digest"))) + + def test_verify(self): + h = self.new() + mac = h.digest() + h.verify(mac) + wrong_mac = strxor_c(mac, 255) + self.assertRaises(ValueError, h.verify, wrong_mac) + + def test_hexverify(self): + h = self.new() + mac = h.hexdigest() + h.hexverify(mac) + self.assertRaises(ValueError, h.hexverify, "4556") + + def test_oid(self): + + oid = "2.16.840.1.101.3.4.2." + self.oid_variant + h = self.new() + self.assertEqual(h.oid, oid) + + def test_bytearray(self): + + key = b'0' * 32 + data = b"\x00\x01\x02" + + # Data and key can be a bytearray (during initialization) + key_ba = bytearray(key) + data_ba = bytearray(data) + + h1 = self.KMAC.new(data=data, key=key) + h2 = self.KMAC.new(data=data_ba, key=key_ba) + key_ba[:1] = b'\xFF' + data_ba[:1] = b'\xFF' + + self.assertEqual(h1.digest(), h2.digest()) + + # Data can be a bytearray (during operation) + data_ba = bytearray(data) + + h1 = self.new() + h2 = self.new() + h1.update(data) + h2.update(data_ba) + data_ba[:1] = b'\xFF' + + self.assertEqual(h1.digest(), h2.digest()) + + def test_memoryview(self): + + key = b'0' * 32 + data = b"\x00\x01\x02" + + def get_mv_ro(data): + return memoryview(data) + + def get_mv_rw(data): + return memoryview(bytearray(data)) + + for get_mv in (get_mv_ro, get_mv_rw): + + # Data and key can be a memoryview (during initialization) + key_mv = get_mv(key) + data_mv = get_mv(data) + + h1 = self.KMAC.new(data=data, key=key) + h2 = self.KMAC.new(data=data_mv, key=key_mv) + if not data_mv.readonly: + data_mv[:1] = b'\xFF' + key_mv[:1] = b'\xFF' + + self.assertEqual(h1.digest(), h2.digest()) + + # Data can be a memoryview (during operation) + data_mv = get_mv(data) + + h1 = self.new() + h2 = self.new() + h1.update(data) + h2.update(data_mv) + if not data_mv.readonly: + data_mv[:1] = b'\xFF' + + self.assertEqual(h1.digest(), h2.digest()) + + +class KMAC128Test(KMACTest): + + KMAC = KMAC128 + + minimum_key_bits = 128 + + minimum_bytes = 8 + default_bytes = 64 + + oid_variant = "19" + + +class KMAC256Test(KMACTest): + + KMAC = KMAC256 + + minimum_key_bits = 256 + + minimum_bytes = 8 + default_bytes = 64 + + oid_variant = "20" + + +class NISTExampleTestVectors(unittest.TestCase): + + # https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/KMAC_samples.pdf + test_data = [ + ( + "40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F" + "50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F", + "00 01 02 03", + "", + "E5 78 0B 0D 3E A6 F7 D3 A4 29 C5 70 6A A4 3A 00" + "FA DB D7 D4 96 28 83 9E 31 87 24 3F 45 6E E1 4E", + "Sample #1 NIST", + KMAC128 + ), + ( + "40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F" + "50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F", + "00 01 02 03", + "My Tagged Application", + "3B 1F BA 96 3C D8 B0 B5 9E 8C 1A 6D 71 88 8B 71" + "43 65 1A F8 BA 0A 70 70 C0 97 9E 28 11 32 4A A5", + "Sample #2 NIST", + KMAC128 + ), + ( + "40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F" + "50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F", + "00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F" + "10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F" + "20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F" + "30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F" + "40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F" + "50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F" + "60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F" + "70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F" + "80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F" + "90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F" + "A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF" + "B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF" + "C0 C1 C2 C3 C4 C5 C6 C7", + "My Tagged Application", + "1F 5B 4E 6C CA 02 20 9E 0D CB 5C A6 35 B8 9A 15" + "E2 71 EC C7 60 07 1D FD 80 5F AA 38 F9 72 92 30", + "Sample #3 NIST", + KMAC128 + ), + ( + "40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F" + "50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F", + "00 01 02 03", + "My Tagged Application", + "20 C5 70 C3 13 46 F7 03 C9 AC 36 C6 1C 03 CB 64" + "C3 97 0D 0C FC 78 7E 9B 79 59 9D 27 3A 68 D2 F7" + "F6 9D 4C C3 DE 9D 10 4A 35 16 89 F2 7C F6 F5 95" + "1F 01 03 F3 3F 4F 24 87 10 24 D9 C2 77 73 A8 DD", + "Sample #4 NIST", + KMAC256 + ), + ( + "40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F" + "50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F", + "00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F" + "10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F" + "20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F" + "30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F" + "40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F" + "50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F" + "60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F" + "70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F" + "80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F" + "90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F" + "A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF" + "B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF" + "C0 C1 C2 C3 C4 C5 C6 C7", + "", + "75 35 8C F3 9E 41 49 4E 94 97 07 92 7C EE 0A F2" + "0A 3F F5 53 90 4C 86 B0 8F 21 CC 41 4B CF D6 91" + "58 9D 27 CF 5E 15 36 9C BB FF 8B 9A 4C 2E B1 78" + "00 85 5D 02 35 FF 63 5D A8 25 33 EC 6B 75 9B 69", + "Sample #5 NIST", + KMAC256 + ), + ( + "40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F" + "50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F", + "00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F" + "10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F" + "20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F" + "30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F" + "40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F" + "50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F" + "60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F" + "70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F" + "80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F" + "90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F" + "A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF" + "B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF" + "C0 C1 C2 C3 C4 C5 C6 C7", + "My Tagged Application", + "B5 86 18 F7 1F 92 E1 D5 6C 1B 8C 55 DD D7 CD 18" + "8B 97 B4 CA 4D 99 83 1E B2 69 9A 83 7D A2 E4 D9" + "70 FB AC FD E5 00 33 AE A5 85 F1 A2 70 85 10 C3" + "2D 07 88 08 01 BD 18 28 98 FE 47 68 76 FC 89 65", + "Sample #6 NIST", + KMAC256 + ), + ] + + def setUp(self): + td = [] + for key, data, custom, mac, text, module in self.test_data: + ni = ( + unhexlify(key.replace(" ", "")), + unhexlify(data.replace(" ", "")), + custom.encode(), + unhexlify(mac.replace(" ", "")), + text, + module + ) + td.append(ni) + self.test_data = td + + def runTest(self): + + for key, data, custom, mac, text, module in self.test_data: + h = module.new(data=data, key=key, custom=custom, mac_len=len(mac)) + mac_tag = h.digest() + self.assertEqual(mac_tag, mac, msg=text) + + +def get_tests(config={}): + tests = [] + + tests += list_test_cases(KMAC128Test) + tests += list_test_cases(KMAC256Test) + tests.append(NISTExampleTestVectors()) + + return tests + + +if __name__ == '__main__': + def suite(): + return unittest.TestSuite(get_tests()) + unittest.main(defaultTest='suite') diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/test_KangarooTwelve.py b/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/test_KangarooTwelve.py new file mode 100644 index 0000000..c9ad363 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/test_KangarooTwelve.py @@ -0,0 +1,367 @@ +# =================================================================== +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# =================================================================== + +"""Self-test suite for Cryptodome.Hash.KangarooTwelve""" + +import unittest +from binascii import unhexlify + +from Cryptodome.SelfTest.st_common import list_test_cases + +from Cryptodome.Hash import KangarooTwelve as K12 +from Cryptodome.Util.py3compat import b, bchr + + +class KangarooTwelveTest(unittest.TestCase): + + def test_length_encode(self): + self.assertEqual(K12._length_encode(0), b'\x00') + self.assertEqual(K12._length_encode(12), b'\x0C\x01') + self.assertEqual(K12._length_encode(65538), b'\x01\x00\x02\x03') + + def test_new_positive(self): + + xof1 = K12.new() + xof2 = K12.new(data=b("90")) + xof3 = K12.new().update(b("90")) + + self.assertNotEqual(xof1.read(10), xof2.read(10)) + xof3.read(10) + self.assertEqual(xof2.read(10), xof3.read(10)) + + xof1 = K12.new() + ref = xof1.read(10) + xof2 = K12.new(custom=b("")) + xof3 = K12.new(custom=b("foo")) + + self.assertEqual(ref, xof2.read(10)) + self.assertNotEqual(ref, xof3.read(10)) + + xof1 = K12.new(custom=b("foo")) + xof2 = K12.new(custom=b("foo"), data=b("90")) + xof3 = K12.new(custom=b("foo")).update(b("90")) + + self.assertNotEqual(xof1.read(10), xof2.read(10)) + xof3.read(10) + self.assertEqual(xof2.read(10), xof3.read(10)) + + def test_update(self): + pieces = [bchr(10) * 200, bchr(20) * 300] + h = K12.new() + h.update(pieces[0]).update(pieces[1]) + digest = h.read(10) + h = K12.new() + h.update(pieces[0] + pieces[1]) + self.assertEqual(h.read(10), digest) + + def test_update_negative(self): + h = K12.new() + self.assertRaises(TypeError, h.update, u"string") + + def test_digest(self): + h = K12.new() + digest = h.read(90) + + # read returns a byte string of the right length + self.assertTrue(isinstance(digest, type(b("digest")))) + self.assertEqual(len(digest), 90) + + def test_update_after_read(self): + mac = K12.new() + mac.update(b("rrrr")) + mac.read(90) + self.assertRaises(TypeError, mac.update, b("ttt")) + + +def txt2bin(txt): + clean = txt.replace(" ", "").replace("\n", "").replace("\r", "") + return unhexlify(clean) + + +def ptn(n): + res = bytearray(n) + pattern = b"".join([bchr(x) for x in range(0, 0xFB)]) + for base in range(0, n - 0xFB, 0xFB): + res[base:base + 0xFB] = pattern + remain = n % 0xFB + if remain: + base = (n // 0xFB) * 0xFB + res[base:] = pattern[:remain] + assert(len(res) == n) + return res + + +def chunked(source, size): + for i in range(0, len(source), size): + yield source[i:i+size] + + +class KangarooTwelveTV(unittest.TestCase): + + # https://github.com/XKCP/XKCP/blob/master/tests/TestVectors/KangarooTwelve.txt + + def test_zero_1(self): + tv = """1A C2 D4 50 FC 3B 42 05 D1 9D A7 BF CA 1B 37 51 + 3C 08 03 57 7A C7 16 7F 06 FE 2C E1 F0 EF 39 E5""" + + btv = txt2bin(tv) + res = K12.new().read(32) + self.assertEqual(res, btv) + + def test_zero_2(self): + tv = """1A C2 D4 50 FC 3B 42 05 D1 9D A7 BF CA 1B 37 51 + 3C 08 03 57 7A C7 16 7F 06 FE 2C E1 F0 EF 39 E5 + 42 69 C0 56 B8 C8 2E 48 27 60 38 B6 D2 92 96 6C + C0 7A 3D 46 45 27 2E 31 FF 38 50 81 39 EB 0A 71""" + + btv = txt2bin(tv) + res = K12.new().read(64) + self.assertEqual(res, btv) + + def test_zero_3(self): + tv = """E8 DC 56 36 42 F7 22 8C 84 68 4C 89 84 05 D3 A8 + 34 79 91 58 C0 79 B1 28 80 27 7A 1D 28 E2 FF 6D""" + + btv = txt2bin(tv) + res = K12.new().read(10032) + self.assertEqual(res[-32:], btv) + + def test_ptn_1(self): + tv = """2B DA 92 45 0E 8B 14 7F 8A 7C B6 29 E7 84 A0 58 + EF CA 7C F7 D8 21 8E 02 D3 45 DF AA 65 24 4A 1F""" + + btv = txt2bin(tv) + res = K12.new(data=ptn(1)).read(32) + self.assertEqual(res, btv) + + def test_ptn_17(self): + tv = """6B F7 5F A2 23 91 98 DB 47 72 E3 64 78 F8 E1 9B + 0F 37 12 05 F6 A9 A9 3A 27 3F 51 DF 37 12 28 88""" + + btv = txt2bin(tv) + res = K12.new(data=ptn(17)).read(32) + self.assertEqual(res, btv) + + def test_ptn_17_2(self): + tv = """0C 31 5E BC DE DB F6 14 26 DE 7D CF 8F B7 25 D1 + E7 46 75 D7 F5 32 7A 50 67 F3 67 B1 08 EC B6 7C""" + + btv = txt2bin(tv) + res = K12.new(data=ptn(17**2)).read(32) + self.assertEqual(res, btv) + + def test_ptn_17_3(self): + tv = """CB 55 2E 2E C7 7D 99 10 70 1D 57 8B 45 7D DF 77 + 2C 12 E3 22 E4 EE 7F E4 17 F9 2C 75 8F 0D 59 D0""" + + btv = txt2bin(tv) + res = K12.new(data=ptn(17**3)).read(32) + self.assertEqual(res, btv) + + def test_ptn_17_4(self): + tv = """87 01 04 5E 22 20 53 45 FF 4D DA 05 55 5C BB 5C + 3A F1 A7 71 C2 B8 9B AE F3 7D B4 3D 99 98 B9 FE""" + + btv = txt2bin(tv) + data = ptn(17**4) + + # All at once + res = K12.new(data=data).read(32) + self.assertEqual(res, btv) + + # Byte by byte + k12 = K12.new() + for x in data: + k12.update(bchr(x)) + res = k12.read(32) + self.assertEqual(res, btv) + + # Chunks of various prime sizes + for chunk_size in (13, 17, 19, 23, 31): + k12 = K12.new() + for x in chunked(data, chunk_size): + k12.update(x) + res = k12.read(32) + self.assertEqual(res, btv) + + def test_ptn_17_5(self): + tv = """84 4D 61 09 33 B1 B9 96 3C BD EB 5A E3 B6 B0 5C + C7 CB D6 7C EE DF 88 3E B6 78 A0 A8 E0 37 16 82""" + + btv = txt2bin(tv) + data = ptn(17**5) + + # All at once + res = K12.new(data=data).read(32) + self.assertEqual(res, btv) + + # Chunks + k12 = K12.new() + for chunk in chunked(data, 8192): + k12.update(chunk) + res = k12.read(32) + self.assertEqual(res, btv) + + def test_ptn_17_6(self): + tv = """3C 39 07 82 A8 A4 E8 9F A6 36 7F 72 FE AA F1 32 + 55 C8 D9 58 78 48 1D 3C D8 CE 85 F5 8E 88 0A F8""" + + btv = txt2bin(tv) + data = ptn(17**6) + + # All at once + res = K12.new(data=data).read(32) + self.assertEqual(res, btv) + + def test_ptn_c_1(self): + tv = """FA B6 58 DB 63 E9 4A 24 61 88 BF 7A F6 9A 13 30 + 45 F4 6E E9 84 C5 6E 3C 33 28 CA AF 1A A1 A5 83""" + + btv = txt2bin(tv) + custom = ptn(1) + + # All at once + res = K12.new(custom=custom).read(32) + self.assertEqual(res, btv) + + def test_ptn_c_41(self): + tv = """D8 48 C5 06 8C ED 73 6F 44 62 15 9B 98 67 FD 4C + 20 B8 08 AC C3 D5 BC 48 E0 B0 6B A0 A3 76 2E C4""" + + btv = txt2bin(tv) + custom = ptn(41) + + # All at once + res = K12.new(data=b'\xFF', custom=custom).read(32) + self.assertEqual(res, btv) + + def test_ptn_c_41_2(self): + tv = """C3 89 E5 00 9A E5 71 20 85 4C 2E 8C 64 67 0A C0 + 13 58 CF 4C 1B AF 89 44 7A 72 42 34 DC 7C ED 74""" + + btv = txt2bin(tv) + custom = ptn(41**2) + + # All at once + res = K12.new(data=b'\xFF' * 3, custom=custom).read(32) + self.assertEqual(res, btv) + + def test_ptn_c_41_3(self): + tv = """75 D2 F8 6A 2E 64 45 66 72 6B 4F BC FC 56 57 B9 + DB CF 07 0C 7B 0D CA 06 45 0A B2 91 D7 44 3B CF""" + + btv = txt2bin(tv) + custom = ptn(41**3) + + # All at once + res = K12.new(data=b'\xFF' * 7, custom=custom).read(32) + self.assertEqual(res, btv) + + # https://datatracker.ietf.org/doc/draft-irtf-cfrg-kangarootwelve/ + + def test_ptn_8191(self): + tv = """1B 57 76 36 F7 23 64 3E 99 0C C7 D6 A6 59 83 74 + 36 FD 6A 10 36 26 60 0E B8 30 1C D1 DB E5 53 D6""" + + btv = txt2bin(tv) + + # All at once + res = K12.new(data=ptn(8191)).read(32) + self.assertEqual(res, btv) + + def test_ptn_8192(self): + tv = """48 F2 56 F6 77 2F 9E DF B6 A8 B6 61 EC 92 DC 93 + B9 5E BD 05 A0 8A 17 B3 9A E3 49 08 70 C9 26 C3""" + + btv = txt2bin(tv) + + # All at once + res = K12.new(data=ptn(8192)).read(32) + self.assertEqual(res, btv) + + def test_ptn_8192_8189(self): + tv = """3E D1 2F 70 FB 05 DD B5 86 89 51 0A B3 E4 D2 3C + 6C 60 33 84 9A A0 1E 1D 8C 22 0A 29 7F ED CD 0B""" + + btv = txt2bin(tv) + + # All at once + res = K12.new(data=ptn(8192), custom=ptn(8189)).read(32) + self.assertEqual(res, btv) + + def test_ptn_8192_8190(self): + tv = """6A 7C 1B 6A 5C D0 D8 C9 CA 94 3A 4A 21 6C C6 46 + 04 55 9A 2E A4 5F 78 57 0A 15 25 3D 67 BA 00 AE""" + + btv = txt2bin(tv) + + # All at once + res = K12.new(data=ptn(8192), custom=ptn(8190)).read(32) + self.assertEqual(res, btv) + + ### + + def test_1(self): + tv = "fd608f91d81904a9916e78a18f65c157a78d63f93d8f6367db0524526a5ea2bb" + + btv = txt2bin(tv) + res = K12.new(data=b'', custom=ptn(100)).read(32) + self.assertEqual(res, btv) + + def test_2(self): + tv4 = "5a4ec9a649f81916d4ce1553492962f7868abf8dd1ceb2f0cb3682ea95cda6a6" + tv3 = "441688fe4fe4ae9425eb3105eb445eb2b3a6f67b66eff8e74ebfbc49371f6d4c" + tv2 = "17269a57759af0214c84a0fd9bc851f4d95f80554cfed4e7da8a6ee1ff080131" + tv1 = "33826990c09dc712ba7224f0d9be319e2720de95a4c1afbd2211507dae1c703a" + tv0 = "9f4d3aba908ddc096e4d3a71da954f917b9752f05052b9d26d916a6fbc75bf3e" + + res = K12.new(data=b'A' * (8192 - 4), custom=b'B').read(32) + self.assertEqual(res, txt2bin(tv4)) + + res = K12.new(data=b'A' * (8192 - 3), custom=b'B').read(32) + self.assertEqual(res, txt2bin(tv3)) + + res = K12.new(data=b'A' * (8192 - 2), custom=b'B').read(32) + self.assertEqual(res, txt2bin(tv2)) + + res = K12.new(data=b'A' * (8192 - 1), custom=b'B').read(32) + self.assertEqual(res, txt2bin(tv1)) + + res = K12.new(data=b'A' * (8192 - 0), custom=b'B').read(32) + self.assertEqual(res, txt2bin(tv0)) + + +def get_tests(config={}): + tests = [] + tests += list_test_cases(KangarooTwelveTest) + tests += list_test_cases(KangarooTwelveTV) + return tests + + +if __name__ == '__main__': + def suite(): + return unittest.TestSuite(get_tests()) + unittest.main(defaultTest='suite') diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/test_MD2.py b/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/test_MD2.py new file mode 100644 index 0000000..beae38a --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/test_MD2.py @@ -0,0 +1,62 @@ +# -*- coding: utf-8 -*- +# +# SelfTest/Hash/MD2.py: Self-test for the MD2 hash function +# +# Written in 2008 by Dwayne C. Litzenberger +# +# =================================================================== +# The contents of this file are dedicated to the public domain. To +# the extent that dedication to the public domain is not available, +# everyone is granted a worldwide, perpetual, royalty-free, +# non-exclusive license to exercise all rights associated with the +# contents of this file for any purpose whatsoever. +# No rights are reserved. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# =================================================================== + +"""Self-test suite for Cryptodome.Hash.MD2""" + +from Cryptodome.Util.py3compat import * + +# This is a list of (expected_result, input[, description]) tuples. +test_data = [ + # Test vectors from RFC 1319 + ('8350e5a3e24c153df2275c9f80692773', '', "'' (empty string)"), + ('32ec01ec4a6dac72c0ab96fb34c0b5d1', 'a'), + ('da853b0d3f88d99b30283a69e6ded6bb', 'abc'), + ('ab4f496bfb2a530b219ff33031fe06b0', 'message digest'), + + ('4e8ddff3650292ab5a4108c3aa47940b', 'abcdefghijklmnopqrstuvwxyz', + 'a-z'), + + ('da33def2a42df13975352846c30338cd', + 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789', + 'A-Z, a-z, 0-9'), + + ('d5976f79d83d3a0dc9806c3c66f3efd8', + '1234567890123456789012345678901234567890123456' + + '7890123456789012345678901234567890', + "'1234567890' * 8"), +] + +def get_tests(config={}): + from Cryptodome.Hash import MD2 + from .common import make_hash_tests + return make_hash_tests(MD2, "MD2", test_data, + digest_size=16, + oid="1.2.840.113549.2.2") + +if __name__ == '__main__': + import unittest + suite = lambda: unittest.TestSuite(get_tests()) + unittest.main(defaultTest='suite') + +# vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/test_MD4.py b/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/test_MD4.py new file mode 100644 index 0000000..41de977 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/test_MD4.py @@ -0,0 +1,64 @@ +# -*- coding: utf-8 -*- +# +# SelfTest/Hash/MD4.py: Self-test for the MD4 hash function +# +# Written in 2008 by Dwayne C. Litzenberger +# +# =================================================================== +# The contents of this file are dedicated to the public domain. To +# the extent that dedication to the public domain is not available, +# everyone is granted a worldwide, perpetual, royalty-free, +# non-exclusive license to exercise all rights associated with the +# contents of this file for any purpose whatsoever. +# No rights are reserved. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# =================================================================== + +"""Self-test suite for Cryptodome.Hash.MD4""" + +__revision__ = "$Id$" + +from Cryptodome.Util.py3compat import * + +# This is a list of (expected_result, input[, description]) tuples. +test_data = [ + # Test vectors from RFC 1320 + ('31d6cfe0d16ae931b73c59d7e0c089c0', '', "'' (empty string)"), + ('bde52cb31de33e46245e05fbdbd6fb24', 'a'), + ('a448017aaf21d8525fc10ae87aa6729d', 'abc'), + ('d9130a8164549fe818874806e1c7014b', 'message digest'), + + ('d79e1c308aa5bbcdeea8ed63df412da9', 'abcdefghijklmnopqrstuvwxyz', + 'a-z'), + + ('043f8582f241db351ce627e153e7f0e4', + 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789', + 'A-Z, a-z, 0-9'), + + ('e33b4ddc9c38f2199c3e7b164fcc0536', + '1234567890123456789012345678901234567890123456' + + '7890123456789012345678901234567890', + "'1234567890' * 8"), +] + +def get_tests(config={}): + from Cryptodome.Hash import MD4 + from .common import make_hash_tests + return make_hash_tests(MD4, "MD4", test_data, + digest_size=16, + oid="1.2.840.113549.2.4") + +if __name__ == '__main__': + import unittest + suite = lambda: unittest.TestSuite(get_tests()) + unittest.main(defaultTest='suite') + +# vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/test_MD5.py b/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/test_MD5.py new file mode 100644 index 0000000..3f7a005 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/test_MD5.py @@ -0,0 +1,94 @@ +# -*- coding: utf-8 -*- +# +# SelfTest/Hash/MD5.py: Self-test for the MD5 hash function +# +# Written in 2008 by Dwayne C. Litzenberger +# +# =================================================================== +# The contents of this file are dedicated to the public domain. To +# the extent that dedication to the public domain is not available, +# everyone is granted a worldwide, perpetual, royalty-free, +# non-exclusive license to exercise all rights associated with the +# contents of this file for any purpose whatsoever. +# No rights are reserved. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# =================================================================== + +"""Self-test suite for Cryptodome.Hash.MD5""" + +from Cryptodome.Util.py3compat import * +from Cryptodome.Hash import MD5 +from binascii import unhexlify +import unittest +from Cryptodome.SelfTest.st_common import list_test_cases + + +# This is a list of (expected_result, input[, description]) tuples. +test_data = [ + # Test vectors from RFC 1321 + ('d41d8cd98f00b204e9800998ecf8427e', '', "'' (empty string)"), + ('0cc175b9c0f1b6a831c399e269772661', 'a'), + ('900150983cd24fb0d6963f7d28e17f72', 'abc'), + ('f96b697d7cb7938d525a2f31aaf161d0', 'message digest'), + + ('c3fcd3d76192e4007dfb496cca67e13b', 'abcdefghijklmnopqrstuvwxyz', + 'a-z'), + + ('d174ab98d277d9f5a5611c2c9f419d9f', + 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789', + 'A-Z, a-z, 0-9'), + + ('57edf4a22be3c955ac49da2e2107b67a', + '1234567890123456789012345678901234567890123456' + + '7890123456789012345678901234567890', + "'1234567890' * 8"), + + # https://www.cosic.esat.kuleuven.be/nessie/testvectors/hash/md5/Md5-128.unverified.test-vectors + ('57EDF4A22BE3C955AC49DA2E2107B67A', '1234567890' * 8, 'Set 1, vector #7'), + ('7707D6AE4E027C70EEA2A935C2296F21', 'a'*1000000, 'Set 1, vector #8'), +] + + +class Md5IterTest(unittest.TestCase): + + def runTest(self): + message = b("\x00") * 16 + result1 = "4AE71336E44BF9BF79D2752E234818A5".lower() + result2 = "1A83F51285E4D89403D00C46EF8508FE".lower() + + h = MD5.new(message) + message = h.digest() + self.assertEqual(h.hexdigest(), result1) + + for _ in range(99999): + h = MD5.new(message) + message = h.digest() + + self.assertEqual(h.hexdigest(), result2) + + +def get_tests(config={}): + from .common import make_hash_tests + + tests = make_hash_tests(MD5, "MD5", test_data, + digest_size=16, + oid="1.2.840.113549.2.5") + if config.get('slow_tests'): + tests += [ Md5IterTest() ] + return tests + + +if __name__ == '__main__': + import unittest + suite = lambda: unittest.TestSuite(get_tests()) + unittest.main(defaultTest='suite') + +# vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/test_Poly1305.py b/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/test_Poly1305.py new file mode 100644 index 0000000..19cacb4 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/test_Poly1305.py @@ -0,0 +1,542 @@ +# +# SelfTest/Hash/test_Poly1305.py: Self-test for the Poly1305 module +# +# =================================================================== +# +# Copyright (c) 2018, Helder Eijs +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# =================================================================== + +"""Self-test suite for Cryptodome.Hash._Poly1305""" + +import json +import unittest +from binascii import unhexlify, hexlify + +from .common import make_mac_tests +from Cryptodome.SelfTest.st_common import list_test_cases + +from Cryptodome.Hash import Poly1305 +from Cryptodome.Cipher import AES, ChaCha20 + +from Cryptodome.Util.py3compat import tobytes +from Cryptodome.Util.strxor import strxor_c + +# This is a list of (r+s keypair, data, result, description, keywords) tuples. +test_data_basic = [ + ( + "85d6be7857556d337f4452fe42d506a80103808afb0db2fd4abff6af4149f51b", + hexlify(b"Cryptographic Forum Research Group").decode(), + "a8061dc1305136c6c22b8baf0c0127a9", + "RFC7539" + ), + ( + "746869732069732033322d62797465206b657920666f7220506f6c7931333035", + "0000000000000000000000000000000000000000000000000000000000000000", + "49ec78090e481ec6c26b33b91ccc0307", + "https://tools.ietf.org/html/draft-agl-tls-chacha20poly1305-00#section-7 A", + ), + ( + "746869732069732033322d62797465206b657920666f7220506f6c7931333035", + "48656c6c6f20776f726c6421", + "a6f745008f81c916a20dcc74eef2b2f0", + "https://tools.ietf.org/html/draft-agl-tls-chacha20poly1305-00#section-7 B", + ), + ( + "746869732069732033322d62797465206b657920666f7220506f6c7931333035", + "", + "6b657920666f7220506f6c7931333035", + "Generated with pure Python", + ), + ( + "746869732069732033322d62797465206b657920666f7220506f6c7931333035", + "FF", + "f7e4e0ef4c46d106219da3d1bdaeb3ff", + "Generated with pure Python", + ), + ( + "746869732069732033322d62797465206b657920666f7220506f6c7931333035", + "FF00", + "7471eceeb22988fc936da1d6e838b70e", + "Generated with pure Python", + ), + ( + "746869732069732033322d62797465206b657920666f7220506f6c7931333035", + "AA" * 17, + "32590bc07cb2afaccca3f67f122975fe", + "Generated with pure Python", + ), + ( + "00" * 32, + "00" * 64, + "00" * 16, + "RFC7539 A.3 #1", + ), + ( + "0000000000000000000000000000000036e5f6b5c5e06070f0efca96227a863e", + hexlify( + b"Any submission t" + b"o the IETF inten" + b"ded by the Contr" + b"ibutor for publi" + b"cation as all or" + b" part of an IETF" + b" Internet-Draft " + b"or RFC and any s" + b"tatement made wi" + b"thin the context" + b" of an IETF acti" + b"vity is consider" + b"ed an \"IETF Cont" + b"ribution\". Such " + b"statements inclu" + b"de oral statemen" + b"ts in IETF sessi" + b"ons, as well as " + b"written and elec" + b"tronic communica" + b"tions made at an" + b"y time or place," + b" which are addre" + b"ssed to").decode(), + "36e5f6b5c5e06070f0efca96227a863e", + "RFC7539 A.3 #2", + ), + ( + "36e5f6b5c5e06070f0efca96227a863e00000000000000000000000000000000", + hexlify( + b"Any submission t" + b"o the IETF inten" + b"ded by the Contr" + b"ibutor for publi" + b"cation as all or" + b" part of an IETF" + b" Internet-Draft " + b"or RFC and any s" + b"tatement made wi" + b"thin the context" + b" of an IETF acti" + b"vity is consider" + b"ed an \"IETF Cont" + b"ribution\". Such " + b"statements inclu" + b"de oral statemen" + b"ts in IETF sessi" + b"ons, as well as " + b"written and elec" + b"tronic communica" + b"tions made at an" + b"y time or place," + b" which are addre" + b"ssed to").decode(), + "f3477e7cd95417af89a6b8794c310cf0", + "RFC7539 A.3 #3", + ), + ( + "1c9240a5eb55d38af333888604f6b5f0473917c1402b80099dca5cbc207075c0", + "2754776173206272696c6c69672c2061" + "6e642074686520736c6974687920746f" + "7665730a446964206779726520616e64" + "2067696d626c6520696e207468652077" + "6162653a0a416c6c206d696d73792077" + "6572652074686520626f726f676f7665" + "732c0a416e6420746865206d6f6d6520" + "7261746873206f757467726162652e", + "4541669a7eaaee61e708dc7cbcc5eb62", + "RFC7539 A.3 #4", + ), + ( + "02" + "00" * 31, + "FF" * 16, + "03" + "00" * 15, + "RFC7539 A.3 #5", + ), + ( + "02" + "00" * 15 + "FF" * 16, + "02" + "00" * 15, + "03" + "00" * 15, + "RFC7539 A.3 #6", + ), + ( + "01" + "00" * 31, + "FF" * 16 + "F0" + "FF" * 15 + "11" + "00" * 15, + "05" + "00" * 15, + "RFC7539 A.3 #7", + ), + ( + "01" + "00" * 31, + "FF" * 16 + "FB" + "FE" * 15 + "01" * 16, + "00" * 16, + "RFC7539 A.3 #8", + ), + ( + "02" + "00" * 31, + "FD" + "FF" * 15, + "FA" + "FF" * 15, + "RFC7539 A.3 #9", + ), + ( + "01 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00" + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", + "E3 35 94 D7 50 5E 43 B9 00 00 00 00 00 00 00 00" + "33 94 D7 50 5E 43 79 CD 01 00 00 00 00 00 00 00" + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00" + "01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", + "14 00 00 00 00 00 00 00 55 00 00 00 00 00 00 00", + "RFC7539 A.3 #10", + ), + ( + "01 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00" + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", + "E3 35 94 D7 50 5E 43 B9 00 00 00 00 00 00 00 00" + "33 94 D7 50 5E 43 79 CD 01 00 00 00 00 00 00 00" + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", + "13" + "00" * 15, + "RFC7539 A.3 #11", + ), +] + +# This is a list of (key(k+r), data, result, description, keywords) tuples. +test_data_aes = [ + ( + "ec074c835580741701425b623235add6851fc40c3467ac0be05cc20404f3f700", + "f3f6", + "f4c633c3044fc145f84f335cb81953de", + "http://cr.yp.to/mac/poly1305-20050329.pdf", + { 'cipher':AES, 'nonce':unhexlify("fb447350c4e868c52ac3275cf9d4327e") } + ), + ( + "75deaa25c09f208e1dc4ce6b5cad3fbfa0f3080000f46400d0c7e9076c834403", + "", + "dd3fab2251f11ac759f0887129cc2ee7", + "http://cr.yp.to/mac/poly1305-20050329.pdf", + { 'cipher':AES, 'nonce':unhexlify("61ee09218d29b0aaed7e154a2c5509cc") } + ), + ( + "6acb5f61a7176dd320c5c1eb2edcdc7448443d0bb0d21109c89a100b5ce2c208", + "663cea190ffb83d89593f3f476b6bc24" + "d7e679107ea26adb8caf6652d0656136", + "0ee1c16bb73f0f4fd19881753c01cdbe", + "http://cr.yp.to/mac/poly1305-20050329.pdf", + { 'cipher':AES, 'nonce':unhexlify("ae212a55399729595dea458bc621ff0e") } + ), + ( + "e1a5668a4d5b66a5f68cc5424ed5982d12976a08c4426d0ce8a82407c4f48207", + "ab0812724a7f1e342742cbed374d94d1" + "36c6b8795d45b3819830f2c04491faf0" + "990c62e48b8018b2c3e4a0fa3134cb67" + "fa83e158c994d961c4cb21095c1bf9", + "5154ad0d2cb26e01274fc51148491f1b", + "http://cr.yp.to/mac/poly1305-20050329.pdf", + { 'cipher':AES, 'nonce':unhexlify("9ae831e743978d3a23527c7128149e3a") } + ), +] + +test_data_chacha20 = [ + ( + "00" * 32, + "FF" * 15, + "13cc5bbadc36b03a5163928f0bcb65aa", + "RFC7539 A.4 #1", + { 'cipher':ChaCha20, 'nonce':unhexlify("00" * 12) } + ), + ( + "00" * 31 + "01", + "FF" * 15, + "0baf33c1d6df211bdd50a6767e98e00a", + "RFC7539 A.4 #2", + { 'cipher':ChaCha20, 'nonce':unhexlify("00" * 11 + "02") } + ), + ( + "1c 92 40 a5 eb 55 d3 8a f3 33 88 86 04 f6 b5 f0" + "47 39 17 c1 40 2b 80 09 9d ca 5c bc 20 70 75 c0", + "FF" * 15, + "e8b4c6db226cd8939e65e02eebf834ce", + "RFC7539 A.4 #3", + { 'cipher':ChaCha20, 'nonce':unhexlify("00" * 11 + "02") } + ), + ( + "1c 92 40 a5 eb 55 d3 8a f3 33 88 86 04 f6 b5 f0" + "47 39 17 c1 40 2b 80 09 9d ca 5c bc 20 70 75 c0", + "f3 33 88 86 00 00 00 00 00 00 4e 91 00 00 00 00" + "64 a0 86 15 75 86 1a f4 60 f0 62 c7 9b e6 43 bd" + "5e 80 5c fd 34 5c f3 89 f1 08 67 0a c7 6c 8c b2" + "4c 6c fc 18 75 5d 43 ee a0 9e e9 4e 38 2d 26 b0" + "bd b7 b7 3c 32 1b 01 00 d4 f0 3b 7f 35 58 94 cf" + "33 2f 83 0e 71 0b 97 ce 98 c8 a8 4a bd 0b 94 81" + "14 ad 17 6e 00 8d 33 bd 60 f9 82 b1 ff 37 c8 55" + "97 97 a0 6e f4 f0 ef 61 c1 86 32 4e 2b 35 06 38" + "36 06 90 7b 6a 7c 02 b0 f9 f6 15 7b 53 c8 67 e4" + "b9 16 6c 76 7b 80 4d 46 a5 9b 52 16 cd e7 a4 e9" + "90 40 c5 a4 04 33 22 5e e2 82 a1 b0 a0 6c 52 3e" + "af 45 34 d7 f8 3f a1 15 5b 00 47 71 8c bc 54 6a" + "0d 07 2b 04 b3 56 4e ea 1b 42 22 73 f5 48 27 1a" + "0b b2 31 60 53 fa 76 99 19 55 eb d6 31 59 43 4e" + "ce bb 4e 46 6d ae 5a 10 73 a6 72 76 27 09 7a 10" + "49 e6 17 d9 1d 36 10 94 fa 68 f0 ff 77 98 71 30" + "30 5b ea ba 2e da 04 df 99 7b 71 4d 6c 6f 2c 29" + "a6 ad 5c b4 02 2b 02 70 9b 00 00 00 00 00 00 00" + "0c 00 00 00 00 00 00 00 09 01 00 00 00 00 00 00", + "ee ad 9d 67 89 0c bb 22 39 23 36 fe a1 85 1f 38", + "RFC7539 A.5", + { 'cipher':ChaCha20, 'nonce':unhexlify("000000000102030405060708") } + ), +] + + +class Poly1305Test_AES(unittest.TestCase): + + key = b'\x11' * 32 + + def test_new_positive(self): + + data = b'r' * 100 + + h1 = Poly1305.new(key=self.key, cipher=AES) + self.assertEqual(h1.digest_size, 16) + self.assertEqual(len(h1.nonce), 16) + d1 = h1.update(data).digest() + self.assertEqual(len(d1), 16) + + h2 = Poly1305.new(key=self.key, nonce=h1.nonce, data=data, cipher=AES) + d2 = h2.digest() + self.assertEqual(h1.nonce, h2.nonce) + self.assertEqual(d1, d2) + + def test_new_negative(self): + from Cryptodome.Cipher import DES3 + + self.assertRaises(ValueError, Poly1305.new, key=self.key[:31], cipher=AES) + self.assertRaises(ValueError, Poly1305.new, key=self.key, cipher=DES3) + self.assertRaises(ValueError, Poly1305.new, key=self.key, nonce=b'1' * 15, cipher=AES) + self.assertRaises(TypeError, Poly1305.new, key=u"2" * 32, cipher=AES) + self.assertRaises(TypeError, Poly1305.new, key=self.key, data=u"2" * 100, cipher=AES) + + def test_update(self): + pieces = [b"\x0A" * 200, b"\x14" * 300] + h1 = Poly1305.new(key=self.key, cipher=AES) + h1.update(pieces[0]).update(pieces[1]) + d1 = h1.digest() + + h2 = Poly1305.new(key=self.key, cipher=AES, nonce=h1.nonce) + h2.update(pieces[0] + pieces[1]) + d2 = h2.digest() + self.assertEqual(d1, d2) + + def test_update_negative(self): + h = Poly1305.new(key=self.key, cipher=AES) + self.assertRaises(TypeError, h.update, u"string") + + def test_digest(self): + h = Poly1305.new(key=self.key, cipher=AES) + digest = h.digest() + + # hexdigest does not change the state + self.assertEqual(h.digest(), digest) + # digest returns a byte string + self.assertTrue(isinstance(digest, type(b"digest"))) + + def test_update_after_digest(self): + msg=b"rrrrttt" + + # Normally, update() cannot be done after digest() + h = Poly1305.new(key=self.key, data=msg[:4], cipher=AES) + h.digest() + self.assertRaises(TypeError, h.update, msg[4:]) + + def test_hex_digest(self): + mac = Poly1305.new(key=self.key, cipher=AES) + digest = mac.digest() + hexdigest = mac.hexdigest() + + # hexdigest is equivalent to digest + self.assertEqual(hexlify(digest), tobytes(hexdigest)) + # hexdigest does not change the state + self.assertEqual(mac.hexdigest(), hexdigest) + # hexdigest returns a string + self.assertTrue(isinstance(hexdigest, type("digest"))) + + def test_verify(self): + h = Poly1305.new(key=self.key, cipher=AES) + mac = h.digest() + h.verify(mac) + wrong_mac = strxor_c(mac, 255) + self.assertRaises(ValueError, h.verify, wrong_mac) + + def test_hexverify(self): + h = Poly1305.new(key=self.key, cipher=AES) + mac = h.hexdigest() + h.hexverify(mac) + self.assertRaises(ValueError, h.hexverify, "4556") + + def test_bytearray(self): + + data = b"\x00\x01\x02" + h0 = Poly1305.new(key=self.key, data=data, cipher=AES) + d_ref = h0.digest() + + # Data and key can be a bytearray (during initialization) + key_ba = bytearray(self.key) + data_ba = bytearray(data) + + h1 = Poly1305.new(key=self.key, data=data, cipher=AES, nonce=h0.nonce) + h2 = Poly1305.new(key=key_ba, data=data_ba, cipher=AES, nonce=h0.nonce) + key_ba[:1] = b'\xFF' + data_ba[:1] = b'\xEE' + + self.assertEqual(h1.digest(), d_ref) + self.assertEqual(h2.digest(), d_ref) + + # Data can be a bytearray (during operation) + data_ba = bytearray(data) + + h1 = Poly1305.new(key=self.key, cipher=AES) + h2 = Poly1305.new(key=self.key, cipher=AES, nonce=h1.nonce) + h1.update(data) + h2.update(data_ba) + data_ba[:1] = b'\xFF' + + self.assertEqual(h1.digest(), h2.digest()) + + def test_memoryview(self): + + data = b"\x00\x01\x02" + + def get_mv_ro(data): + return memoryview(data) + + def get_mv_rw(data): + return memoryview(bytearray(data)) + + for get_mv in (get_mv_ro, get_mv_rw): + + # Data and key can be a memoryview (during initialization) + key_mv = get_mv(self.key) + data_mv = get_mv(data) + + h1 = Poly1305.new(key=self.key, data=data, cipher=AES) + h2 = Poly1305.new(key=key_mv, data=data_mv, cipher=AES, + nonce=h1.nonce) + if not data_mv.readonly: + data_mv[:1] = b'\xFF' + key_mv[:1] = b'\xFF' + + self.assertEqual(h1.digest(), h2.digest()) + + # Data can be a memoryview (during operation) + data_mv = get_mv(data) + + h1 = Poly1305.new(key=self.key, cipher=AES) + h2 = Poly1305.new(key=self.key, cipher=AES, nonce=h1.nonce) + h1.update(data) + h2.update(data_mv) + if not data_mv.readonly: + data_mv[:1] = b'\xFF' + + self.assertEqual(h1.digest(), h2.digest()) + + +class Poly1305Test_ChaCha20(unittest.TestCase): + + key = b'\x11' * 32 + + def test_new_positive(self): + data = b'r' * 100 + + h1 = Poly1305.new(key=self.key, cipher=ChaCha20) + self.assertEqual(h1.digest_size, 16) + self.assertEqual(len(h1.nonce), 12) + + h2 = Poly1305.new(key=self.key, cipher=ChaCha20, nonce = b'8' * 8) + self.assertEqual(len(h2.nonce), 8) + self.assertEqual(h2.nonce, b'8' * 8) + + def test_new_negative(self): + + self.assertRaises(ValueError, Poly1305.new, key=self.key, nonce=b'1' * 7, cipher=ChaCha20) + + +# +# make_mac_tests() expect a new() function with signature new(key, data, +# **kwargs), and we need to adapt Poly1305's, as it only uses keywords +# +class Poly1305_New(object): + + @staticmethod + def new(key, *data, **kwds): + _kwds = dict(kwds) + if len(data) == 1: + _kwds['data'] = data[0] + _kwds['key'] = key + return Poly1305.new(**_kwds) + + +class Poly1305_Basic(object): + + @staticmethod + def new(key, *data, **kwds): + from Cryptodome.Hash.Poly1305 import Poly1305_MAC + + if len(data) == 1: + msg = data[0] + else: + msg = None + + return Poly1305_MAC(key[:16], key[16:], msg) + + +class Poly1305AES_MC(unittest.TestCase): + + def runTest(self): + tag = unhexlify(b"fb447350c4e868c52ac3275cf9d4327e") + + msg = b'' + for msg_len in range(5000 + 1): + key = tag + strxor_c(tag, 0xFF) + nonce = tag[::-1] + if msg_len > 0: + msg = msg + tobytes(tag[0]) + auth = Poly1305.new(key=key, nonce=nonce, cipher=AES, data=msg) + tag = auth.digest() + + # Compare against output of original DJB's poly1305aes-20050218 + self.assertEqual("CDFA436DDD629C7DC20E1128530BAED2", auth.hexdigest().upper()) + + +def get_tests(config={}): + tests = make_mac_tests(Poly1305_Basic, "Poly1305", test_data_basic) + tests += make_mac_tests(Poly1305_New, "Poly1305", test_data_aes) + tests += make_mac_tests(Poly1305_New, "Poly1305", test_data_chacha20) + tests += [ Poly1305AES_MC() ] + tests += list_test_cases(Poly1305Test_AES) + tests += list_test_cases(Poly1305Test_ChaCha20) + return tests + + +if __name__ == '__main__': + suite = lambda: unittest.TestSuite(get_tests()) + unittest.main(defaultTest='suite') diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/test_RIPEMD160.py b/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/test_RIPEMD160.py new file mode 100644 index 0000000..c05a877 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/test_RIPEMD160.py @@ -0,0 +1,71 @@ +# -*- coding: utf-8 -*- +# +# SelfTest/Hash/test_RIPEMD160.py: Self-test for the RIPEMD-160 hash function +# +# Written in 2008 by Dwayne C. Litzenberger +# +# =================================================================== +# The contents of this file are dedicated to the public domain. To +# the extent that dedication to the public domain is not available, +# everyone is granted a worldwide, perpetual, royalty-free, +# non-exclusive license to exercise all rights associated with the +# contents of this file for any purpose whatsoever. +# No rights are reserved. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# =================================================================== + +#"""Self-test suite for Cryptodome.Hash.RIPEMD160""" + +from Cryptodome.Util.py3compat import * + +# This is a list of (expected_result, input[, description]) tuples. +test_data = [ + # Test vectors downloaded 2008-09-12 from + # http://homes.esat.kuleuven.be/~bosselae/ripemd160.html + ('9c1185a5c5e9fc54612808977ee8f548b2258d31', '', "'' (empty string)"), + ('0bdc9d2d256b3ee9daae347be6f4dc835a467ffe', 'a'), + ('8eb208f7e05d987a9b044a8e98c6b087f15a0bfc', 'abc'), + ('5d0689ef49d2fae572b881b123a85ffa21595f36', 'message digest'), + + ('f71c27109c692c1b56bbdceb5b9d2865b3708dbc', + 'abcdefghijklmnopqrstuvwxyz', + 'a-z'), + + ('12a053384a9c0c88e405a06c27dcf49ada62eb2b', + 'abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq', + 'abcdbcd...pnopq'), + + ('b0e20b6e3116640286ed3a87a5713079b21f5189', + 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789', + 'A-Z, a-z, 0-9'), + + ('9b752e45573d4b39f4dbd3323cab82bf63326bfb', + '1234567890' * 8, + "'1234567890' * 8"), + + ('52783243c1697bdbe16d37f97f68f08325dc1528', + 'a' * 10**6, + '"a" * 10**6'), +] + +def get_tests(config={}): + from Cryptodome.Hash import RIPEMD160 + from .common import make_hash_tests + return make_hash_tests(RIPEMD160, "RIPEMD160", test_data, + digest_size=20, + oid="1.3.36.3.2.1") + +if __name__ == '__main__': + import unittest + suite = lambda: unittest.TestSuite(get_tests()) + unittest.main(defaultTest='suite') + +# vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/test_SHA1.py b/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/test_SHA1.py new file mode 100644 index 0000000..a879e68 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/test_SHA1.py @@ -0,0 +1,84 @@ +# -*- coding: utf-8 -*- +# +# SelfTest/Hash/SHA1.py: Self-test for the SHA-1 hash function +# +# Written in 2008 by Dwayne C. Litzenberger +# +# =================================================================== +# The contents of this file are dedicated to the public domain. To +# the extent that dedication to the public domain is not available, +# everyone is granted a worldwide, perpetual, royalty-free, +# non-exclusive license to exercise all rights associated with the +# contents of this file for any purpose whatsoever. +# No rights are reserved. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# =================================================================== + +"""Self-test suite for Cryptodome.Hash.SHA""" + +from binascii import hexlify + +from Cryptodome.SelfTest.loader import load_test_vectors + +# Test vectors from various sources +# This is a list of (expected_result, input[, description]) tuples. +test_data_various = [ + # FIPS PUB 180-2, A.1 - "One-Block Message" + ('a9993e364706816aba3e25717850c26c9cd0d89d', 'abc'), + + # FIPS PUB 180-2, A.2 - "Multi-Block Message" + ('84983e441c3bd26ebaae4aa1f95129e5e54670f1', + 'abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq'), + + # FIPS PUB 180-2, A.3 - "Long Message" +# ('34aa973cd4c4daa4f61eeb2bdbad27316534016f', +# 'a' * 10**6, +# '"a" * 10**6'), + + # RFC 3174: Section 7.3, "TEST4" (multiple of 512 bits) + ('dea356a2cddd90c7a7ecedc5ebb563934f460452', + '01234567' * 80, + '"01234567" * 80'), +] + +def get_tests(config={}): + from Cryptodome.Hash import SHA1 + from .common import make_hash_tests + + tests = [] + + test_vectors = load_test_vectors(("Hash", "SHA1"), + "SHA1ShortMsg.rsp", + "KAT SHA-1", + { "len" : lambda x: int(x) } ) or [] + + test_data = test_data_various[:] + for tv in test_vectors: + try: + if tv.startswith('['): + continue + except AttributeError: + pass + if tv.len == 0: + tv.msg = b"" + test_data.append((hexlify(tv.md), tv.msg, tv.desc)) + + tests = make_hash_tests(SHA1, "SHA1", test_data, + digest_size=20, + oid="1.3.14.3.2.26") + return tests + +if __name__ == '__main__': + import unittest + suite = lambda: unittest.TestSuite(get_tests()) + unittest.main(defaultTest='suite') + +# vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/test_SHA224.py b/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/test_SHA224.py new file mode 100644 index 0000000..da32423 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/test_SHA224.py @@ -0,0 +1,63 @@ +# -*- coding: utf-8 -*- +# +# SelfTest/Hash/test_SHA224.py: Self-test for the SHA-224 hash function +# +# Written in 2008 by Dwayne C. Litzenberger +# +# =================================================================== +# The contents of this file are dedicated to the public domain. To +# the extent that dedication to the public domain is not available, +# everyone is granted a worldwide, perpetual, royalty-free, +# non-exclusive license to exercise all rights associated with the +# contents of this file for any purpose whatsoever. +# No rights are reserved. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# =================================================================== + +"""Self-test suite for Cryptodome.Hash.SHA224""" + +# Test vectors from various sources +# This is a list of (expected_result, input[, description]) tuples. +test_data = [ + + # RFC 3874: Section 3.1, "Test Vector #1 + ('23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7', 'abc'), + + # RFC 3874: Section 3.2, "Test Vector #2 + ('75388b16512776cc5dba5da1fd890150b0c6455cb4f58b1952522525', 'abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq'), + + # RFC 3874: Section 3.3, "Test Vector #3 + ('20794655980c91d8bbb4c1ea97618a4bf03f42581948b2ee4ee7ad67', 'a' * 10**6, "'a' * 10**6"), + + # Examples from http://de.wikipedia.org/wiki/Secure_Hash_Algorithm + ('d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f', ''), + + ('49b08defa65e644cbf8a2dd9270bdededabc741997d1dadd42026d7b', + 'Franz jagt im komplett verwahrlosten Taxi quer durch Bayern'), + + ('58911e7fccf2971a7d07f93162d8bd13568e71aa8fc86fc1fe9043d1', + 'Frank jagt im komplett verwahrlosten Taxi quer durch Bayern'), + +] + +def get_tests(config={}): + from Cryptodome.Hash import SHA224 + from .common import make_hash_tests + return make_hash_tests(SHA224, "SHA224", test_data, + digest_size=28, + oid='2.16.840.1.101.3.4.2.4') + +if __name__ == '__main__': + import unittest + suite = lambda: unittest.TestSuite(get_tests()) + unittest.main(defaultTest='suite') + +# vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/test_SHA256.py b/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/test_SHA256.py new file mode 100644 index 0000000..23d1145 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/test_SHA256.py @@ -0,0 +1,94 @@ +# -*- coding: utf-8 -*- +# +# SelfTest/Hash/test_SHA256.py: Self-test for the SHA-256 hash function +# +# Written in 2008 by Dwayne C. Litzenberger +# +# =================================================================== +# The contents of this file are dedicated to the public domain. To +# the extent that dedication to the public domain is not available, +# everyone is granted a worldwide, perpetual, royalty-free, +# non-exclusive license to exercise all rights associated with the +# contents of this file for any purpose whatsoever. +# No rights are reserved. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# =================================================================== + +"""Self-test suite for Cryptodome.Hash.SHA256""" + +import unittest +from Cryptodome.Util.py3compat import * + +class LargeSHA256Test(unittest.TestCase): + def runTest(self): + """SHA256: 512/520 MiB test""" + from Cryptodome.Hash import SHA256 + zeros = bchr(0x00) * (1024*1024) + + h = SHA256.new(zeros) + for i in range(511): + h.update(zeros) + + # This test vector is from PyCrypto's old testdata.py file. + self.assertEqual('9acca8e8c22201155389f65abbf6bc9723edc7384ead80503839f49dcc56d767', h.hexdigest()) # 512 MiB + + for i in range(8): + h.update(zeros) + + # This test vector is from PyCrypto's old testdata.py file. + self.assertEqual('abf51ad954b246009dfe5a50ecd582fd5b8f1b8b27f30393853c3ef721e7fa6e', h.hexdigest()) # 520 MiB + +def get_tests(config={}): + # Test vectors from FIPS PUB 180-2 + # This is a list of (expected_result, input[, description]) tuples. + test_data = [ + # FIPS PUB 180-2, B.1 - "One-Block Message" + ('ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad', + 'abc'), + + # FIPS PUB 180-2, B.2 - "Multi-Block Message" + ('248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1', + 'abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq'), + + # FIPS PUB 180-2, B.3 - "Long Message" + ('cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0', + 'a' * 10**6, + '"a" * 10**6'), + + # Test for an old PyCryptodome bug. + ('f7fd017a3c721ce7ff03f3552c0813adcc48b7f33f07e5e2ba71e23ea393d103', + 'This message is precisely 55 bytes long, to test a bug.', + 'Length = 55 (mod 64)'), + + # Example from http://de.wikipedia.org/wiki/Secure_Hash_Algorithm + ('e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855', ''), + + ('d32b568cd1b96d459e7291ebf4b25d007f275c9f13149beeb782fac0716613f8', + 'Franz jagt im komplett verwahrlosten Taxi quer durch Bayern'), + ] + + from Cryptodome.Hash import SHA256 + from .common import make_hash_tests + tests = make_hash_tests(SHA256, "SHA256", test_data, + digest_size=32, + oid="2.16.840.1.101.3.4.2.1") + + if config.get('slow_tests'): + tests += [LargeSHA256Test()] + + return tests + +if __name__ == '__main__': + import unittest + suite = lambda: unittest.TestSuite(get_tests()) + unittest.main(defaultTest='suite') + +# vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/test_SHA384.py b/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/test_SHA384.py new file mode 100644 index 0000000..5233d13 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/test_SHA384.py @@ -0,0 +1,61 @@ +# -*- coding: utf-8 -*- +# +# SelfTest/Hash/test_SHA.py: Self-test for the SHA-384 hash function +# +# Written in 2008 by Dwayne C. Litzenberger +# +# =================================================================== +# The contents of this file are dedicated to the public domain. To +# the extent that dedication to the public domain is not available, +# everyone is granted a worldwide, perpetual, royalty-free, +# non-exclusive license to exercise all rights associated with the +# contents of this file for any purpose whatsoever. +# No rights are reserved. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# =================================================================== + +"""Self-test suite for Cryptodome.Hash.SHA384""" + +# Test vectors from various sources +# This is a list of (expected_result, input[, description]) tuples. +test_data = [ + + # RFC 4634: Section Page 8.4, "Test 1" + ('cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7', 'abc'), + + # RFC 4634: Section Page 8.4, "Test 2.2" + ('09330c33f71147e83d192fc782cd1b4753111b173b3b05d22fa08086e3b0f712fcc7c71a557e2db966c3e9fa91746039', 'abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu'), + + # RFC 4634: Section Page 8.4, "Test 3" + ('9d0e1809716474cb086e834e310a4a1ced149e9c00f248527972cec5704c2a5b07b8b3dc38ecc4ebae97ddd87f3d8985', 'a' * 10**6, "'a' * 10**6"), + + # Taken from http://de.wikipedia.org/wiki/Secure_Hash_Algorithm + ('38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b', ''), + + # Example from http://de.wikipedia.org/wiki/Secure_Hash_Algorithm + ('71e8383a4cea32d6fd6877495db2ee353542f46fa44bc23100bca48f3366b84e809f0708e81041f427c6d5219a286677', + 'Franz jagt im komplett verwahrlosten Taxi quer durch Bayern'), + +] + +def get_tests(config={}): + from Cryptodome.Hash import SHA384 + from .common import make_hash_tests + return make_hash_tests(SHA384, "SHA384", test_data, + digest_size=48, + oid='2.16.840.1.101.3.4.2.2') + +if __name__ == '__main__': + import unittest + suite = lambda: unittest.TestSuite(get_tests()) + unittest.main(defaultTest='suite') + +# vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/test_SHA3_224.py b/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/test_SHA3_224.py new file mode 100644 index 0000000..3141880 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/test_SHA3_224.py @@ -0,0 +1,79 @@ +# -*- coding: utf-8 -*- +# +# SelfTest/Hash/test_SHA3_224.py: Self-test for the SHA-3/224 hash function +# +# =================================================================== +# The contents of this file are dedicated to the public domain. To +# the extent that dedication to the public domain is not available, +# everyone is granted a worldwide, perpetual, royalty-free, +# non-exclusive license to exercise all rights associated with the +# contents of this file for any purpose whatsoever. +# No rights are reserved. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# =================================================================== + +"""Self-test suite for Cryptodome.Hash.SHA3_224""" + +import unittest +from binascii import hexlify + +from Cryptodome.SelfTest.loader import load_test_vectors +from Cryptodome.SelfTest.st_common import list_test_cases +from Cryptodome.Hash import SHA3_224 as SHA3 +from Cryptodome.Util.py3compat import b + + +class APITest(unittest.TestCase): + + def test_update_after_digest(self): + msg=b("rrrrttt") + + # Normally, update() cannot be done after digest() + h = SHA3.new(data=msg[:4]) + dig1 = h.digest() + self.assertRaises(TypeError, h.update, msg[4:]) + dig2 = SHA3.new(data=msg).digest() + + # With the proper flag, it is allowed + h = SHA3.new(data=msg[:4], update_after_digest=True) + self.assertEqual(h.digest(), dig1) + # ... and the subsequent digest applies to the entire message + # up to that point + h.update(msg[4:]) + self.assertEqual(h.digest(), dig2) + + +def get_tests(config={}): + from .common import make_hash_tests + + tests = [] + + test_vectors = load_test_vectors(("Hash", "SHA3"), + "ShortMsgKAT_SHA3-224.txt", + "KAT SHA-3 224", + { "len" : lambda x: int(x) } ) or [] + + test_data = [] + for tv in test_vectors: + if tv.len == 0: + tv.msg = b("") + test_data.append((hexlify(tv.md), tv.msg, tv.desc)) + + tests += make_hash_tests(SHA3, "SHA3_224", test_data, + digest_size=SHA3.digest_size, + oid="2.16.840.1.101.3.4.2.7") + tests += list_test_cases(APITest) + return tests + +if __name__ == '__main__': + import unittest + suite = lambda: unittest.TestSuite(get_tests()) + unittest.main(defaultTest='suite') diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/test_SHA3_256.py b/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/test_SHA3_256.py new file mode 100644 index 0000000..9dee551 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/test_SHA3_256.py @@ -0,0 +1,80 @@ +# -*- coding: utf-8 -*- +# +# SelfTest/Hash/test_SHA3_256.py: Self-test for the SHA-3/256 hash function +# +# =================================================================== +# The contents of this file are dedicated to the public domain. To +# the extent that dedication to the public domain is not available, +# everyone is granted a worldwide, perpetual, royalty-free, +# non-exclusive license to exercise all rights associated with the +# contents of this file for any purpose whatsoever. +# No rights are reserved. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# =================================================================== + +"""Self-test suite for Cryptodome.Hash.SHA3_256""" + +import unittest +from binascii import hexlify + +from Cryptodome.SelfTest.loader import load_test_vectors +from Cryptodome.SelfTest.st_common import list_test_cases +from Cryptodome.Hash import SHA3_256 as SHA3 +from Cryptodome.Util.py3compat import b + + +class APITest(unittest.TestCase): + + def test_update_after_digest(self): + msg=b("rrrrttt") + + # Normally, update() cannot be done after digest() + h = SHA3.new(data=msg[:4]) + dig1 = h.digest() + self.assertRaises(TypeError, h.update, msg[4:]) + dig2 = SHA3.new(data=msg).digest() + + # With the proper flag, it is allowed + h = SHA3.new(data=msg[:4], update_after_digest=True) + self.assertEqual(h.digest(), dig1) + # ... and the subsequent digest applies to the entire message + # up to that point + h.update(msg[4:]) + self.assertEqual(h.digest(), dig2) + + +def get_tests(config={}): + from .common import make_hash_tests + + tests = [] + + test_vectors = load_test_vectors(("Hash", "SHA3"), + "ShortMsgKAT_SHA3-256.txt", + "KAT SHA-3 256", + { "len" : lambda x: int(x) } ) or [] + + test_data = [] + for tv in test_vectors: + if tv.len == 0: + tv.msg = b("") + test_data.append((hexlify(tv.md), tv.msg, tv.desc)) + + + tests += make_hash_tests(SHA3, "SHA3_256", test_data, + digest_size=SHA3.digest_size, + oid="2.16.840.1.101.3.4.2.8") + tests += list_test_cases(APITest) + return tests + +if __name__ == '__main__': + import unittest + suite = lambda: unittest.TestSuite(get_tests()) + unittest.main(defaultTest='suite') diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/test_SHA3_384.py b/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/test_SHA3_384.py new file mode 100644 index 0000000..c5030b5 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/test_SHA3_384.py @@ -0,0 +1,79 @@ +# -*- coding: utf-8 -*- +# +# SelfTest/Hash/test_SHA3_384.py: Self-test for the SHA-3/384 hash function +# +# =================================================================== +# The contents of this file are dedicated to the public domain. To +# the extent that dedication to the public domain is not available, +# everyone is granted a worldwide, perpetual, royalty-free, +# non-exclusive license to exercise all rights associated with the +# contents of this file for any purpose whatsoever. +# No rights are reserved. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# =================================================================== + +"""Self-test suite for Cryptodome.Hash.SHA3_384""" + +import unittest +from binascii import hexlify + +from Cryptodome.SelfTest.loader import load_test_vectors +from Cryptodome.SelfTest.st_common import list_test_cases +from Cryptodome.Hash import SHA3_384 as SHA3 +from Cryptodome.Util.py3compat import b + + +class APITest(unittest.TestCase): + + def test_update_after_digest(self): + msg=b("rrrrttt") + + # Normally, update() cannot be done after digest() + h = SHA3.new(data=msg[:4]) + dig1 = h.digest() + self.assertRaises(TypeError, h.update, msg[4:]) + dig2 = SHA3.new(data=msg).digest() + + # With the proper flag, it is allowed + h = SHA3.new(data=msg[:4], update_after_digest=True) + self.assertEqual(h.digest(), dig1) + # ... and the subsequent digest applies to the entire message + # up to that point + h.update(msg[4:]) + self.assertEqual(h.digest(), dig2) + + +def get_tests(config={}): + from .common import make_hash_tests + + tests = [] + + test_vectors = load_test_vectors(("Hash", "SHA3"), + "ShortMsgKAT_SHA3-384.txt", + "KAT SHA-3 384", + { "len" : lambda x: int(x) } ) or [] + + test_data = [] + for tv in test_vectors: + if tv.len == 0: + tv.msg = b("") + test_data.append((hexlify(tv.md), tv.msg, tv.desc)) + + tests += make_hash_tests(SHA3, "SHA3_384", test_data, + digest_size=SHA3.digest_size, + oid="2.16.840.1.101.3.4.2.9") + tests += list_test_cases(APITest) + return tests + +if __name__ == '__main__': + import unittest + suite = lambda: unittest.TestSuite(get_tests()) + unittest.main(defaultTest='suite') diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/test_SHA3_512.py b/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/test_SHA3_512.py new file mode 100644 index 0000000..b7a57f8 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/test_SHA3_512.py @@ -0,0 +1,79 @@ +# -*- coding: utf-8 -*- +# +# SelfTest/Hash/test_SHA3_512.py: Self-test for the SHA-3/512 hash function +# +# =================================================================== +# The contents of this file are dedicated to the public domain. To +# the extent that dedication to the public domain is not available, +# everyone is granted a worldwide, perpetual, royalty-free, +# non-exclusive license to exercise all rights associated with the +# contents of this file for any purpose whatsoever. +# No rights are reserved. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# =================================================================== + +"""Self-test suite for Cryptodome.Hash.SHA3_512""" + +import unittest +from binascii import hexlify + +from Cryptodome.SelfTest.loader import load_test_vectors +from Cryptodome.SelfTest.st_common import list_test_cases +from Cryptodome.Hash import SHA3_512 as SHA3 +from Cryptodome.Util.py3compat import b + + +class APITest(unittest.TestCase): + + def test_update_after_digest(self): + msg=b("rrrrttt") + + # Normally, update() cannot be done after digest() + h = SHA3.new(data=msg[:4]) + dig1 = h.digest() + self.assertRaises(TypeError, h.update, msg[4:]) + dig2 = SHA3.new(data=msg).digest() + + # With the proper flag, it is allowed + h = SHA3.new(data=msg[:4], update_after_digest=True) + self.assertEqual(h.digest(), dig1) + # ... and the subsequent digest applies to the entire message + # up to that point + h.update(msg[4:]) + self.assertEqual(h.digest(), dig2) + + +def get_tests(config={}): + from .common import make_hash_tests + + tests = [] + + test_vectors = load_test_vectors(("Hash", "SHA3"), + "ShortMsgKAT_SHA3-512.txt", + "KAT SHA-3 512", + { "len" : lambda x: int(x) } ) or [] + + test_data = [] + for tv in test_vectors: + if tv.len == 0: + tv.msg = b("") + test_data.append((hexlify(tv.md), tv.msg, tv.desc)) + + tests += make_hash_tests(SHA3, "SHA3_512", test_data, + digest_size=SHA3.digest_size, + oid="2.16.840.1.101.3.4.2.10") + tests += list_test_cases(APITest) + return tests + +if __name__ == '__main__': + import unittest + suite = lambda: unittest.TestSuite(get_tests()) + unittest.main(defaultTest='suite') diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/test_SHA512.py b/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/test_SHA512.py new file mode 100644 index 0000000..e6c74b3 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/test_SHA512.py @@ -0,0 +1,140 @@ +# -*- coding: utf-8 -*- +# +# SelfTest/Hash/test_SHA512.py: Self-test for the SHA-512 hash function +# +# Written in 2008 by Dwayne C. Litzenberger +# +# =================================================================== +# The contents of this file are dedicated to the public domain. To +# the extent that dedication to the public domain is not available, +# everyone is granted a worldwide, perpetual, royalty-free, +# non-exclusive license to exercise all rights associated with the +# contents of this file for any purpose whatsoever. +# No rights are reserved. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# =================================================================== + +"""Self-test suite for Cryptodome.Hash.SHA512""" + +from binascii import hexlify + +from Cryptodome.Hash import SHA512 +from .common import make_hash_tests +from Cryptodome.SelfTest.loader import load_test_vectors + +# Test vectors from various sources +# This is a list of (expected_result, input[, description]) tuples. +test_data_512_other = [ + + # RFC 4634: Section Page 8.4, "Test 1" + ('ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f', 'abc'), + + # RFC 4634: Section Page 8.4, "Test 2.1" + ('8e959b75dae313da8cf4f72814fc143f8f7779c6eb9f7fa17299aeadb6889018501d289e4900f7e4331b99dec4b5433ac7d329eeb6dd26545e96e55b874be909', 'abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu'), + + # RFC 4634: Section Page 8.4, "Test 3" + ('e718483d0ce769644e2e42c7bc15b4638e1f98b13b2044285632a803afa973ebde0ff244877ea60a4cb0432ce577c31beb009c5c2c49aa2e4eadb217ad8cc09b', 'a' * 10**6, "'a' * 10**6"), + + # Taken from http://de.wikipedia.org/wiki/Secure_Hash_Algorithm + ('cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e', ''), + + ('af9ed2de700433b803240a552b41b5a472a6ef3fe1431a722b2063c75e9f07451f67a28e37d09cde769424c96aea6f8971389db9e1993d6c565c3c71b855723c', 'Franz jagt im komplett verwahrlosten Taxi quer durch Bayern'), +] + + +def get_tests_SHA512(): + + test_vectors = load_test_vectors(("Hash", "SHA2"), + "SHA512ShortMsg.rsp", + "KAT SHA-512", + {"len": lambda x: int(x)}) or [] + + test_data = test_data_512_other[:] + for tv in test_vectors: + try: + if tv.startswith('['): + continue + except AttributeError: + pass + if tv.len == 0: + tv.msg = b"" + test_data.append((hexlify(tv.md), tv.msg, tv.desc)) + + tests = make_hash_tests(SHA512, "SHA512", test_data, + digest_size=64, + oid="2.16.840.1.101.3.4.2.3") + return tests + + +def get_tests_SHA512_224(): + + test_vectors = load_test_vectors(("Hash", "SHA2"), + "SHA512_224ShortMsg.rsp", + "KAT SHA-512/224", + {"len": lambda x: int(x)}) or [] + + test_data = [] + for tv in test_vectors: + try: + if tv.startswith('['): + continue + except AttributeError: + pass + if tv.len == 0: + tv.msg = b"" + test_data.append((hexlify(tv.md), tv.msg, tv.desc)) + + tests = make_hash_tests(SHA512, "SHA512/224", test_data, + digest_size=28, + oid="2.16.840.1.101.3.4.2.5", + extra_params={ "truncate" : "224" }) + return tests + + +def get_tests_SHA512_256(): + + test_vectors = load_test_vectors(("Hash", "SHA2"), + "SHA512_256ShortMsg.rsp", + "KAT SHA-512/256", + {"len": lambda x: int(x)}) or [] + + test_data = [] + for tv in test_vectors: + try: + if tv.startswith('['): + continue + except AttributeError: + pass + if tv.len == 0: + tv.msg = b"" + test_data.append((hexlify(tv.md), tv.msg, tv.desc)) + + tests = make_hash_tests(SHA512, "SHA512/256", test_data, + digest_size=32, + oid="2.16.840.1.101.3.4.2.6", + extra_params={ "truncate" : "256" }) + return tests + + +def get_tests(config={}): + + tests = [] + tests += get_tests_SHA512() + tests += get_tests_SHA512_224() + tests += get_tests_SHA512_256() + return tests + +if __name__ == '__main__': + import unittest + suite = lambda: unittest.TestSuite(get_tests()) + unittest.main(defaultTest='suite') + +# vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/test_SHAKE.py b/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/test_SHAKE.py new file mode 100644 index 0000000..07965f6 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/test_SHAKE.py @@ -0,0 +1,151 @@ +# =================================================================== +# +# Copyright (c) 2015, Legrandin +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# =================================================================== + +"""Self-test suite for Cryptodome.Hash.SHAKE128 and SHAKE256""" + +import unittest +from binascii import hexlify, unhexlify + +from Cryptodome.SelfTest.loader import load_test_vectors +from Cryptodome.SelfTest.st_common import list_test_cases + +from Cryptodome.Hash import SHAKE128, SHAKE256 +from Cryptodome.Util.py3compat import b, bchr, bord, tobytes + +class SHAKETest(unittest.TestCase): + + def test_new_positive(self): + + xof1 = self.shake.new() + xof2 = self.shake.new(data=b("90")) + xof3 = self.shake.new().update(b("90")) + + self.assertNotEqual(xof1.read(10), xof2.read(10)) + xof3.read(10) + self.assertEqual(xof2.read(10), xof3.read(10)) + + def test_update(self): + pieces = [bchr(10) * 200, bchr(20) * 300] + h = self.shake.new() + h.update(pieces[0]).update(pieces[1]) + digest = h.read(10) + h = self.shake.new() + h.update(pieces[0] + pieces[1]) + self.assertEqual(h.read(10), digest) + + def test_update_negative(self): + h = self.shake.new() + self.assertRaises(TypeError, h.update, u"string") + + def test_digest(self): + h = self.shake.new() + digest = h.read(90) + + # read returns a byte string of the right length + self.assertTrue(isinstance(digest, type(b("digest")))) + self.assertEqual(len(digest), 90) + + def test_update_after_read(self): + mac = self.shake.new() + mac.update(b("rrrr")) + mac.read(90) + self.assertRaises(TypeError, mac.update, b("ttt")) + + def test_copy(self): + mac = self.shake.new() + mac.update(b("rrrr")) + mac2 = mac.copy() + x1 = mac.read(90) + x2 = mac2.read(90) + self.assertEqual(x1, x2) + + +class SHAKE128Test(SHAKETest): + shake = SHAKE128 + + +class SHAKE256Test(SHAKETest): + shake = SHAKE256 + + +class SHAKEVectors(unittest.TestCase): + pass + + +test_vectors_128 = load_test_vectors(("Hash", "SHA3"), + "ShortMsgKAT_SHAKE128.txt", + "Short Messages KAT SHAKE128", + { "len" : lambda x: int(x) } ) or [] + +for idx, tv in enumerate(test_vectors_128): + if tv.len == 0: + data = b("") + else: + data = tobytes(tv.msg) + + def new_test(self, data=data, result=tv.md): + hobj = SHAKE128.new(data=data) + digest = hobj.read(len(result)) + self.assertEqual(digest, result) + + setattr(SHAKEVectors, "test_128_%d" % idx, new_test) + + +test_vectors_256 = load_test_vectors(("Hash", "SHA3"), + "ShortMsgKAT_SHAKE256.txt", + "Short Messages KAT SHAKE256", + { "len" : lambda x: int(x) } ) or [] + +for idx, tv in enumerate(test_vectors_256): + if tv.len == 0: + data = b("") + else: + data = tobytes(tv.msg) + + def new_test(self, data=data, result=tv.md): + hobj = SHAKE256.new(data=data) + digest = hobj.read(len(result)) + self.assertEqual(digest, result) + + setattr(SHAKEVectors, "test_256_%d" % idx, new_test) + + +def get_tests(config={}): + tests = [] + tests += list_test_cases(SHAKE128Test) + tests += list_test_cases(SHAKE256Test) + tests += list_test_cases(SHAKEVectors) + return tests + + +if __name__ == '__main__': + import unittest + suite = lambda: unittest.TestSuite(get_tests()) + unittest.main(defaultTest='suite') diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/test_TupleHash.py b/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/test_TupleHash.py new file mode 100644 index 0000000..2f93d7b --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/test_TupleHash.py @@ -0,0 +1,302 @@ +import unittest +from binascii import unhexlify, hexlify + +from Cryptodome.Util.py3compat import tobytes +from Cryptodome.SelfTest.st_common import list_test_cases + +from Cryptodome.Hash import TupleHash128, TupleHash256 + + +class TupleHashTest(unittest.TestCase): + + def new(self, *args, **kwargs): + return self.TupleHash.new(*args, **kwargs) + + def test_new_positive(self): + + h = self.new() + for new_func in self.TupleHash.new, h.new: + + for dbits in range(64, 1024 + 1, 8): + hobj = new_func(digest_bits=dbits) + self.assertEqual(hobj.digest_size * 8, dbits) + + for dbytes in range(8, 128 + 1): + hobj = new_func(digest_bytes=dbytes) + self.assertEqual(hobj.digest_size, dbytes) + + hobj = h.new() + self.assertEqual(hobj.digest_size, self.default_bytes) + + def test_new_negative(self): + + h = self.new() + for new_func in self.TupleHash.new, h.new: + self.assertRaises(TypeError, new_func, + digest_bytes=self.minimum_bytes, + digest_bits=self.minimum_bits) + self.assertRaises(ValueError, new_func, digest_bytes=0) + self.assertRaises(ValueError, new_func, + digest_bits=self.minimum_bits + 7) + self.assertRaises(ValueError, new_func, + digest_bits=self.minimum_bits - 8) + self.assertRaises(ValueError, new_func, + digest_bits=self.minimum_bytes - 1) + + def test_default_digest_size(self): + digest = self.new().digest() + self.assertEqual(len(digest), self.default_bytes) + + def test_update(self): + h = self.new() + h.update(b'') + h.digest() + + h = self.new() + h.update(b'') + h.update(b'STRING1') + h.update(b'STRING2') + mac1 = h.digest() + + h = self.new() + h.update(b'STRING1') + h.update(b'STRING2') + mac2 = h.digest() + self.assertNotEqual(mac1, mac2) + + h = self.new() + h.update(b'STRING1', b'STRING2') + self.assertEqual(mac2, h.digest()) + + h = self.new() + t = b'STRING1', b'STRING2' + h.update(*t) + self.assertEqual(mac2, h.digest()) + + def test_update_negative(self): + h = self.new() + self.assertRaises(TypeError, h.update, u"string") + self.assertRaises(TypeError, h.update, None) + self.assertRaises(TypeError, h.update, (b'STRING1', b'STRING2')) + + def test_digest(self): + h = self.new() + digest = h.digest() + + # hexdigest does not change the state + self.assertEqual(h.digest(), digest) + # digest returns a byte string + self.assertTrue(isinstance(digest, type(b"digest"))) + + def test_update_after_digest(self): + msg = b"rrrrttt" + + # Normally, update() cannot be done after digest() + h = self.new() + h.update(msg) + dig1 = h.digest() + self.assertRaises(TypeError, h.update, dig1) + + def test_hex_digest(self): + mac = self.new() + digest = mac.digest() + hexdigest = mac.hexdigest() + + # hexdigest is equivalent to digest + self.assertEqual(hexlify(digest), tobytes(hexdigest)) + # hexdigest does not change the state + self.assertEqual(mac.hexdigest(), hexdigest) + # hexdigest returns a string + self.assertTrue(isinstance(hexdigest, type("digest"))) + + def test_bytearray(self): + + data = b"\x00\x01\x02" + + # Data can be a bytearray (during operation) + data_ba = bytearray(data) + + h1 = self.new() + h2 = self.new() + h1.update(data) + h2.update(data_ba) + data_ba[:1] = b'\xFF' + + self.assertEqual(h1.digest(), h2.digest()) + + def test_memoryview(self): + + data = b"\x00\x01\x02" + + def get_mv_ro(data): + return memoryview(data) + + def get_mv_rw(data): + return memoryview(bytearray(data)) + + for get_mv in (get_mv_ro, get_mv_rw): + + # Data can be a memoryview (during operation) + data_mv = get_mv(data) + + h1 = self.new() + h2 = self.new() + h1.update(data) + h2.update(data_mv) + if not data_mv.readonly: + data_mv[:1] = b'\xFF' + + self.assertEqual(h1.digest(), h2.digest()) + + +class TupleHash128Test(TupleHashTest): + + TupleHash = TupleHash128 + + minimum_bytes = 8 + default_bytes = 64 + + minimum_bits = 64 + default_bits = 512 + + +class TupleHash256Test(TupleHashTest): + + TupleHash = TupleHash256 + + minimum_bytes = 8 + default_bytes = 64 + + minimum_bits = 64 + default_bits = 512 + + +class NISTExampleTestVectors(unittest.TestCase): + + # http://csrc.nist.gov/groups/ST/toolkit/documents/Examples/TupleHash_samples.pdf + test_data = [ + ( + ( + "00 01 02", + "10 11 12 13 14 15", + ), + "", + "C5 D8 78 6C 1A FB 9B 82 11 1A B3 4B 65 B2 C0 04" + "8F A6 4E 6D 48 E2 63 26 4C E1 70 7D 3F FC 8E D1", + "KMAC128 Sample #1 NIST", + TupleHash128 + ), + ( + ( + "00 01 02", + "10 11 12 13 14 15", + ), + "My Tuple App", + "75 CD B2 0F F4 DB 11 54 E8 41 D7 58 E2 41 60 C5" + "4B AE 86 EB 8C 13 E7 F5 F4 0E B3 55 88 E9 6D FB", + "KMAC128 Sample #2 NIST", + TupleHash128 + ), + ( + ( + "00 01 02", + "10 11 12 13 14 15", + "20 21 22 23 24 25 26 27 28", + ), + "My Tuple App", + "E6 0F 20 2C 89 A2 63 1E DA 8D 4C 58 8C A5 FD 07" + "F3 9E 51 51 99 8D EC CF 97 3A DB 38 04 BB 6E 84", + "KMAC128 Sample #3 NIST", + TupleHash128 + ), + ( + ( + "00 01 02", + "10 11 12 13 14 15", + ), + "", + "CF B7 05 8C AC A5 E6 68 F8 1A 12 A2 0A 21 95 CE" + "97 A9 25 F1 DB A3 E7 44 9A 56 F8 22 01 EC 60 73" + "11 AC 26 96 B1 AB 5E A2 35 2D F1 42 3B DE 7B D4" + "BB 78 C9 AE D1 A8 53 C7 86 72 F9 EB 23 BB E1 94", + "KMAC256 Sample #4 NIST", + TupleHash256 + ), + ( + ( + "00 01 02", + "10 11 12 13 14 15", + ), + "My Tuple App", + "14 7C 21 91 D5 ED 7E FD 98 DB D9 6D 7A B5 A1 16" + "92 57 6F 5F E2 A5 06 5F 3E 33 DE 6B BA 9F 3A A1" + "C4 E9 A0 68 A2 89 C6 1C 95 AA B3 0A EE 1E 41 0B" + "0B 60 7D E3 62 0E 24 A4 E3 BF 98 52 A1 D4 36 7E", + "KMAC256 Sample #5 NIST", + TupleHash256 + ), + ( + ( + "00 01 02", + "10 11 12 13 14 15", + "20 21 22 23 24 25 26 27 28", + ), + "My Tuple App", + "45 00 0B E6 3F 9B 6B FD 89 F5 47 17 67 0F 69 A9" + "BC 76 35 91 A4 F0 5C 50 D6 88 91 A7 44 BC C6 E7" + "D6 D5 B5 E8 2C 01 8D A9 99 ED 35 B0 BB 49 C9 67" + "8E 52 6A BD 8E 85 C1 3E D2 54 02 1D B9 E7 90 CE", + "KMAC256 Sample #6 NIST", + TupleHash256 + ), + + + + ] + + def setUp(self): + td = [] + for tv_in in self.test_data: + tv_out = [None] * len(tv_in) + + tv_out[0] = [] + for string in tv_in[0]: + tv_out[0].append(unhexlify(string.replace(" ", ""))) + + tv_out[1] = tobytes(tv_in[1]) # Custom + tv_out[2] = unhexlify(tv_in[2].replace(" ", "")) + tv_out[3] = tv_in[3] + tv_out[4] = tv_in[4] + td.append(tv_out) + self.test_data = td + + def runTest(self): + + for data, custom, digest, text, module in self.test_data: + hd1 = module.new(custom=custom, digest_bytes=len(digest)) + hd2 = module.new(custom=custom, digest_bytes=len(digest)) + + # Call update() for each element + for string in data: + hd1.update(string) + + # One single update for all elements + hd2.update(*data) + + self.assertEqual(hd1.digest(), digest, msg=text) + self.assertEqual(hd2.digest(), digest, msg=text) + +def get_tests(config={}): + tests = [] + + tests += list_test_cases(TupleHash128Test) + tests += list_test_cases(TupleHash256Test) + tests.append(NISTExampleTestVectors()) + + return tests + + +if __name__ == '__main__': + def suite(): + return unittest.TestSuite(get_tests()) + unittest.main(defaultTest='suite') diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/test_TurboSHAKE.py b/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/test_TurboSHAKE.py new file mode 100644 index 0000000..7c13d1e --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/test_TurboSHAKE.py @@ -0,0 +1,468 @@ +"""Self-test suite for Cryptodome.Hash.TurboSHAKE128 and TurboSHAKE256""" + +import unittest +from binascii import unhexlify + +from Cryptodome.SelfTest.st_common import list_test_cases + +from Cryptodome.Hash import TurboSHAKE128, TurboSHAKE256 +from Cryptodome.Util.py3compat import bchr + + +class TurboSHAKETest(unittest.TestCase): + + def test_new_positive(self): + + xof1 = self.TurboSHAKE.new() + xof1.update(b'90') + + xof2 = self.TurboSHAKE.new(domain=0x1F) + xof2.update(b'90') + + xof3 = self.TurboSHAKE.new(data=b'90') + + out1 = xof1.read(128) + out2 = xof2.read(128) + out3 = xof3.read(128) + + self.assertEqual(out1, out2) + self.assertEqual(out1, out3) + + def test_new_domain(self): + xof1 = self.TurboSHAKE.new(domain=0x1D) + xof2 = self.TurboSHAKE.new(domain=0x20) + self.assertNotEqual(xof1.read(128), xof2.read(128)) + + def test_update(self): + pieces = [bchr(10) * 200, bchr(20) * 300] + + xof1 = self.TurboSHAKE.new() + xof1.update(pieces[0]).update(pieces[1]) + digest1 = xof1.read(10) + + xof2 = self.TurboSHAKE.new() + xof2.update(pieces[0] + pieces[1]) + digest2 = xof2.read(10) + + self.assertEqual(digest1, digest2) + + def test_update_negative(self): + xof1 = self.TurboSHAKE.new() + self.assertRaises(TypeError, xof1.update, u"string") + + def test_read(self): + xof1 = self.TurboSHAKE.new() + digest = xof1.read(90) + + # read returns a byte string of the right length + self.assertTrue(isinstance(digest, bytes)) + self.assertEqual(len(digest), 90) + + def test_update_after_read(self): + xof1 = self.TurboSHAKE.new() + xof1.update(b"rrrr") + xof1.read(90) + self.assertRaises(TypeError, xof1.update, b"ttt") + + def test_new(self): + xof1 = self.TurboSHAKE.new(domain=0x07) + xof1.update(b'90') + digest1 = xof1.read(100) + + xof2 = xof1.new() + xof2.update(b'90') + digest2 = xof2.read(100) + + self.assertEqual(digest1, digest2) + + self.assertRaises(TypeError, xof1.new, domain=0x07) + + +class TurboSHAKE128Test(TurboSHAKETest): + TurboSHAKE = TurboSHAKE128 + + +class TurboSHAKE256Test(TurboSHAKETest): + TurboSHAKE = TurboSHAKE256 + + +def txt2bin(txt): + clean = txt.replace(" ", "").replace("\n", "").replace("\r", "") + return unhexlify(clean) + + +def ptn(n): + res = bytearray(n) + pattern = b"".join([bchr(x) for x in range(0, 0xFB)]) + for base in range(0, n - 0xFB, 0xFB): + res[base:base + 0xFB] = pattern + remain = n % 0xFB + if remain: + base = (n // 0xFB) * 0xFB + res[base:] = pattern[:remain] + assert len(res) == n + return res + + +def chunked(source, size): + for i in range(0, len(source), size): + yield source[i:i+size] + + +class TurboSHAKE128TV(unittest.TestCase): + + def test_zero_1(self): + tv = """1E 41 5F 1C 59 83 AF F2 16 92 17 27 7D 17 BB 53 + 8C D9 45 A3 97 DD EC 54 1F 1C E4 1A F2 C1 B7 4C""" + + btv = txt2bin(tv) + res = TurboSHAKE128.new().read(32) + self.assertEqual(res, btv) + + def test_zero_2(self): + tv = """1E 41 5F 1C 59 83 AF F2 16 92 17 27 7D 17 BB 53 + 8C D9 45 A3 97 DD EC 54 1F 1C E4 1A F2 C1 B7 4C + 3E 8C CA E2 A4 DA E5 6C 84 A0 4C 23 85 C0 3C 15 + E8 19 3B DF 58 73 73 63 32 16 91 C0 54 62 C8 DF""" + + btv = txt2bin(tv) + res = TurboSHAKE128.new().read(64) + self.assertEqual(res, btv) + + def test_zero_3(self): + tv = """A3 B9 B0 38 59 00 CE 76 1F 22 AE D5 48 E7 54 DA + 10 A5 24 2D 62 E8 C6 58 E3 F3 A9 23 A7 55 56 07""" + + btv = txt2bin(tv) + res = TurboSHAKE128.new().read(10032)[-32:] + self.assertEqual(res, btv) + + def test_ptn_1(self): + tv = """55 CE DD 6F 60 AF 7B B2 9A 40 42 AE 83 2E F3 F5 + 8D B7 29 9F 89 3E BB 92 47 24 7D 85 69 58 DA A9""" + + btv = txt2bin(tv) + res = TurboSHAKE128.new(data=ptn(1)).read(32) + self.assertEqual(res, btv) + + def test_ptn_17(self): + tv = """9C 97 D0 36 A3 BA C8 19 DB 70 ED E0 CA 55 4E C6 + E4 C2 A1 A4 FF BF D9 EC 26 9C A6 A1 11 16 12 33""" + + btv = txt2bin(tv) + res = TurboSHAKE128.new(data=ptn(17)).read(32) + self.assertEqual(res, btv) + + def test_ptn_17_2(self): + tv = """96 C7 7C 27 9E 01 26 F7 FC 07 C9 B0 7F 5C DA E1 + E0 BE 60 BD BE 10 62 00 40 E7 5D 72 23 A6 24 D2""" + + btv = txt2bin(tv) + res = TurboSHAKE128.new(data=ptn(17**2)).read(32) + self.assertEqual(res, btv) + + def test_ptn_17_3(self): + tv = """D4 97 6E B5 6B CF 11 85 20 58 2B 70 9F 73 E1 D6 + 85 3E 00 1F DA F8 0E 1B 13 E0 D0 59 9D 5F B3 72""" + + btv = txt2bin(tv) + res = TurboSHAKE128.new(data=ptn(17**3)).read(32) + self.assertEqual(res, btv) + + def test_ptn_17_4(self): + tv = """DA 67 C7 03 9E 98 BF 53 0C F7 A3 78 30 C6 66 4E + 14 CB AB 7F 54 0F 58 40 3B 1B 82 95 13 18 EE 5C""" + + btv = txt2bin(tv) + data = ptn(17**4) + + # All at once + res = TurboSHAKE128.new(data=data).read(32) + self.assertEqual(res, btv) + + # Byte by byte + xof = TurboSHAKE128.new() + for x in data: + xof.update(bchr(x)) + res = xof.read(32) + self.assertEqual(res, btv) + + # Chunks of various prime sizes + for chunk_size in (13, 17, 19, 23, 31): + xof = TurboSHAKE128.new() + for x in chunked(data, chunk_size): + xof.update(x) + res = xof.read(32) + self.assertEqual(res, btv) + + def test_ptn_17_5(self): + tv = """B9 7A 90 6F BF 83 EF 7C 81 25 17 AB F3 B2 D0 AE + A0 C4 F6 03 18 CE 11 CF 10 39 25 12 7F 59 EE CD""" + + btv = txt2bin(tv) + data = ptn(17**5) + + # All at once + res = TurboSHAKE128.new(data=data).read(32) + self.assertEqual(res, btv) + + # Chunks + xof = TurboSHAKE128.new() + for chunk in chunked(data, 8192): + xof.update(chunk) + res = xof.read(32) + self.assertEqual(res, btv) + + def test_ptn_17_6(self): + tv = """35 CD 49 4A DE DE D2 F2 52 39 AF 09 A7 B8 EF 0C + 4D 1C A4 FE 2D 1A C3 70 FA 63 21 6F E7 B4 C2 B1""" + + btv = txt2bin(tv) + data = ptn(17**6) + + res = TurboSHAKE128.new(data=data).read(32) + self.assertEqual(res, btv) + + def test_ffffff_d01(self): + tv = """BF 32 3F 94 04 94 E8 8E E1 C5 40 FE 66 0B E8 A0 + C9 3F 43 D1 5E C0 06 99 84 62 FA 99 4E ED 5D AB""" + + btv = txt2bin(tv) + res = TurboSHAKE128.new(data=b"\xff\xff\xff", domain=0x01).read(32) + self.assertEqual(res, btv) + + def test_ff_d06(self): + tv = """8E C9 C6 64 65 ED 0D 4A 6C 35 D1 35 06 71 8D 68 + 7A 25 CB 05 C7 4C CA 1E 42 50 1A BD 83 87 4A 67""" + + btv = txt2bin(tv) + res = TurboSHAKE128.new(data=b'\xFF', domain=0x06).read(32) + self.assertEqual(res, btv) + + def test_ffffff_d07(self): + tv = """B6 58 57 60 01 CA D9 B1 E5 F3 99 A9 F7 77 23 BB + A0 54 58 04 2D 68 20 6F 72 52 68 2D BA 36 63 ED""" + + btv = txt2bin(tv) + res = TurboSHAKE128.new(data=b'\xFF' * 3, domain=0x07).read(32) + self.assertEqual(res, btv) + + def test_ffffffffffff_d0b(self): + tv = """8D EE AA 1A EC 47 CC EE 56 9F 65 9C 21 DF A8 E1 + 12 DB 3C EE 37 B1 81 78 B2 AC D8 05 B7 99 CC 37""" + + btv = txt2bin(tv) + res = TurboSHAKE128.new(data=b'\xFF' * 7, domain=0x0B).read(32) + self.assertEqual(res, btv) + + def test_ff_d30(self): + tv = """55 31 22 E2 13 5E 36 3C 32 92 BE D2 C6 42 1F A2 + 32 BA B0 3D AA 07 C7 D6 63 66 03 28 65 06 32 5B""" + + btv = txt2bin(tv) + res = TurboSHAKE128.new(data=b'\xFF', domain=0x30).read(32) + self.assertEqual(res, btv) + + def test_ffffff_d7f(self): + tv = """16 27 4C C6 56 D4 4C EF D4 22 39 5D 0F 90 53 BD + A6 D2 8E 12 2A BA 15 C7 65 E5 AD 0E 6E AF 26 F9""" + + btv = txt2bin(tv) + res = TurboSHAKE128.new(data=b'\xFF' * 3, domain=0x7F).read(32) + self.assertEqual(res, btv) + + +class TurboSHAKE256TV(unittest.TestCase): + + def test_zero_1(self): + tv = """36 7A 32 9D AF EA 87 1C 78 02 EC 67 F9 05 AE 13 + C5 76 95 DC 2C 66 63 C6 10 35 F5 9A 18 F8 E7 DB + 11 ED C0 E1 2E 91 EA 60 EB 6B 32 DF 06 DD 7F 00 + 2F BA FA BB 6E 13 EC 1C C2 0D 99 55 47 60 0D B0""" + + btv = txt2bin(tv) + res = TurboSHAKE256.new().read(64) + self.assertEqual(res, btv) + + def test_zero_2(self): + tv = """AB EF A1 16 30 C6 61 26 92 49 74 26 85 EC 08 2F + 20 72 65 DC CF 2F 43 53 4E 9C 61 BA 0C 9D 1D 75""" + + btv = txt2bin(tv) + res = TurboSHAKE256.new().read(10032)[-32:] + self.assertEqual(res, btv) + + def test_ptn_1(self): + tv = """3E 17 12 F9 28 F8 EA F1 05 46 32 B2 AA 0A 24 6E + D8 B0 C3 78 72 8F 60 BC 97 04 10 15 5C 28 82 0E + 90 CC 90 D8 A3 00 6A A2 37 2C 5C 5E A1 76 B0 68 + 2B F2 2B AE 74 67 AC 94 F7 4D 43 D3 9B 04 82 E2""" + + btv = txt2bin(tv) + res = TurboSHAKE256.new(data=ptn(1)).read(64) + self.assertEqual(res, btv) + + def test_ptn_17(self): + tv = """B3 BA B0 30 0E 6A 19 1F BE 61 37 93 98 35 92 35 + 78 79 4E A5 48 43 F5 01 10 90 FA 2F 37 80 A9 E5 + CB 22 C5 9D 78 B4 0A 0F BF F9 E6 72 C0 FB E0 97 + 0B D2 C8 45 09 1C 60 44 D6 87 05 4D A5 D8 E9 C7""" + + btv = txt2bin(tv) + res = TurboSHAKE256.new(data=ptn(17)).read(64) + self.assertEqual(res, btv) + + def test_ptn_17_2(self): + tv = """66 B8 10 DB 8E 90 78 04 24 C0 84 73 72 FD C9 57 + 10 88 2F DE 31 C6 DF 75 BE B9 D4 CD 93 05 CF CA + E3 5E 7B 83 E8 B7 E6 EB 4B 78 60 58 80 11 63 16 + FE 2C 07 8A 09 B9 4A D7 B8 21 3C 0A 73 8B 65 C0""" + + btv = txt2bin(tv) + res = TurboSHAKE256.new(data=ptn(17**2)).read(64) + self.assertEqual(res, btv) + + def test_ptn_17_3(self): + tv = """C7 4E BC 91 9A 5B 3B 0D D1 22 81 85 BA 02 D2 9E + F4 42 D6 9D 3D 42 76 A9 3E FE 0B F9 A1 6A 7D C0 + CD 4E AB AD AB 8C D7 A5 ED D9 66 95 F5 D3 60 AB + E0 9E 2C 65 11 A3 EC 39 7D A3 B7 6B 9E 16 74 FB""" + + btv = txt2bin(tv) + res = TurboSHAKE256.new(data=ptn(17**3)).read(64) + self.assertEqual(res, btv) + + def test_ptn_17_4(self): + tv = """02 CC 3A 88 97 E6 F4 F6 CC B6 FD 46 63 1B 1F 52 + 07 B6 6C 6D E9 C7 B5 5B 2D 1A 23 13 4A 17 0A FD + AC 23 4E AB A9 A7 7C FF 88 C1 F0 20 B7 37 24 61 + 8C 56 87 B3 62 C4 30 B2 48 CD 38 64 7F 84 8A 1D""" + + btv = txt2bin(tv) + data = ptn(17**4) + + # All at once + res = TurboSHAKE256.new(data=data).read(64) + self.assertEqual(res, btv) + + # Byte by byte + xof = TurboSHAKE256.new() + for x in data: + xof.update(bchr(x)) + res = xof.read(64) + self.assertEqual(res, btv) + + # Chunks of various prime sizes + for chunk_size in (13, 17, 19, 23, 31): + xof = TurboSHAKE256.new() + for x in chunked(data, chunk_size): + xof.update(x) + res = xof.read(64) + self.assertEqual(res, btv) + + def test_ptn_17_5(self): + tv = """AD D5 3B 06 54 3E 58 4B 58 23 F6 26 99 6A EE 50 + FE 45 ED 15 F2 02 43 A7 16 54 85 AC B4 AA 76 B4 + FF DA 75 CE DF 6D 8C DC 95 C3 32 BD 56 F4 B9 86 + B5 8B B1 7D 17 78 BF C1 B1 A9 75 45 CD F4 EC 9F""" + + btv = txt2bin(tv) + data = ptn(17**5) + + # All at once + res = TurboSHAKE256.new(data=data).read(64) + self.assertEqual(res, btv) + + # Chunks + xof = TurboSHAKE256.new() + for chunk in chunked(data, 8192): + xof.update(chunk) + res = xof.read(64) + self.assertEqual(res, btv) + + def test_ptn_17_6(self): + tv = """9E 11 BC 59 C2 4E 73 99 3C 14 84 EC 66 35 8E F7 + 1D B7 4A EF D8 4E 12 3F 78 00 BA 9C 48 53 E0 2C + FE 70 1D 9E 6B B7 65 A3 04 F0 DC 34 A4 EE 3B A8 + 2C 41 0F 0D A7 0E 86 BF BD 90 EA 87 7C 2D 61 04""" + + btv = txt2bin(tv) + data = ptn(17**6) + + res = TurboSHAKE256.new(data=data).read(64) + self.assertEqual(res, btv) + + def test_ffffff_d01(self): + tv = """D2 1C 6F BB F5 87 FA 22 82 F2 9A EA 62 01 75 FB + 02 57 41 3A F7 8A 0B 1B 2A 87 41 9C E0 31 D9 33 + AE 7A 4D 38 33 27 A8 A1 76 41 A3 4F 8A 1D 10 03 + AD 7D A6 B7 2D BA 84 BB 62 FE F2 8F 62 F1 24 24""" + + btv = txt2bin(tv) + res = TurboSHAKE256.new(data=b"\xff\xff\xff", domain=0x01).read(64) + self.assertEqual(res, btv) + + def test_ff_d06(self): + tv = """73 8D 7B 4E 37 D1 8B 7F 22 AD 1B 53 13 E3 57 E3 + DD 7D 07 05 6A 26 A3 03 C4 33 FA 35 33 45 52 80 + F4 F5 A7 D4 F7 00 EF B4 37 FE 6D 28 14 05 E0 7B + E3 2A 0A 97 2E 22 E6 3A DC 1B 09 0D AE FE 00 4B""" + + btv = txt2bin(tv) + res = TurboSHAKE256.new(data=b'\xFF', domain=0x06).read(64) + self.assertEqual(res, btv) + + def test_ffffff_d07(self): + tv = """18 B3 B5 B7 06 1C 2E 67 C1 75 3A 00 E6 AD 7E D7 + BA 1C 90 6C F9 3E FB 70 92 EA F2 7F BE EB B7 55 + AE 6E 29 24 93 C1 10 E4 8D 26 00 28 49 2B 8E 09 + B5 50 06 12 B8 F2 57 89 85 DE D5 35 7D 00 EC 67""" + + btv = txt2bin(tv) + res = TurboSHAKE256.new(data=b'\xFF' * 3, domain=0x07).read(64) + self.assertEqual(res, btv) + + def test_ffffffffffff_d0b(self): + tv = """BB 36 76 49 51 EC 97 E9 D8 5F 7E E9 A6 7A 77 18 + FC 00 5C F4 25 56 BE 79 CE 12 C0 BD E5 0E 57 36 + D6 63 2B 0D 0D FB 20 2D 1B BB 8F FE 3D D7 4C B0 + 08 34 FA 75 6C B0 34 71 BA B1 3A 1E 2C 16 B3 C0""" + + btv = txt2bin(tv) + res = TurboSHAKE256.new(data=b'\xFF' * 7, domain=0x0B).read(64) + self.assertEqual(res, btv) + + def test_ff_d30(self): + tv = """F3 FE 12 87 3D 34 BC BB 2E 60 87 79 D6 B7 0E 7F + 86 BE C7 E9 0B F1 13 CB D4 FD D0 C4 E2 F4 62 5E + 14 8D D7 EE 1A 52 77 6C F7 7F 24 05 14 D9 CC FC + 3B 5D DA B8 EE 25 5E 39 EE 38 90 72 96 2C 11 1A""" + + btv = txt2bin(tv) + res = TurboSHAKE256.new(data=b'\xFF', domain=0x30).read(64) + self.assertEqual(res, btv) + + def test_ffffff_d7f(self): + tv = """AB E5 69 C1 F7 7E C3 40 F0 27 05 E7 D3 7C 9A B7 + E1 55 51 6E 4A 6A 15 00 21 D7 0B 6F AC 0B B4 0C + 06 9F 9A 98 28 A0 D5 75 CD 99 F9 BA E4 35 AB 1A + CF 7E D9 11 0B A9 7C E0 38 8D 07 4B AC 76 87 76""" + + btv = txt2bin(tv) + res = TurboSHAKE256.new(data=b'\xFF' * 3, domain=0x7F).read(64) + self.assertEqual(res, btv) + + +def get_tests(config={}): + tests = [] + tests += list_test_cases(TurboSHAKE128Test) + tests += list_test_cases(TurboSHAKE256Test) + tests += list_test_cases(TurboSHAKE128TV) + tests += list_test_cases(TurboSHAKE256TV) + return tests + + +if __name__ == '__main__': + def suite(): + return unittest.TestSuite(get_tests()) + unittest.main(defaultTest='suite') diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/test_cSHAKE.py b/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/test_cSHAKE.py new file mode 100644 index 0000000..6797160 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/test_cSHAKE.py @@ -0,0 +1,178 @@ +# =================================================================== +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# =================================================================== + +"""Self-test suite for Cryptodome.Hash.cSHAKE128 and cSHAKE256""" + +import unittest + +from Cryptodome.SelfTest.loader import load_test_vectors +from Cryptodome.SelfTest.st_common import list_test_cases + +from Cryptodome.Hash import cSHAKE128, cSHAKE256, SHAKE128, SHAKE256 +from Cryptodome.Util.py3compat import b, bchr, tobytes + + +class cSHAKETest(unittest.TestCase): + + def test_left_encode(self): + from Cryptodome.Hash.cSHAKE128 import _left_encode + self.assertEqual(_left_encode(0), b'\x01\x00') + self.assertEqual(_left_encode(1), b'\x01\x01') + self.assertEqual(_left_encode(256), b'\x02\x01\x00') + + def test_bytepad(self): + from Cryptodome.Hash.cSHAKE128 import _bytepad + self.assertEqual(_bytepad(b'', 4), b'\x01\x04\x00\x00') + self.assertEqual(_bytepad(b'A', 4), b'\x01\x04A\x00') + self.assertEqual(_bytepad(b'AA', 4), b'\x01\x04AA') + self.assertEqual(_bytepad(b'AAA', 4), b'\x01\x04AAA\x00\x00\x00') + self.assertEqual(_bytepad(b'AAAA', 4), b'\x01\x04AAAA\x00\x00') + self.assertEqual(_bytepad(b'AAAAA', 4), b'\x01\x04AAAAA\x00') + self.assertEqual(_bytepad(b'AAAAAA', 4), b'\x01\x04AAAAAA') + self.assertEqual(_bytepad(b'AAAAAAA', 4), b'\x01\x04AAAAAAA\x00\x00\x00') + + def test_new_positive(self): + + xof1 = self.cshake.new() + xof2 = self.cshake.new(data=b("90")) + xof3 = self.cshake.new().update(b("90")) + + self.assertNotEqual(xof1.read(10), xof2.read(10)) + xof3.read(10) + self.assertEqual(xof2.read(10), xof3.read(10)) + + xof1 = self.cshake.new() + ref = xof1.read(10) + xof2 = self.cshake.new(custom=b("")) + xof3 = self.cshake.new(custom=b("foo")) + + self.assertEqual(ref, xof2.read(10)) + self.assertNotEqual(ref, xof3.read(10)) + + xof1 = self.cshake.new(custom=b("foo")) + xof2 = self.cshake.new(custom=b("foo"), data=b("90")) + xof3 = self.cshake.new(custom=b("foo")).update(b("90")) + + self.assertNotEqual(xof1.read(10), xof2.read(10)) + xof3.read(10) + self.assertEqual(xof2.read(10), xof3.read(10)) + + def test_update(self): + pieces = [bchr(10) * 200, bchr(20) * 300] + h = self.cshake.new() + h.update(pieces[0]).update(pieces[1]) + digest = h.read(10) + h = self.cshake.new() + h.update(pieces[0] + pieces[1]) + self.assertEqual(h.read(10), digest) + + def test_update_negative(self): + h = self.cshake.new() + self.assertRaises(TypeError, h.update, u"string") + + def test_digest(self): + h = self.cshake.new() + digest = h.read(90) + + # read returns a byte string of the right length + self.assertTrue(isinstance(digest, type(b("digest")))) + self.assertEqual(len(digest), 90) + + def test_update_after_read(self): + mac = self.cshake.new() + mac.update(b("rrrr")) + mac.read(90) + self.assertRaises(TypeError, mac.update, b("ttt")) + + def test_shake(self): + # When no customization string is passed, results must match SHAKE + for digest_len in range(64): + xof1 = self.cshake.new(b'TEST') + xof2 = self.shake.new(b'TEST') + self.assertEqual(xof1.read(digest_len), xof2.read(digest_len)) + + +class cSHAKE128Test(cSHAKETest): + cshake = cSHAKE128 + shake = SHAKE128 + + +class cSHAKE256Test(cSHAKETest): + cshake = cSHAKE256 + shake = SHAKE256 + + +class cSHAKEVectors(unittest.TestCase): + pass + + +vector_files = [("ShortMsgSamples_cSHAKE128.txt", "Short Message Samples cSHAKE128", "128_cshake", cSHAKE128), + ("ShortMsgSamples_cSHAKE256.txt", "Short Message Samples cSHAKE256", "256_cshake", cSHAKE256), + ("CustomMsgSamples_cSHAKE128.txt", "Custom Message Samples cSHAKE128", "custom_128_cshake", cSHAKE128), + ("CustomMsgSamples_cSHAKE256.txt", "Custom Message Samples cSHAKE256", "custom_256_cshake", cSHAKE256), + ] + +for file, descr, tag, test_class in vector_files: + + test_vectors = load_test_vectors(("Hash", "SHA3"), file, descr, + {"len": lambda x: int(x), + "nlen": lambda x: int(x), + "slen": lambda x: int(x)}) or [] + + for idx, tv in enumerate(test_vectors): + if getattr(tv, "len", 0) == 0: + data = b("") + else: + data = tobytes(tv.msg) + assert(tv.len == len(tv.msg)*8) + if getattr(tv, "nlen", 0) != 0: + raise ValueError("Unsupported cSHAKE test vector") + if getattr(tv, "slen", 0) == 0: + custom = b("") + else: + custom = tobytes(tv.s) + assert(tv.slen == len(tv.s)*8) + + def new_test(self, data=data, result=tv.md, custom=custom, test_class=test_class): + hobj = test_class.new(data=data, custom=custom) + digest = hobj.read(len(result)) + self.assertEqual(digest, result) + + setattr(cSHAKEVectors, "test_%s_%d" % (tag, idx), new_test) + + +def get_tests(config={}): + tests = [] + tests += list_test_cases(cSHAKE128Test) + tests += list_test_cases(cSHAKE256Test) + tests += list_test_cases(cSHAKEVectors) + return tests + + +if __name__ == '__main__': + import unittest + suite = lambda: unittest.TestSuite(get_tests()) + unittest.main(defaultTest='suite') diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/test_keccak.py b/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/test_keccak.py new file mode 100644 index 0000000..dcc0d13 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/SelfTest/Hash/test_keccak.py @@ -0,0 +1,250 @@ +# =================================================================== +# +# Copyright (c) 2015, Legrandin +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# =================================================================== + +"""Self-test suite for Cryptodome.Hash.keccak""" + +import unittest +from binascii import hexlify, unhexlify + +from Cryptodome.SelfTest.loader import load_test_vectors +from Cryptodome.SelfTest.st_common import list_test_cases + +from Cryptodome.Hash import keccak +from Cryptodome.Util.py3compat import b, tobytes, bchr + +class KeccakTest(unittest.TestCase): + + def test_new_positive(self): + + for digest_bits in (224, 256, 384, 512): + hobj = keccak.new(digest_bits=digest_bits) + self.assertEqual(hobj.digest_size, digest_bits // 8) + + hobj2 = hobj.new() + self.assertEqual(hobj2.digest_size, digest_bits // 8) + + for digest_bytes in (28, 32, 48, 64): + hobj = keccak.new(digest_bytes=digest_bytes) + self.assertEqual(hobj.digest_size, digest_bytes) + + hobj2 = hobj.new() + self.assertEqual(hobj2.digest_size, digest_bytes) + + def test_new_positive2(self): + + digest1 = keccak.new(data=b("\x90"), digest_bytes=64).digest() + digest2 = keccak.new(digest_bytes=64).update(b("\x90")).digest() + self.assertEqual(digest1, digest2) + + def test_new_negative(self): + + # keccak.new needs digest size + self.assertRaises(TypeError, keccak.new) + + h = keccak.new(digest_bits=512) + + # Either bits or bytes can be specified + self.assertRaises(TypeError, keccak.new, + digest_bytes=64, + digest_bits=512) + + # Range + self.assertRaises(ValueError, keccak.new, digest_bytes=0) + self.assertRaises(ValueError, keccak.new, digest_bytes=1) + self.assertRaises(ValueError, keccak.new, digest_bytes=65) + self.assertRaises(ValueError, keccak.new, digest_bits=0) + self.assertRaises(ValueError, keccak.new, digest_bits=1) + self.assertRaises(ValueError, keccak.new, digest_bits=513) + + def test_update(self): + pieces = [bchr(10) * 200, bchr(20) * 300] + h = keccak.new(digest_bytes=64) + h.update(pieces[0]).update(pieces[1]) + digest = h.digest() + h = keccak.new(digest_bytes=64) + h.update(pieces[0] + pieces[1]) + self.assertEqual(h.digest(), digest) + + def test_update_negative(self): + h = keccak.new(digest_bytes=64) + self.assertRaises(TypeError, h.update, u"string") + + def test_digest(self): + h = keccak.new(digest_bytes=64) + digest = h.digest() + + # hexdigest does not change the state + self.assertEqual(h.digest(), digest) + # digest returns a byte string + self.assertTrue(isinstance(digest, type(b("digest")))) + + def test_hex_digest(self): + mac = keccak.new(digest_bits=512) + digest = mac.digest() + hexdigest = mac.hexdigest() + + # hexdigest is equivalent to digest + self.assertEqual(hexlify(digest), tobytes(hexdigest)) + # hexdigest does not change the state + self.assertEqual(mac.hexdigest(), hexdigest) + # hexdigest returns a string + self.assertTrue(isinstance(hexdigest, type("digest"))) + + def test_update_after_digest(self): + msg=b("rrrrttt") + + # Normally, update() cannot be done after digest() + h = keccak.new(digest_bits=512, data=msg[:4]) + dig1 = h.digest() + self.assertRaises(TypeError, h.update, msg[4:]) + dig2 = keccak.new(digest_bits=512, data=msg).digest() + + # With the proper flag, it is allowed + h = keccak.new(digest_bits=512, data=msg[:4], update_after_digest=True) + self.assertEqual(h.digest(), dig1) + # ... and the subsequent digest applies to the entire message + # up to that point + h.update(msg[4:]) + self.assertEqual(h.digest(), dig2) + + +class KeccakVectors(unittest.TestCase): + pass + + # TODO: add ExtremelyLong tests + + +test_vectors_224 = load_test_vectors(("Hash", "keccak"), + "ShortMsgKAT_224.txt", + "Short Messages KAT 224", + {"len": lambda x: int(x)}) or [] + +test_vectors_224 += load_test_vectors(("Hash", "keccak"), + "LongMsgKAT_224.txt", + "Long Messages KAT 224", + {"len": lambda x: int(x)}) or [] + +for idx, tv in enumerate(test_vectors_224): + if tv.len == 0: + data = b("") + else: + data = tobytes(tv.msg) + + def new_test(self, data=data, result=tv.md): + hobj = keccak.new(digest_bits=224, data=data) + self.assertEqual(hobj.digest(), result) + + setattr(KeccakVectors, "test_224_%d" % idx, new_test) + +# --- + +test_vectors_256 = load_test_vectors(("Hash", "keccak"), + "ShortMsgKAT_256.txt", + "Short Messages KAT 256", + { "len" : lambda x: int(x) } ) or [] + +test_vectors_256 += load_test_vectors(("Hash", "keccak"), + "LongMsgKAT_256.txt", + "Long Messages KAT 256", + { "len" : lambda x: int(x) } ) or [] + +for idx, tv in enumerate(test_vectors_256): + if tv.len == 0: + data = b("") + else: + data = tobytes(tv.msg) + + def new_test(self, data=data, result=tv.md): + hobj = keccak.new(digest_bits=256, data=data) + self.assertEqual(hobj.digest(), result) + + setattr(KeccakVectors, "test_256_%d" % idx, new_test) + + +# --- + +test_vectors_384 = load_test_vectors(("Hash", "keccak"), + "ShortMsgKAT_384.txt", + "Short Messages KAT 384", + {"len": lambda x: int(x)}) or [] + +test_vectors_384 += load_test_vectors(("Hash", "keccak"), + "LongMsgKAT_384.txt", + "Long Messages KAT 384", + {"len": lambda x: int(x)}) or [] + +for idx, tv in enumerate(test_vectors_384): + if tv.len == 0: + data = b("") + else: + data = tobytes(tv.msg) + + def new_test(self, data=data, result=tv.md): + hobj = keccak.new(digest_bits=384, data=data) + self.assertEqual(hobj.digest(), result) + + setattr(KeccakVectors, "test_384_%d" % idx, new_test) + +# --- + +test_vectors_512 = load_test_vectors(("Hash", "keccak"), + "ShortMsgKAT_512.txt", + "Short Messages KAT 512", + {"len": lambda x: int(x)}) or [] + +test_vectors_512 += load_test_vectors(("Hash", "keccak"), + "LongMsgKAT_512.txt", + "Long Messages KAT 512", + {"len": lambda x: int(x)}) or [] + +for idx, tv in enumerate(test_vectors_512): + if tv.len == 0: + data = b("") + else: + data = tobytes(tv.msg) + + def new_test(self, data=data, result=tv.md): + hobj = keccak.new(digest_bits=512, data=data) + self.assertEqual(hobj.digest(), result) + + setattr(KeccakVectors, "test_512_%d" % idx, new_test) + + +def get_tests(config={}): + tests = [] + tests += list_test_cases(KeccakTest) + tests += list_test_cases(KeccakVectors) + return tests + + +if __name__ == '__main__': + import unittest + suite = lambda: unittest.TestSuite(get_tests()) + unittest.main(defaultTest='suite') diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/IO/__init__.py b/venv/Lib/site-packages/Cryptodome/SelfTest/IO/__init__.py new file mode 100644 index 0000000..f15f141 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/SelfTest/IO/__init__.py @@ -0,0 +1,47 @@ +# +# SelfTest/IO/__init__.py: Self-test for input/output module +# +# =================================================================== +# +# Copyright (c) 2014, Legrandin +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# =================================================================== + +"""Self-test for I/O""" + +def get_tests(config={}): + tests = [] + from Cryptodome.SelfTest.IO import test_PKCS8; tests += test_PKCS8.get_tests(config=config) + from Cryptodome.SelfTest.IO import test_PBES; tests += test_PBES.get_tests(config=config) + return tests + +if __name__ == '__main__': + import unittest + suite = lambda: unittest.TestSuite(get_tests()) + unittest.main(defaultTest='suite') + + diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/IO/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/SelfTest/IO/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000..2958b27 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/SelfTest/IO/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/IO/__pycache__/test_PBES.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/SelfTest/IO/__pycache__/test_PBES.cpython-312.pyc new file mode 100644 index 0000000..e2b4004 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/SelfTest/IO/__pycache__/test_PBES.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/IO/__pycache__/test_PKCS8.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/SelfTest/IO/__pycache__/test_PKCS8.cpython-312.pyc new file mode 100644 index 0000000..92420d4 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/SelfTest/IO/__pycache__/test_PKCS8.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/IO/test_PBES.py b/venv/Lib/site-packages/Cryptodome/SelfTest/IO/test_PBES.py new file mode 100644 index 0000000..19762f3 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/SelfTest/IO/test_PBES.py @@ -0,0 +1,118 @@ +# +# SelfTest/IO/test_PBES.py: Self-test for the _PBES module +# +# =================================================================== +# +# Copyright (c) 2014, Legrandin +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# =================================================================== + +"""Self-tests for Cryptodome.IO._PBES module""" + +import unittest + +from Cryptodome.IO._PBES import PBES2 + + +class TestPBES2(unittest.TestCase): + + def setUp(self): + self.ref = b"Test data" + self.passphrase = b"Passphrase" + + def test1(self): + ct = PBES2.encrypt(self.ref, self.passphrase, + 'PBKDF2WithHMAC-SHA1AndDES-EDE3-CBC') + pt = PBES2.decrypt(ct, self.passphrase) + self.assertEqual(self.ref, pt) + + def test2(self): + ct = PBES2.encrypt(self.ref, self.passphrase, + 'PBKDF2WithHMAC-SHA224AndAES128-CBC') + pt = PBES2.decrypt(ct, self.passphrase) + self.assertEqual(self.ref, pt) + + def test3(self): + ct = PBES2.encrypt(self.ref, self.passphrase, + 'PBKDF2WithHMAC-SHA256AndAES192-CBC') + pt = PBES2.decrypt(ct, self.passphrase) + self.assertEqual(self.ref, pt) + + def test4(self): + ct = PBES2.encrypt(self.ref, self.passphrase, + 'PBKDF2WithHMAC-SHA384AndAES256-CBC') + pt = PBES2.decrypt(ct, self.passphrase) + self.assertEqual(self.ref, pt) + + def test5(self): + ct = PBES2.encrypt(self.ref, self.passphrase, + 'PBKDF2WithHMAC-SHA512AndAES128-GCM') + pt = PBES2.decrypt(ct, self.passphrase) + self.assertEqual(self.ref, pt) + + def test6(self): + ct = PBES2.encrypt(self.ref, self.passphrase, + 'PBKDF2WithHMAC-SHA512-224AndAES192-GCM') + pt = PBES2.decrypt(ct, self.passphrase) + self.assertEqual(self.ref, pt) + + def test7(self): + ct = PBES2.encrypt(self.ref, self.passphrase, + 'PBKDF2WithHMAC-SHA3-256AndAES256-GCM') + pt = PBES2.decrypt(ct, self.passphrase) + self.assertEqual(self.ref, pt) + + def test8(self): + ct = PBES2.encrypt(self.ref, self.passphrase, + 'scryptAndAES128-CBC') + pt = PBES2.decrypt(ct, self.passphrase) + self.assertEqual(self.ref, pt) + + def test9(self): + ct = PBES2.encrypt(self.ref, self.passphrase, + 'scryptAndAES192-CBC') + pt = PBES2.decrypt(ct, self.passphrase) + self.assertEqual(self.ref, pt) + + def test10(self): + ct = PBES2.encrypt(self.ref, self.passphrase, + 'scryptAndAES256-CBC') + pt = PBES2.decrypt(ct, self.passphrase) + self.assertEqual(self.ref, pt) + + +def get_tests(config={}): + from Cryptodome.SelfTest.st_common import list_test_cases + listTests = [] + listTests += list_test_cases(TestPBES2) + return listTests + + +if __name__ == '__main__': + def suite(): + return unittest.TestSuite(get_tests()) + unittest.main(defaultTest='suite') diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/IO/test_PKCS8.py b/venv/Lib/site-packages/Cryptodome/SelfTest/IO/test_PKCS8.py new file mode 100644 index 0000000..718b69d --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/SelfTest/IO/test_PKCS8.py @@ -0,0 +1,459 @@ +# +# SelfTest/IO/test_PKCS8.py: Self-test for the PKCS8 module +# +# =================================================================== +# +# Copyright (c) 2014, Legrandin +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# =================================================================== + +"""Self-tests for Cryptodome.IO.PKCS8 module""" + +import unittest +from binascii import unhexlify + +from Cryptodome.Util.py3compat import * +from Cryptodome.IO import PKCS8 + +from Cryptodome.Util.asn1 import DerNull + +oid_key = '1.2.840.113549.1.1.1' + +# Original RSA key (in DER format) +# hexdump -v -e '32/1 "%02x" "\n"' key.der +clear_key=""" +308201ab020100025a00b94a7f7075ab9e79e8196f47be707781e80dd965cf16 +0c951a870b71783b6aaabbd550c0e65e5a3dfe15b8620009f6d7e5efec42a3f0 +6fe20faeebb0c356e79cdec6db4dd427e82d8ae4a5b90996227b8ba54ccfc4d2 +5c08050203010001025a00afa09c70d528299b7552fe766b5d20f9a221d66938 +c3b68371d48515359863ff96f0978d700e08cd6fd3d8a3f97066fc2e0d5f78eb +3a50b8e17ba297b24d1b8e9cdfd18d608668198d724ad15863ef0329195dee89 +3f039395022d0ebe0518df702a8b25954301ec60a97efdcec8eaa4f2e76ca7e8 +8dfbc3f7e0bb83f9a0e8dc47c0f8c746e9df6b022d0c9195de13f09b7be1fdd7 +1f56ae7d973e08bd9fd2c3dfd8936bb05be9cc67bd32d663c7f00d70932a0be3 +c24f022d0ac334eb6cabf1933633db007b763227b0d9971a9ea36aca8b669ec9 +4fcf16352f6b3dcae28e4bd6137db4ddd3022d0400a09f15ee7b351a2481cb03 +09920905c236d09c87afd3022f3afc2a19e3b746672b635238956ee7e6dd62d5 +022d0cd88ed14fcfbda5bbf0257f700147137bbab9c797af7df866704b889aa3 +7e2e93df3ff1a0fd3490111dcdbc4c +""" + +# Same key as above, wrapped in PKCS#8 but w/o password +# +# openssl pkcs8 -topk8 -inform DER -nocrypt -in key.der -outform DER -out keyp8.der +# hexdump -v -e '32/1 "%02x" "\n"' keyp8.der +wrapped_clear_key=""" +308201c5020100300d06092a864886f70d0101010500048201af308201ab0201 +00025a00b94a7f7075ab9e79e8196f47be707781e80dd965cf160c951a870b71 +783b6aaabbd550c0e65e5a3dfe15b8620009f6d7e5efec42a3f06fe20faeebb0 +c356e79cdec6db4dd427e82d8ae4a5b90996227b8ba54ccfc4d25c0805020301 +0001025a00afa09c70d528299b7552fe766b5d20f9a221d66938c3b68371d485 +15359863ff96f0978d700e08cd6fd3d8a3f97066fc2e0d5f78eb3a50b8e17ba2 +97b24d1b8e9cdfd18d608668198d724ad15863ef0329195dee893f039395022d +0ebe0518df702a8b25954301ec60a97efdcec8eaa4f2e76ca7e88dfbc3f7e0bb +83f9a0e8dc47c0f8c746e9df6b022d0c9195de13f09b7be1fdd71f56ae7d973e +08bd9fd2c3dfd8936bb05be9cc67bd32d663c7f00d70932a0be3c24f022d0ac3 +34eb6cabf1933633db007b763227b0d9971a9ea36aca8b669ec94fcf16352f6b +3dcae28e4bd6137db4ddd3022d0400a09f15ee7b351a2481cb0309920905c236 +d09c87afd3022f3afc2a19e3b746672b635238956ee7e6dd62d5022d0cd88ed1 +4fcfbda5bbf0257f700147137bbab9c797af7df866704b889aa37e2e93df3ff1 +a0fd3490111dcdbc4c +""" + +### +# +# The key above will now be encrypted with different algorithms. +# The password is always 'TestTest'. +# +# Each item in the wrapped_enc_keys list contains: +# * wrap algorithm +# * iteration count +# * Salt +# * IV +# * Expected result +### +wrapped_enc_keys = [] + +# +# openssl pkcs8 -topk8 -passin pass:TestTest -inform DER -in key.der -outform DER -out keyenc.der -v2 des3 +# hexdump -v -e '32/1 "%02x" "\n"' keyenc.der +# +wrapped_enc_keys.append(( +'PBKDF2WithHMAC-SHA1AndDES-EDE3-CBC', +2048, +"47EA7227D8B22E2F", # IV +"E3F7A838AB911A4D", # Salt +""" +30820216304006092a864886f70d01050d3033301b06092a864886f70d01050c +300e0408e3f7a838ab911a4d02020800301406082a864886f70d0307040847ea +7227d8b22e2f048201d0ea388b374d2d0e4ceb7a5139f850fdff274884a6e6c0 +64326e09d00dbba9018834edb5a51a6ae3d1806e6e91eebf33788ce71fee0637 +a2ebf58859dd32afc644110c390274a6128b50c39b8d907823810ec471bada86 +6f5b75d8ea04ad310fad2e73621696db8e426cd511ee93ec1714a1a7db45e036 +4bf20d178d1f16bbb250b32c2d200093169d588de65f7d99aad9ddd0104b44f1 +326962e1520dfac3c2a800e8a14f678dff2b3d0bb23f69da635bf2a643ac934e +219a447d2f4460b67149e860e54f365da130763deefa649c72b0dcd48966a2d3 +4a477444782e3e66df5a582b07bbb19778a79bd355074ce331f4a82eb966b0c4 +52a09eab6116f2722064d314ae433b3d6e81d2436e93fdf446112663cde93b87 +9c8be44beb45f18e2c78fee9b016033f01ecda51b9b142091fa69f65ab784d2c +5ad8d34be6f7f1464adfc1e0ef3f7848f40d3bdea4412758f2fcb655c93d8f4d +f6fa48fc5aa4b75dd1c017ab79ac9d737233a6d668f5364ccf47786debd37334 +9c10c9e6efbe78430a61f71c89948aa32cdc3cc7338cf994147819ce7ab23450 +c8f7d9b94c3bb377d17a3fa204b601526317824b142ff6bc843fa7815ece89c0 +839573f234dac8d80cc571a045353d61db904a4398d8ef3df5ac +""" +)) + +# +# openssl pkcs8 -topk8 -passin pass:TestTest -inform DER -in key.der -outform DER -out keyenc.der +# hexdump -v -e '32/1 "%02x" "\n"' keyenc.der +# +wrapped_enc_keys.append(( +'skip encryption', # pbeWithMD5AndDES-CBC, only decoding is supported +-1, +"", +"", +""" +308201f1301b06092a864886f70d010503300e0408f9b990c89af1d41b020208 +00048201d0c6267fe8592903891933d559e71a7ca68b2e39150f19daca0f7921 +52f97e249d72f670d5140e9150433310ed7c7ee51927693fd39884cb9551cea5 +a7b746f7edf199f8787d4787a35dad930d7db057b2118851211b645ac8b90fa6 +b0e7d49ac8567cbd5fff226e87aa9129a0f52c45e9307752e8575c3b0ff756b7 +31fda6942d15ecb6b27ea19370ccc79773f47891e80d22b440d81259c4c28eac +e0ca839524116bcf52d8c566e49a95ddb0e5493437279a770a39fd333f3fca91 +55884fad0ba5aaf273121f893059d37dd417da7dcfd0d6fa7494968f13b2cc95 +65633f2c891340193e5ec00e4ee0b0e90b3b93da362a4906360845771ade1754 +9df79140be5993f3424c012598eadd3e7c7c0b4db2c72cf103d7943a5cf61420 +93370b9702386c3dd4eb0a47f34b579624a46a108b2d13921fa1b367495fe345 +6aa128aa70f8ca80ae13eb301e96c380724ce67c54380bbea2316c1faf4d058e +b4ca2e23442047606b9bc4b3bf65b432cb271bea4eb35dd3eb360d3be8612a87 +a50e96a2264490aeabdc07c6e78e5dbf4fe3388726d0e2a228346bf3c2907d68 +2a6276b22ae883fb30fa611f4e4193e7a08480fcd7db48308bacbd72bf4807aa +11fd394859f97d22982f7fe890b2e2a0f7e7ffb693 +""" +)) + +# +# openssl pkcs8 -topk8 -passin pass:TestTest -inform DER -in key.der +# -outform DER -out keyenc.der -v1 PBE-SHA1-RC2-64 +# hexdump -v -e '32/1 "%02x" "\n"' keyenc.der +# +wrapped_enc_keys.append(( +'skip encryption', # pbeWithSHA1AndRC2-CBC, only decoding is supported +-1, +"", +"", +""" +308201f1301b06092a864886f70d01050b300e04083ee943bdae185008020208 +00048201d0e4614d9371d3ff10ceabc2f6a7a13a0f449f9a714144e46518ea55 +e3e6f0cde24031d01ef1f37ec40081449ef01914faf45983dde0d2bc496712de +8dd15a5527dff4721d9016c13f34fb93e3ce68577e30146266d71b539f854e56 +753a192cf126ed4812734d86f81884374f1100772f78d0646e9946407637c565 +d070acab413c55952f7237437f2e48cae7fa0ff8d370de2bf446dd08049a3663 +d9c813ac197468c02e2b687e7ca994cf7f03f01b6eca87dbfed94502c2094157 +ea39f73fe4e591df1a68b04d19d9adab90bb9898467c1464ad20bf2b8fb9a5ff +d3ec91847d1c67fd768a4b9cfb46572eccc83806601372b6fad0243f58f623b7 +1c5809dea0feb8278fe27e5560eed8448dc93f5612f546e5dd7c5f6404365eb2 +5bf3396814367ae8b15c5c432b57eaed1f882c05c7f6517ee9e42b87b7b8d071 +9d6125d1b52f7b2cca1f6bd5f584334bf90bce1a7d938274cafe27b68e629698 +b16e27ae528db28593af9adcfccbebb3b9e1f2af5cd5531b51968389caa6c091 +e7de1f1b96f0d258e54e540d961a7c0ef51fda45d6da5fddd33e9bbfd3a5f8d7 +d7ab2e971de495cddbc86d38444fee9f0ac097b00adaf7802dabe0cff5b43b45 +4f26b7b547016f89be52676866189911c53e2f2477""" +)) + +# +# openssl pkcs8 -topk8 -passin pass:TestTest -inform DER -in key.der +# -outform DER -out keyenc.der -v1 PBE-MD5-RC2-64 +# hexdump -v -e '32/1 "%02x" "\n"' keyenc.der +# +wrapped_enc_keys.append(( +'skip encryption', # pbeWithMD5AndRC2-CBC, only decoding is supported +-1, +"", +"", +""" +308201f1301b06092a864886f70d010506300e0408f5cd2fee56d9b4b8020208 +00048201d086454942d6166a19d6b108465bd111e7080911f573d54b1369c676 +df28600e84936bfec04f91023ff16499e2e07178c340904f12ffa6886ab66228 +32bf43c2bff5a0ed14e765918cf5fc543ad49566246f7eb3fc044fa5a9c25f40 +8fc8c8296b91658d3bb1067c0aba008c4fefd9e2bcdbbbd63fdc8085482bccf4 +f150cec9a084259ad441a017e5d81a1034ef2484696a7a50863836d0eeda45cd +8cee8ecabfed703f8d9d4bbdf3a767d32a0ccdc38550ee2928d7fe3fa27eda5b +5c7899e75ad55d076d2c2d3c37d6da3d95236081f9671dab9a99afdb1cbc890e +332d1a91105d9a8ce08b6027aa07367bd1daec3059cb51f5d896124da16971e4 +0ca4bcadb06c854bdf39f42dd24174011414e51626d198775eff3449a982df7b +ace874e77e045eb6d7c3faef0750792b29a068a6291f7275df1123fac5789c51 +27ace42836d81633faf9daf38f6787fff0394ea484bbcd465b57d4dbee3cf8df +b77d1db287b3a6264c466805be5a4fe85cfbca180699859280f2dd8e2c2c10b5 +7a7d2ac670c6039d41952fbb0e4f99b560ebe1d020e1b96d02403283819c00cc +529c51f0b0101555e4c58002ba3c6e3c12e3fde1aec94382792e96d9666a2b33 +3dc397b22ecab67ee38a552fec29a1d4ff8719c748""" +)) + +# +# openssl pkcs8 -topk8 -passin pass:TestTest -inform DER -in key.der +# -outform DER -out keyenc.der -v1 PBE-SHA1-DES +# hexdump -v -e '32/1 "%02x" "\n"' keyenc.der +# +wrapped_enc_keys.append(( +'skip encryption', # pbeWithSHA1AndDES-CBC, only decoding is supported +-1, +"", +"", +""" +308201f1301b06092a864886f70d01050a300e04089bacc9cf1e8f734e020208 +00048201d03e502f3ceafe8fd19ab2939576bfdded26d719b2441db1459688f5 +9673218b41ec1f739edf1e460bd927bc28470c87b2d4fc8ea02ba17b47a63c49 +c5c1bee40529dadfd3ef8b4472c730bc136678c78abfb34670ec9d7dcd17ee3f +892f93f2629e6e0f4b24ecb9f954069bf722f466dece3913bb6abbd2c471d9a5 +c5eea89b14aaccda43d30b0dd0f6eb6e9850d9747aa8aa8414c383ad01c374ee +26d3552abec9ba22669cc9622ccf2921e3d0c8ecd1a70e861956de0bec6104b5 +b649ac994970c83f8a9e84b14a7dff7843d4ca3dd4af87cea43b5657e15ae0b5 +a940ce5047f006ab3596506600724764f23757205fe374fee04911336d655acc +03e159ec27789191d1517c4f3f9122f5242d44d25eab8f0658cafb928566ca0e +8f6589aa0c0ab13ca7a618008ae3eafd4671ee8fe0b562e70b3623b0e2a16eee +97fd388087d2e03530c9fe7db6e52eccc7c48fd701ede35e08922861a9508d12 +bc8bbf24f0c6bee6e63dbcb489b603d4c4a78ce45bf2eab1d5d10456c42a65a8 +3a606f4e4b9b46eb13b57f2624b651859d3d2d5192b45dbd5a2ead14ff20ca76 +48f321309aa56d8c0c4a192b580821cc6c70c75e6f19d1c5414da898ec4dd39d +b0eb93d6ba387a80702dfd2db610757ba340f63230 +""" +)) + +# +# openssl pkcs8 -topk8 -passin pass:TestTest -inform DER -in key.der +# -outform DER -out keyenc.der -v2 aes128 +# hexdump -v -e '32/1 "%02x" "\n"' keyenc.der +# +wrapped_enc_keys.append(( +'PBKDF2WithHMAC-SHA1AndAES128-CBC', +2048, +"4F66EE5D3BCD531FE6EBF4B4E73016B8", # IV +"479F25156176C53A", # Salt +""" +3082021f304906092a864886f70d01050d303c301b06092a864886f70d01050c +300e0408479f25156176c53a02020800301d060960864801650304010204104f +66ee5d3bcd531fe6ebf4b4e73016b8048201d0e33cfa560423f589d097d21533 +3b880a5ebac5b2ac58b4e73b0d787aee7764f034fe34ca1d1bd845c0a7c3316f +afbfb2129e03dcaf5a5031394206492828dacef1e04639bee5935e0f46114202 +10bc6c37182f4889be11c5d0486c398f4be952e5740f65de9d8edeb275e2b406 +e19bc29ad5ebb97fa536344fc3d84c7e755696f12b810898de4e6f069b8a81c8 +0aab0d45d7d062303aaa4a10c2ce84fdb5a03114039cfe138e38bb15b2ced717 +93549cdad85e730b14d9e2198b663dfdc8d04a4349eb3de59b076ad40b116d4a +25ed917c576bc7c883c95ef0f1180e28fc9981bea069594c309f1aa1b253ceab +a2f0313bb1372bcb51a745056be93d77a1f235a762a45e8856512d436b2ca0f7 +dd60fbed394ba28978d2a2b984b028529d0a58d93aba46c6bbd4ac1e4013cbaa +63b00988bc5f11ccc40141c346762d2b28f64435d4be98ec17c1884985e3807e +e550db606600993efccf6de0dfc2d2d70b5336a3b018fa415d6bdd59f5777118 +16806b7bc17c4c7e20ad7176ebfa5a1aa3f6bc10f04b77afd443944642ac9cca +d740e082b4a3bbb8bafdd34a0b3c5f2f3c2aceccccdccd092b78994b845bfa61 +706c3b9df5165ed1dbcbf1244fe41fc9bf993f52f7658e2f87e1baaeacb0f562 +9d905c +""" +)) + +# +# openssl pkcs8 -topk8 -passin pass:TestTest -inform DER -in key.der +# -outform DER -out keyenc.der -v2 aes192 +# hexdump -v -e '32/1 "%02x" "\n"' keyenc.der +# +wrapped_enc_keys.append(( +'PBKDF2WithHMAC-SHA1AndAES192-CBC', +2048, +"5CFC2A4FF7B63201A4A8A5B021148186", # IV +"D718541C264944CE", # Salt +""" +3082021f304906092a864886f70d01050d303c301b06092a864886f70d01050c +300e0408d718541c264944ce02020800301d060960864801650304011604105c +fc2a4ff7b63201a4a8a5b021148186048201d08e74aaa21b8bcfb15b9790fe95 +b0e09ddb0f189b6fb1682fdb9f122b804650ddec3c67a1df093a828b3e5fbcc6 +286abbcc5354c482fd796d972e919ca8a5eba1eaa2293af1d648013ddad72106 +75622264dfba55dafdda39e338f058f1bdb9846041ffff803797d3fdf3693135 +8a192729ea8346a7e5e58e925a2e2e4af0818581859e8215d87370eb4194a5ff +bae900857d4c591dbc651a241865a817eaede9987c9f9ae4f95c0bf930eea88c +4d7596e535ffb7ca369988aba75027a96b9d0bc9c8b0b75f359067fd145a378b +02aaa15e9db7a23176224da48a83249005460cc6e429168657f2efa8b1af7537 +d7d7042f2d683e8271b21d591090963eeb57aea6172f88da139e1614d6a7d1a2 +1002d5a7a93d6d21156e2b4777f6fc069287a85a1538c46b7722ccde591ab55c +630e1ceeb1ac42d1b41f3f654e9da86b5efced43775ea68b2594e50e4005e052 +0fe753c0898120c2c07265367ff157f6538a1e4080d6f9d1ca9eb51939c9574e +f2e4e1e87c1434affd5808563cddd376776dbbf790c6a40028f311a8b58dafa2 +0970ed34acd6e3e89d063987893b2b9570ddb8cc032b05a723bba9444933ebf3 +c624204be72f4190e0245197d0cb772bec933fd8442445f9a28bd042d5a3a1e9 +9a8a07 +""" +)) + +# +# openssl pkcs8 -topk8 -passin pass:TestTest -inform DER -in key.der +# -outform DER -out keyenc.der -v2 aes192 +# hexdump -v -e '32/1 "%02x" "\n"' keyenc.der +# +wrapped_enc_keys.append(( +'PBKDF2WithHMAC-SHA1AndAES256-CBC', +2048, +"323351F94462AC563E053A056252C2C4", # IV +"02A6CD0D12E727B5", # Salt +""" +3082021f304906092a864886f70d01050d303c301b06092a864886f70d01050c +300e040802a6cd0d12e727b502020800301d060960864801650304012a041032 +3351f94462ac563e053a056252c2c4048201d07f4ef1c7be21aae738a20c5632 +b8bdbbb9083b6e7f68822267b1f481fd27fdafd61a90660de6e4058790e4c912 +bf3f319a7c37e6eb3d956daaa143865020d554bf6215e8d7492359aaeef45d6e +d85a686ed26c0bf7c18d071d827a86f0b73e1db0c0e7f3d42201544093302a90 +551ad530692468c47ac15c69500b8ca67d4a17b64d15cecc035ae50b768a36cf +07c395afa091e9e6f86f665455fbdc1b21ad79c0908b73da5de75a9b43508d5d +44dc97a870cd3cd9f01ca24452e9b11c1b4982946702cfcbfda5b2fcc0203fb5 +0b52a115760bd635c94d4c95ac2c640ee9a04ffaf6ccff5a8d953dd5d88ca478 +c377811c521f2191639c643d657a9e364af88bb7c14a356c2b0b4870a23c2f54 +d41f8157afff731471dccc6058b15e1151bcf84b39b5e622a3a1d65859c912a5 +591b85e034a1f6af664f030a6bfc8c3d20c70f32b54bcf4da9c2da83cef49cf8 +e9a74f0e5d358fe50b88acdce6a9db9a7ad61536212fc5f877ebfc7957b8bda4 +b1582a0f10d515a20ee06cf768db9c977aa6fbdca7540d611ff953012d009dac +e8abd059f8e8ffea637c9c7721f817aaf0bb23403e26a0ef0ff0e2037da67d41 +af728481f53443551a9bff4cea023164e9622b5441a309e1f4bff98e5bf76677 +8d7cd9 +""" +)) + +# hexdump -v -e '32/1 "%02x" "\n"' botan_scrypt.der +botan_scrypt = """ +3081f1305206092a864886f70d01050d3045302806092b06010401da47040b30 +1b040c316c5c7a847276a838a668280202200002010102010102012030190609 +60864801650304012e040c293e9bcddc0d59d64e060cb604819ab92318063480 +16148081a3123bb092b636ec0cc3b964628e181504c13eaf94987e6fb9f171d4 +9c45baeeb79c1d805d5a762d9bfd6d1995669df60a2cd0174b6d204693964de7 +05bc3fdc3a4ce5db01f30a994c82b0aac786e4f8655138c952f1cf2cc6093f90 +b5e5ca507beb539ff497b7b6370ba7f31f4928d3385dbe8bcd2395813ba1324e +6795e81a8518aff0f0a9e01396539f937b8b7b08 +""" + +# hexdump -v -e '32/1 "%02x" "\n"' botan_pbkdf2.der +botan_pbkdf2 = """ +3081f3305e06092a864886f70d01050d3051303006092a864886f70d01050c30 +23040cc91c89b368db578d2ec4c32002020fa0020118300c06082a864886f70d +02090500301d060960864801650304011604102a7147289e7c914a7d8257e4a1 +a2135b048190a648955fc96ecae56dcb4d0ab19edc5b7ef1219c88c7c3b2d0ed +b21e25d2559447f53e20b90b2f20e72456d943561c4925aad6067a4c720afb3d +691e14dfffa10ef77898e21d134f19136d35088a7aac508b296fd00d5742ad69 +8c693293b6a591e3660b130d718724d23d696f4da9bf4031475fafb682d7955c +996363f37032e10ac85afebb7cc1cbfc0e5d4c60a4c2 +""" + +def txt2bin(inputs): + s = b('').join([b(x) for x in inputs if not (x in '\n\r\t ')]) + return unhexlify(s) + +class Rng: + def __init__(self, output): + self.output=output + self.idx=0 + def __call__(self, n): + output = self.output[self.idx:self.idx+n] + self.idx += n + return output + +class PKCS8_Decrypt(unittest.TestCase): + + def setUp(self): + self.oid_key = oid_key + self.clear_key = txt2bin(clear_key) + self.wrapped_clear_key = txt2bin(wrapped_clear_key) + self.wrapped_enc_keys = [] + for t in wrapped_enc_keys: + self.wrapped_enc_keys.append(( + t[0], + t[1], + txt2bin(t[2]), + txt2bin(t[3]), + txt2bin(t[4]) + )) + + ### NO ENCRYTION + + def test1(self): + """Verify unwrapping w/o encryption""" + res1, res2, res3 = PKCS8.unwrap(self.wrapped_clear_key) + self.assertEqual(res1, self.oid_key) + self.assertEqual(res2, self.clear_key) + + def test2(self): + """Verify wrapping w/o encryption""" + wrapped = PKCS8.wrap(self.clear_key, self.oid_key) + res1, res2, res3 = PKCS8.unwrap(wrapped) + self.assertEqual(res1, self.oid_key) + self.assertEqual(res2, self.clear_key) + + ## ENCRYPTION + + def test3(self): + """Verify unwrapping with encryption""" + + for t in self.wrapped_enc_keys: + res1, res2, res3 = PKCS8.unwrap(t[4], b"TestTest") + self.assertEqual(res1, self.oid_key) + self.assertEqual(res2, self.clear_key) + + def test4(self): + """Verify wrapping with encryption""" + + for t in self.wrapped_enc_keys: + if t[0] == 'skip encryption': + continue + rng = Rng(t[2]+t[3]) + params = { 'iteration_count':t[1] } + wrapped = PKCS8.wrap( + self.clear_key, + self.oid_key, + b("TestTest"), + protection=t[0], + prot_params=params, + key_params=DerNull(), + randfunc=rng) + self.assertEqual(wrapped, t[4]) + + def test_import_botan_keys(self): + botan_scrypt_der = txt2bin(botan_scrypt) + key1 = PKCS8.unwrap(botan_scrypt_der, + b'your_password') + botan_pbkdf2_der = txt2bin(botan_pbkdf2) + key2 = PKCS8.unwrap(botan_pbkdf2_der, + b'your_password') + self.assertEqual(key1, key2) + + +def get_tests(config={}): + from Cryptodome.SelfTest.st_common import list_test_cases + listTests = [] + listTests += list_test_cases(PKCS8_Decrypt) + return listTests + +if __name__ == '__main__': + suite = lambda: unittest.TestSuite(get_tests()) + unittest.main(defaultTest='suite') + diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Math/__init__.py b/venv/Lib/site-packages/Cryptodome/SelfTest/Math/__init__.py new file mode 100644 index 0000000..9f732ba --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/SelfTest/Math/__init__.py @@ -0,0 +1,51 @@ +# +# SelfTest/Math/__init__.py: Self-test for math module +# +# =================================================================== +# +# Copyright (c) 2014, Legrandin +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# =================================================================== + +"""Self-test for Math""" + +def get_tests(config={}): + tests = [] + from Cryptodome.SelfTest.Math import test_Numbers + from Cryptodome.SelfTest.Math import test_Primality + from Cryptodome.SelfTest.Math import test_modexp + from Cryptodome.SelfTest.Math import test_modmult + tests += test_Numbers.get_tests(config=config) + tests += test_Primality.get_tests(config=config) + tests += test_modexp.get_tests(config=config) + tests += test_modmult.get_tests(config=config) + return tests + +if __name__ == '__main__': + import unittest + suite = lambda: unittest.TestSuite(get_tests()) + unittest.main(defaultTest='suite') diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Math/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/SelfTest/Math/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000..4f714ff Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/SelfTest/Math/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Math/__pycache__/test_Numbers.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/SelfTest/Math/__pycache__/test_Numbers.cpython-312.pyc new file mode 100644 index 0000000..8a051bc Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/SelfTest/Math/__pycache__/test_Numbers.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Math/__pycache__/test_Primality.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/SelfTest/Math/__pycache__/test_Primality.cpython-312.pyc new file mode 100644 index 0000000..756898d Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/SelfTest/Math/__pycache__/test_Primality.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Math/__pycache__/test_modexp.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/SelfTest/Math/__pycache__/test_modexp.cpython-312.pyc new file mode 100644 index 0000000..242734f Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/SelfTest/Math/__pycache__/test_modexp.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Math/__pycache__/test_modmult.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/SelfTest/Math/__pycache__/test_modmult.cpython-312.pyc new file mode 100644 index 0000000..e6e3ccb Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/SelfTest/Math/__pycache__/test_modmult.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Math/test_Numbers.py b/venv/Lib/site-packages/Cryptodome/SelfTest/Math/test_Numbers.py new file mode 100644 index 0000000..f974d5a --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/SelfTest/Math/test_Numbers.py @@ -0,0 +1,838 @@ +# +# SelfTest/Math/test_Numbers.py: Self-test for Numbers module +# +# =================================================================== +# +# Copyright (c) 2014, Legrandin +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# =================================================================== + +"""Self-test for Math.Numbers""" + +import sys +import unittest + +from Cryptodome.SelfTest.st_common import list_test_cases + +from Cryptodome.Util.py3compat import * + +from Cryptodome.Math._IntegerNative import IntegerNative + + +class TestIntegerBase(unittest.TestCase): + + def setUp(self): + raise NotImplementedError("To be implemented") + + def Integers(self, *arg): + return map(self.Integer, arg) + + def test_init_and_equality(self): + Integer = self.Integer + + v1 = Integer(23) + v2 = Integer(v1) + v3 = Integer(-9) + self.assertRaises(ValueError, Integer, 1.0) + + v4 = Integer(10**10) + v5 = Integer(-10**10) + + v6 = Integer(0xFFFF) + v7 = Integer(0xFFFFFFFF) + v8 = Integer(0xFFFFFFFFFFFFFFFF) + + self.assertEqual(v1, v1) + self.assertEqual(v1, 23) + self.assertEqual(v1, v2) + self.assertEqual(v3, -9) + self.assertEqual(v4, 10 ** 10) + self.assertEqual(v5, -10 ** 10) + self.assertEqual(v6, 0xFFFF) + self.assertEqual(v7, 0xFFFFFFFF) + self.assertEqual(v8, 0xFFFFFFFFFFFFFFFF) + + self.assertFalse(v1 == v4) + + # Init and comparison between Integer's + v6 = Integer(v1) + self.assertEqual(v1, v6) + + self.assertFalse(Integer(0) == None) + + def test_conversion_to_int(self): + v1, v2 = self.Integers(-23, 2 ** 1000) + self.assertEqual(int(v1), -23) + self.assertEqual(int(v2), 2 ** 1000) + + def test_equality_with_ints(self): + v1, v2, v3 = self.Integers(23, -89, 2 ** 1000) + self.assertTrue(v1 == 23) + self.assertTrue(v2 == -89) + self.assertFalse(v1 == 24) + self.assertTrue(v3 == 2 ** 1000) + + def test_conversion_to_str(self): + v1, v2, v3, v4 = self.Integers(20, 0, -20, 2 ** 1000) + self.assertTrue(str(v1) == "20") + self.assertTrue(str(v2) == "0") + self.assertTrue(str(v3) == "-20") + self.assertTrue(str(v4) == "10715086071862673209484250490600018105614048117055336074437503883703510511249361224931983788156958581275946729175531468251871452856923140435984577574698574803934567774824230985421074605062371141877954182153046474983581941267398767559165543946077062914571196477686542167660429831652624386837205668069376") + + def test_repr(self): + v1, v2 = self.Integers(-1, 2**80) + self.assertEqual(repr(v1), "Integer(-1)") + self.assertEqual(repr(v2), "Integer(1208925819614629174706176)") + + def test_conversion_to_bytes(self): + Integer = self.Integer + + v0 = Integer(0) + self.assertEqual(b"\x00", v0.to_bytes()) + + v1 = Integer(0x17) + self.assertEqual(b"\x17", v1.to_bytes()) + + v2 = Integer(0xFFFE) + self.assertEqual(b"\xFF\xFE", v2.to_bytes()) + self.assertEqual(b"\x00\xFF\xFE", v2.to_bytes(3)) + self.assertRaises(ValueError, v2.to_bytes, 1) + + self.assertEqual(b"\xFE\xFF", v2.to_bytes(byteorder='little')) + self.assertEqual(b"\xFE\xFF\x00", v2.to_bytes(3, byteorder='little')) + + v3 = Integer(0xFF00AABBCCDDEE1122) + self.assertEqual(b"\xFF\x00\xAA\xBB\xCC\xDD\xEE\x11\x22", v3.to_bytes()) + self.assertEqual(b"\x22\x11\xEE\xDD\xCC\xBB\xAA\x00\xFF", + v3.to_bytes(byteorder='little')) + self.assertEqual(b"\x00\xFF\x00\xAA\xBB\xCC\xDD\xEE\x11\x22", + v3.to_bytes(10)) + self.assertEqual(b"\x22\x11\xEE\xDD\xCC\xBB\xAA\x00\xFF\x00", + v3.to_bytes(10, byteorder='little')) + self.assertRaises(ValueError, v3.to_bytes, 8) + + v4 = Integer(-90) + self.assertRaises(ValueError, v4.to_bytes) + self.assertRaises(ValueError, v4.to_bytes, byteorder='bittle') + + def test_conversion_from_bytes(self): + Integer = self.Integer + + v1 = Integer.from_bytes(b"\x00") + self.assertTrue(isinstance(v1, Integer)) + self.assertEqual(0, v1) + + v2 = Integer.from_bytes(b"\x00\x01") + self.assertEqual(1, v2) + + v3 = Integer.from_bytes(b"\xFF\xFF") + self.assertEqual(0xFFFF, v3) + + v4 = Integer.from_bytes(b"\x00\x01", 'big') + self.assertEqual(1, v4) + + v5 = Integer.from_bytes(b"\x00\x01", byteorder='big') + self.assertEqual(1, v5) + + v6 = Integer.from_bytes(b"\x00\x01", byteorder='little') + self.assertEqual(0x0100, v6) + + self.assertRaises(ValueError, Integer.from_bytes, b'\x09', 'bittle') + + def test_inequality(self): + # Test Integer!=Integer and Integer!=int + v1, v2, v3, v4 = self.Integers(89, 89, 90, -8) + self.assertTrue(v1 != v3) + self.assertTrue(v1 != 90) + self.assertFalse(v1 != v2) + self.assertFalse(v1 != 89) + self.assertTrue(v1 != v4) + self.assertTrue(v4 != v1) + self.assertTrue(self.Integer(0) != None) + + def test_less_than(self): + # Test IntegerInteger and Integer>int + v1, v2, v3, v4, v5 = self.Integers(13, 13, 14, -8, 2 ** 10) + self.assertTrue(v3 > v1) + self.assertTrue(v3 > 13) + self.assertFalse(v1 > v1) + self.assertFalse(v1 > v2) + self.assertFalse(v1 > 13) + self.assertTrue(v1 > v4) + self.assertFalse(v4 > v1) + self.assertTrue(v5 > v1) + self.assertFalse(v1 > v5) + + def test_more_than_or_equal(self): + # Test Integer>=Integer and Integer>=int + v1, v2, v3, v4 = self.Integers(13, 13, 14, -4) + self.assertTrue(v3 >= v1) + self.assertTrue(v3 >= 13) + self.assertTrue(v1 >= v2) + self.assertTrue(v1 >= v1) + self.assertTrue(v1 >= 13) + self.assertFalse(v4 >= v1) + + def test_bool(self): + v1, v2, v3, v4 = self.Integers(0, 10, -9, 2 ** 10) + self.assertFalse(v1) + self.assertFalse(bool(v1)) + self.assertTrue(v2) + self.assertTrue(bool(v2)) + self.assertTrue(v3) + self.assertTrue(v4) + + def test_is_negative(self): + v1, v2, v3, v4, v5 = self.Integers(-3 ** 100, -3, 0, 3, 3**100) + self.assertTrue(v1.is_negative()) + self.assertTrue(v2.is_negative()) + self.assertFalse(v4.is_negative()) + self.assertFalse(v5.is_negative()) + + def test_addition(self): + # Test Integer+Integer and Integer+int + v1, v2, v3 = self.Integers(7, 90, -7) + self.assertTrue(isinstance(v1 + v2, self.Integer)) + self.assertEqual(v1 + v2, 97) + self.assertEqual(v1 + 90, 97) + self.assertEqual(v1 + v3, 0) + self.assertEqual(v1 + (-7), 0) + self.assertEqual(v1 + 2 ** 10, 2 ** 10 + 7) + + def test_subtraction(self): + # Test Integer-Integer and Integer-int + v1, v2, v3 = self.Integers(7, 90, -7) + self.assertTrue(isinstance(v1 - v2, self.Integer)) + self.assertEqual(v2 - v1, 83) + self.assertEqual(v2 - 7, 83) + self.assertEqual(v2 - v3, 97) + self.assertEqual(v1 - (-7), 14) + self.assertEqual(v1 - 2 ** 10, 7 - 2 ** 10) + + def test_multiplication(self): + # Test Integer-Integer and Integer-int + v1, v2, v3, v4 = self.Integers(4, 5, -2, 2 ** 10) + self.assertTrue(isinstance(v1 * v2, self.Integer)) + self.assertEqual(v1 * v2, 20) + self.assertEqual(v1 * 5, 20) + self.assertEqual(v1 * -2, -8) + self.assertEqual(v1 * 2 ** 10, 4 * (2 ** 10)) + + def test_floor_div(self): + v1, v2, v3 = self.Integers(3, 8, 2 ** 80) + self.assertTrue(isinstance(v1 // v2, self.Integer)) + self.assertEqual(v2 // v1, 2) + self.assertEqual(v2 // 3, 2) + self.assertEqual(v2 // -3, -3) + self.assertEqual(v3 // 2 ** 79, 2) + self.assertRaises(ZeroDivisionError, lambda: v1 // 0) + + def test_remainder(self): + # Test Integer%Integer and Integer%int + v1, v2, v3 = self.Integers(23, 5, -4) + self.assertTrue(isinstance(v1 % v2, self.Integer)) + self.assertEqual(v1 % v2, 3) + self.assertEqual(v1 % 5, 3) + self.assertEqual(v3 % 5, 1) + self.assertEqual(v1 % 2 ** 10, 23) + self.assertRaises(ZeroDivisionError, lambda: v1 % 0) + self.assertRaises(ValueError, lambda: v1 % -6) + + def test_simple_exponentiation(self): + v1, v2, v3 = self.Integers(4, 3, -2) + self.assertTrue(isinstance(v1 ** v2, self.Integer)) + self.assertEqual(v1 ** v2, 64) + self.assertEqual(pow(v1, v2), 64) + self.assertEqual(v1 ** 3, 64) + self.assertEqual(pow(v1, 3), 64) + self.assertEqual(v3 ** 2, 4) + self.assertEqual(v3 ** 3, -8) + + self.assertRaises(ValueError, pow, v1, -3) + + def test_modular_exponentiation(self): + v1, v2, v3 = self.Integers(23, 5, 17) + + self.assertTrue(isinstance(pow(v1, v2, v3), self.Integer)) + self.assertEqual(pow(v1, v2, v3), 7) + self.assertEqual(pow(v1, 5, v3), 7) + self.assertEqual(pow(v1, v2, 17), 7) + self.assertEqual(pow(v1, 5, 17), 7) + self.assertEqual(pow(v1, 0, 17), 1) + self.assertEqual(pow(v1, 1, 2 ** 80), 23) + self.assertEqual(pow(v1, 2 ** 80, 89298), 17689) + + self.assertRaises(ZeroDivisionError, pow, v1, 5, 0) + self.assertRaises(ValueError, pow, v1, 5, -4) + self.assertRaises(ValueError, pow, v1, -3, 8) + + def test_inplace_exponentiation(self): + v1 = self.Integer(4) + v1.inplace_pow(2) + self.assertEqual(v1, 16) + + v1 = self.Integer(4) + v1.inplace_pow(2, 15) + self.assertEqual(v1, 1) + + def test_abs(self): + v1, v2, v3, v4, v5 = self.Integers(-2 ** 100, -2, 0, 2, 2 ** 100) + self.assertEqual(abs(v1), 2 ** 100) + self.assertEqual(abs(v2), 2) + self.assertEqual(abs(v3), 0) + self.assertEqual(abs(v4), 2) + self.assertEqual(abs(v5), 2 ** 100) + + def test_sqrt(self): + v1, v2, v3, v4 = self.Integers(-2, 0, 49, 10**100) + + self.assertRaises(ValueError, v1.sqrt) + self.assertEqual(v2.sqrt(), 0) + self.assertEqual(v3.sqrt(), 7) + self.assertEqual(v4.sqrt(), 10**50) + + def test_sqrt_module(self): + + # Invalid modulus (non positive) + self.assertRaises(ValueError, self.Integer(5).sqrt, 0) + self.assertRaises(ValueError, self.Integer(5).sqrt, -1) + + # Simple cases + assert self.Integer(0).sqrt(5) == 0 + assert self.Integer(1).sqrt(5) in (1, 4) + + # Test with all quadratic residues in several fields + for p in (11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53): + for i in range(0, p): + square = i**2 % p + res = self.Integer(square).sqrt(p) + assert res in (i, p - i) + + # 2 is a non-quadratic reside in Z_11 + self.assertRaises(ValueError, self.Integer(2).sqrt, 11) + + # 10 is not a prime + self.assertRaises(ValueError, self.Integer(4).sqrt, 10) + + # 5 is square residue of 4 and 7 + assert self.Integer(5 - 11).sqrt(11) in (4, 7) + assert self.Integer(5 + 11).sqrt(11) in (4, 7) + + def test_in_place_add(self): + v1, v2 = self.Integers(10, 20) + + v1 += v2 + self.assertEqual(v1, 30) + v1 += 10 + self.assertEqual(v1, 40) + v1 += -1 + self.assertEqual(v1, 39) + v1 += 2 ** 1000 + self.assertEqual(v1, 39 + 2 ** 1000) + + def test_in_place_sub(self): + v1, v2 = self.Integers(10, 20) + + v1 -= v2 + self.assertEqual(v1, -10) + v1 -= -100 + self.assertEqual(v1, 90) + v1 -= 90000 + self.assertEqual(v1, -89910) + v1 -= -100000 + self.assertEqual(v1, 10090) + + def test_in_place_mul(self): + v1, v2 = self.Integers(3, 5) + + v1 *= v2 + self.assertEqual(v1, 15) + v1 *= 2 + self.assertEqual(v1, 30) + v1 *= -2 + self.assertEqual(v1, -60) + v1 *= 2 ** 1000 + self.assertEqual(v1, -60 * (2 ** 1000)) + + def test_in_place_modulus(self): + v1, v2 = self.Integers(20, 7) + + v1 %= v2 + self.assertEqual(v1, 6) + v1 %= 2 ** 1000 + self.assertEqual(v1, 6) + v1 %= 2 + self.assertEqual(v1, 0) + def t(): + v3 = self.Integer(9) + v3 %= 0 + self.assertRaises(ZeroDivisionError, t) + + def test_and(self): + v1, v2, v3 = self.Integers(0xF4, 0x31, -0xF) + self.assertTrue(isinstance(v1 & v2, self.Integer)) + self.assertEqual(v1 & v2, 0x30) + self.assertEqual(v1 & 0x31, 0x30) + self.assertEqual(v1 & v3, 0xF0) + self.assertEqual(v1 & -0xF, 0xF0) + self.assertEqual(v3 & -0xF, -0xF) + self.assertEqual(v2 & (2 ** 1000 + 0x31), 0x31) + + def test_or(self): + v1, v2, v3 = self.Integers(0x40, 0x82, -0xF) + self.assertTrue(isinstance(v1 | v2, self.Integer)) + self.assertEqual(v1 | v2, 0xC2) + self.assertEqual(v1 | 0x82, 0xC2) + self.assertEqual(v2 | v3, -0xD) + self.assertEqual(v2 | 2 ** 1000, 2 ** 1000 + 0x82) + + def test_right_shift(self): + v1, v2, v3 = self.Integers(0x10, 1, -0x10) + self.assertEqual(v1 >> 0, v1) + self.assertTrue(isinstance(v1 >> v2, self.Integer)) + self.assertEqual(v1 >> v2, 0x08) + self.assertEqual(v1 >> 1, 0x08) + self.assertRaises(ValueError, lambda: v1 >> -1) + self.assertEqual(v1 >> (2 ** 1000), 0) + + self.assertEqual(v3 >> 1, -0x08) + self.assertEqual(v3 >> (2 ** 1000), -1) + + def test_in_place_right_shift(self): + v1, v2, v3 = self.Integers(0x10, 1, -0x10) + v1 >>= 0 + self.assertEqual(v1, 0x10) + v1 >>= 1 + self.assertEqual(v1, 0x08) + v1 >>= v2 + self.assertEqual(v1, 0x04) + v3 >>= 1 + self.assertEqual(v3, -0x08) + def l(): + v4 = self.Integer(0x90) + v4 >>= -1 + self.assertRaises(ValueError, l) + def m1(): + v4 = self.Integer(0x90) + v4 >>= 2 ** 1000 + return v4 + self.assertEqual(0, m1()) + def m2(): + v4 = self.Integer(-1) + v4 >>= 2 ** 1000 + return v4 + self.assertEqual(-1, m2()) + + def _test_left_shift(self): + v1, v2, v3 = self.Integers(0x10, 1, -0x10) + self.assertEqual(v1 << 0, v1) + self.assertTrue(isinstance(v1 << v2, self.Integer)) + self.assertEqual(v1 << v2, 0x20) + self.assertEqual(v1 << 1, 0x20) + self.assertEqual(v3 << 1, -0x20) + self.assertRaises(ValueError, lambda: v1 << -1) + self.assertRaises(ValueError, lambda: v1 << (2 ** 1000)) + + def test_in_place_left_shift(self): + v1, v2, v3 = self.Integers(0x10, 1, -0x10) + v1 <<= 0 + self.assertEqual(v1, 0x10) + v1 <<= 1 + self.assertEqual(v1, 0x20) + v1 <<= v2 + self.assertEqual(v1, 0x40) + v3 <<= 1 + self.assertEqual(v3, -0x20) + def l(): + v4 = self.Integer(0x90) + v4 <<= -1 + self.assertRaises(ValueError, l) + def m(): + v4 = self.Integer(0x90) + v4 <<= 2 ** 1000 + self.assertRaises(ValueError, m) + + + def test_get_bit(self): + v1, v2, v3 = self.Integers(0x102, -3, 1) + self.assertEqual(v1.get_bit(0), 0) + self.assertEqual(v1.get_bit(1), 1) + self.assertEqual(v1.get_bit(v3), 1) + self.assertEqual(v1.get_bit(8), 1) + self.assertEqual(v1.get_bit(9), 0) + + self.assertRaises(ValueError, v1.get_bit, -1) + self.assertEqual(v1.get_bit(2 ** 1000), 0) + + self.assertRaises(ValueError, v2.get_bit, -1) + self.assertRaises(ValueError, v2.get_bit, 0) + self.assertRaises(ValueError, v2.get_bit, 1) + self.assertRaises(ValueError, v2.get_bit, 2 * 1000) + + def test_odd_even(self): + v1, v2, v3, v4, v5 = self.Integers(0, 4, 17, -4, -17) + + self.assertTrue(v1.is_even()) + self.assertTrue(v2.is_even()) + self.assertFalse(v3.is_even()) + self.assertTrue(v4.is_even()) + self.assertFalse(v5.is_even()) + + self.assertFalse(v1.is_odd()) + self.assertFalse(v2.is_odd()) + self.assertTrue(v3.is_odd()) + self.assertFalse(v4.is_odd()) + self.assertTrue(v5.is_odd()) + + def test_size_in_bits(self): + v1, v2, v3, v4 = self.Integers(0, 1, 0x100, -90) + self.assertEqual(v1.size_in_bits(), 1) + self.assertEqual(v2.size_in_bits(), 1) + self.assertEqual(v3.size_in_bits(), 9) + self.assertRaises(ValueError, v4.size_in_bits) + + def test_size_in_bytes(self): + v1, v2, v3, v4, v5, v6 = self.Integers(0, 1, 0xFF, 0x1FF, 0x10000, -9) + self.assertEqual(v1.size_in_bytes(), 1) + self.assertEqual(v2.size_in_bytes(), 1) + self.assertEqual(v3.size_in_bytes(), 1) + self.assertEqual(v4.size_in_bytes(), 2) + self.assertEqual(v5.size_in_bytes(), 3) + self.assertRaises(ValueError, v6.size_in_bits) + + def test_perfect_square(self): + + self.assertFalse(self.Integer(-9).is_perfect_square()) + self.assertTrue(self.Integer(0).is_perfect_square()) + self.assertTrue(self.Integer(1).is_perfect_square()) + self.assertFalse(self.Integer(2).is_perfect_square()) + self.assertFalse(self.Integer(3).is_perfect_square()) + self.assertTrue(self.Integer(4).is_perfect_square()) + self.assertTrue(self.Integer(39*39).is_perfect_square()) + self.assertFalse(self.Integer(39*39+1).is_perfect_square()) + + for x in range(100, 1000): + self.assertFalse(self.Integer(x**2+1).is_perfect_square()) + self.assertTrue(self.Integer(x**2).is_perfect_square()) + + def test_fail_if_divisible_by(self): + v1, v2, v3 = self.Integers(12, -12, 4) + + # No failure expected + v1.fail_if_divisible_by(7) + v2.fail_if_divisible_by(7) + v2.fail_if_divisible_by(2 ** 80) + + # Failure expected + self.assertRaises(ValueError, v1.fail_if_divisible_by, 4) + self.assertRaises(ValueError, v1.fail_if_divisible_by, v3) + + def test_multiply_accumulate(self): + v1, v2, v3 = self.Integers(4, 3, 2) + v1.multiply_accumulate(v2, v3) + self.assertEqual(v1, 10) + v1.multiply_accumulate(v2, 2) + self.assertEqual(v1, 16) + v1.multiply_accumulate(3, v3) + self.assertEqual(v1, 22) + v1.multiply_accumulate(1, -2) + self.assertEqual(v1, 20) + v1.multiply_accumulate(-2, 1) + self.assertEqual(v1, 18) + v1.multiply_accumulate(1, 2 ** 1000) + self.assertEqual(v1, 18 + 2 ** 1000) + v1.multiply_accumulate(2 ** 1000, 1) + self.assertEqual(v1, 18 + 2 ** 1001) + + def test_set(self): + v1, v2 = self.Integers(3, 6) + v1.set(v2) + self.assertEqual(v1, 6) + v1.set(9) + self.assertEqual(v1, 9) + v1.set(-2) + self.assertEqual(v1, -2) + v1.set(2 ** 1000) + self.assertEqual(v1, 2 ** 1000) + + def test_inverse(self): + v1, v2, v3, v4, v5, v6 = self.Integers(2, 5, -3, 0, 723872, 3433) + + self.assertTrue(isinstance(v1.inverse(v2), self.Integer)) + self.assertEqual(v1.inverse(v2), 3) + self.assertEqual(v1.inverse(5), 3) + self.assertEqual(v3.inverse(5), 3) + self.assertEqual(v5.inverse(92929921), 58610507) + self.assertEqual(v6.inverse(9912), 5353) + + self.assertRaises(ValueError, v2.inverse, 10) + self.assertRaises(ValueError, v1.inverse, -3) + self.assertRaises(ValueError, v4.inverse, 10) + self.assertRaises(ZeroDivisionError, v2.inverse, 0) + + def test_inplace_inverse(self): + v1, v2 = self.Integers(2, 5) + + v1.inplace_inverse(v2) + self.assertEqual(v1, 3) + + def test_gcd(self): + v1, v2, v3, v4 = self.Integers(6, 10, 17, -2) + self.assertTrue(isinstance(v1.gcd(v2), self.Integer)) + self.assertEqual(v1.gcd(v2), 2) + self.assertEqual(v1.gcd(10), 2) + self.assertEqual(v1.gcd(v3), 1) + self.assertEqual(v1.gcd(-2), 2) + self.assertEqual(v4.gcd(6), 2) + + def test_lcm(self): + v1, v2, v3, v4, v5 = self.Integers(6, 10, 17, -2, 0) + self.assertTrue(isinstance(v1.lcm(v2), self.Integer)) + self.assertEqual(v1.lcm(v2), 30) + self.assertEqual(v1.lcm(10), 30) + self.assertEqual(v1.lcm(v3), 102) + self.assertEqual(v1.lcm(-2), 6) + self.assertEqual(v4.lcm(6), 6) + self.assertEqual(v1.lcm(0), 0) + self.assertEqual(v5.lcm(0), 0) + + def test_jacobi_symbol(self): + + data = ( + (1001, 1, 1), + (19, 45, 1), + (8, 21, -1), + (5, 21, 1), + (610, 987, -1), + (1001, 9907, -1), + (5, 3439601197, -1) + ) + + js = self.Integer.jacobi_symbol + + # Jacobi symbol is always 1 for k==1 or n==1 + for k in range(1, 30): + self.assertEqual(js(k, 1), 1) + for n in range(1, 30, 2): + self.assertEqual(js(1, n), 1) + + # Fail if n is not positive odd + self.assertRaises(ValueError, js, 6, -2) + self.assertRaises(ValueError, js, 6, -1) + self.assertRaises(ValueError, js, 6, 0) + self.assertRaises(ValueError, js, 0, 0) + self.assertRaises(ValueError, js, 6, 2) + self.assertRaises(ValueError, js, 6, 4) + self.assertRaises(ValueError, js, 6, 6) + self.assertRaises(ValueError, js, 6, 8) + + for tv in data: + self.assertEqual(js(tv[0], tv[1]), tv[2]) + self.assertEqual(js(self.Integer(tv[0]), tv[1]), tv[2]) + self.assertEqual(js(tv[0], self.Integer(tv[1])), tv[2]) + + def test_jacobi_symbol_wikipedia(self): + + # Test vectors from https://en.wikipedia.org/wiki/Jacobi_symbol + tv = [ + (3, [(1, 1), (2, -1), (3, 0), (4, 1), (5, -1), (6, 0), (7, 1), (8, -1), (9, 0), (10, 1), (11, -1), (12, 0), (13, 1), (14, -1), (15, 0), (16, 1), (17, -1), (18, 0), (19, 1), (20, -1), (21, 0), (22, 1), (23, -1), (24, 0), (25, 1), (26, -1), (27, 0), (28, 1), (29, -1), (30, 0)]), + (5, [(1, 1), (2, -1), (3, -1), (4, 1), (5, 0), (6, 1), (7, -1), (8, -1), (9, 1), (10, 0), (11, 1), (12, -1), (13, -1), (14, 1), (15, 0), (16, 1), (17, -1), (18, -1), (19, 1), (20, 0), (21, 1), (22, -1), (23, -1), (24, 1), (25, 0), (26, 1), (27, -1), (28, -1), (29, 1), (30, 0)]), + (7, [(1, 1), (2, 1), (3, -1), (4, 1), (5, -1), (6, -1), (7, 0), (8, 1), (9, 1), (10, -1), (11, 1), (12, -1), (13, -1), (14, 0), (15, 1), (16, 1), (17, -1), (18, 1), (19, -1), (20, -1), (21, 0), (22, 1), (23, 1), (24, -1), (25, 1), (26, -1), (27, -1), (28, 0), (29, 1), (30, 1)]), + (9, [(1, 1), (2, 1), (3, 0), (4, 1), (5, 1), (6, 0), (7, 1), (8, 1), (9, 0), (10, 1), (11, 1), (12, 0), (13, 1), (14, 1), (15, 0), (16, 1), (17, 1), (18, 0), (19, 1), (20, 1), (21, 0), (22, 1), (23, 1), (24, 0), (25, 1), (26, 1), (27, 0), (28, 1), (29, 1), (30, 0)]), + (11, [(1, 1), (2, -1), (3, 1), (4, 1), (5, 1), (6, -1), (7, -1), (8, -1), (9, 1), (10, -1), (11, 0), (12, 1), (13, -1), (14, 1), (15, 1), (16, 1), (17, -1), (18, -1), (19, -1), (20, 1), (21, -1), (22, 0), (23, 1), (24, -1), (25, 1), (26, 1), (27, 1), (28, -1), (29, -1), (30, -1)]), + (13, [(1, 1), (2, -1), (3, 1), (4, 1), (5, -1), (6, -1), (7, -1), (8, -1), (9, 1), (10, 1), (11, -1), (12, 1), (13, 0), (14, 1), (15, -1), (16, 1), (17, 1), (18, -1), (19, -1), (20, -1), (21, -1), (22, 1), (23, 1), (24, -1), (25, 1), (26, 0), (27, 1), (28, -1), (29, 1), (30, 1)]), + (15, [(1, 1), (2, 1), (3, 0), (4, 1), (5, 0), (6, 0), (7, -1), (8, 1), (9, 0), (10, 0), (11, -1), (12, 0), (13, -1), (14, -1), (15, 0), (16, 1), (17, 1), (18, 0), (19, 1), (20, 0), (21, 0), (22, -1), (23, 1), (24, 0), (25, 0), (26, -1), (27, 0), (28, -1), (29, -1), (30, 0)]), + (17, [(1, 1), (2, 1), (3, -1), (4, 1), (5, -1), (6, -1), (7, -1), (8, 1), (9, 1), (10, -1), (11, -1), (12, -1), (13, 1), (14, -1), (15, 1), (16, 1), (17, 0), (18, 1), (19, 1), (20, -1), (21, 1), (22, -1), (23, -1), (24, -1), (25, 1), (26, 1), (27, -1), (28, -1), (29, -1), (30, 1)]), + (19, [(1, 1), (2, -1), (3, -1), (4, 1), (5, 1), (6, 1), (7, 1), (8, -1), (9, 1), (10, -1), (11, 1), (12, -1), (13, -1), (14, -1), (15, -1), (16, 1), (17, 1), (18, -1), (19, 0), (20, 1), (21, -1), (22, -1), (23, 1), (24, 1), (25, 1), (26, 1), (27, -1), (28, 1), (29, -1), (30, 1)]), + (21, [(1, 1), (2, -1), (3, 0), (4, 1), (5, 1), (6, 0), (7, 0), (8, -1), (9, 0), (10, -1), (11, -1), (12, 0), (13, -1), (14, 0), (15, 0), (16, 1), (17, 1), (18, 0), (19, -1), (20, 1), (21, 0), (22, 1), (23, -1), (24, 0), (25, 1), (26, 1), (27, 0), (28, 0), (29, -1), (30, 0)]), + (23, [(1, 1), (2, 1), (3, 1), (4, 1), (5, -1), (6, 1), (7, -1), (8, 1), (9, 1), (10, -1), (11, -1), (12, 1), (13, 1), (14, -1), (15, -1), (16, 1), (17, -1), (18, 1), (19, -1), (20, -1), (21, -1), (22, -1), (23, 0), (24, 1), (25, 1), (26, 1), (27, 1), (28, -1), (29, 1), (30, -1)]), + (25, [(1, 1), (2, 1), (3, 1), (4, 1), (5, 0), (6, 1), (7, 1), (8, 1), (9, 1), (10, 0), (11, 1), (12, 1), (13, 1), (14, 1), (15, 0), (16, 1), (17, 1), (18, 1), (19, 1), (20, 0), (21, 1), (22, 1), (23, 1), (24, 1), (25, 0), (26, 1), (27, 1), (28, 1), (29, 1), (30, 0)]), + (27, [(1, 1), (2, -1), (3, 0), (4, 1), (5, -1), (6, 0), (7, 1), (8, -1), (9, 0), (10, 1), (11, -1), (12, 0), (13, 1), (14, -1), (15, 0), (16, 1), (17, -1), (18, 0), (19, 1), (20, -1), (21, 0), (22, 1), (23, -1), (24, 0), (25, 1), (26, -1), (27, 0), (28, 1), (29, -1), (30, 0)]), + (29, [(1, 1), (2, -1), (3, -1), (4, 1), (5, 1), (6, 1), (7, 1), (8, -1), (9, 1), (10, -1), (11, -1), (12, -1), (13, 1), (14, -1), (15, -1), (16, 1), (17, -1), (18, -1), (19, -1), (20, 1), (21, -1), (22, 1), (23, 1), (24, 1), (25, 1), (26, -1), (27, -1), (28, 1), (29, 0), (30, 1)]), + ] + + js = self.Integer.jacobi_symbol + + for n, kj in tv: + for k, j in kj: + self.assertEqual(js(k, n), j) + + def test_hex(self): + v1, = self.Integers(0x10) + self.assertEqual(hex(v1), "0x10") + + def test_mult_modulo_bytes(self): + modmult = self.Integer._mult_modulo_bytes + + res = modmult(4, 5, 19) + self.assertEqual(res, b'\x01') + + res = modmult(4 - 19, 5, 19) + self.assertEqual(res, b'\x01') + + res = modmult(4, 5 - 19, 19) + self.assertEqual(res, b'\x01') + + res = modmult(4 + 19, 5, 19) + self.assertEqual(res, b'\x01') + + res = modmult(4, 5 + 19, 19) + self.assertEqual(res, b'\x01') + + modulus = 2**512 - 1 # 64 bytes + t1 = 13**100 + t2 = 17**100 + expect = b"\xfa\xb2\x11\x87\xc3(y\x07\xf8\xf1n\xdepq\x0b\xca\xf3\xd3B,\xef\xf2\xfbf\xcc)\x8dZ*\x95\x98r\x96\xa8\xd5\xc3}\xe2q:\xa2'z\xf48\xde%\xef\t\x07\xbc\xc4[C\x8bUE2\x90\xef\x81\xaa:\x08" + self.assertEqual(expect, modmult(t1, t2, modulus)) + + self.assertRaises(ZeroDivisionError, modmult, 4, 5, 0) + self.assertRaises(ValueError, modmult, 4, 5, -1) + self.assertRaises(ValueError, modmult, 4, 5, 4) + + +class TestIntegerInt(TestIntegerBase): + + def setUp(self): + self.Integer = IntegerNative + + +class testIntegerRandom(unittest.TestCase): + + def test_random_exact_bits(self): + + for _ in range(1000): + a = IntegerNative.random(exact_bits=8) + self.assertFalse(a < 128) + self.assertFalse(a >= 256) + + for bits_value in range(1024, 1024 + 8): + a = IntegerNative.random(exact_bits=bits_value) + self.assertFalse(a < 2**(bits_value - 1)) + self.assertFalse(a >= 2**bits_value) + + def test_random_max_bits(self): + + flag = False + for _ in range(1000): + a = IntegerNative.random(max_bits=8) + flag = flag or a < 128 + self.assertFalse(a>=256) + self.assertTrue(flag) + + for bits_value in range(1024, 1024 + 8): + a = IntegerNative.random(max_bits=bits_value) + self.assertFalse(a >= 2**bits_value) + + def test_random_bits_custom_rng(self): + + class CustomRNG(object): + def __init__(self): + self.counter = 0 + + def __call__(self, size): + self.counter += size + return bchr(0) * size + + custom_rng = CustomRNG() + a = IntegerNative.random(exact_bits=32, randfunc=custom_rng) + self.assertEqual(custom_rng.counter, 4) + + def test_random_range(self): + + func = IntegerNative.random_range + + for x in range(200): + a = func(min_inclusive=1, max_inclusive=15) + self.assertTrue(1 <= a <= 15) + + for x in range(200): + a = func(min_inclusive=1, max_exclusive=15) + self.assertTrue(1 <= a < 15) + + self.assertRaises(ValueError, func, min_inclusive=1, max_inclusive=2, + max_exclusive=3) + self.assertRaises(ValueError, func, max_inclusive=2, max_exclusive=3) + +def get_tests(config={}): + tests = [] + tests += list_test_cases(TestIntegerInt) + + try: + from Cryptodome.Math._IntegerGMP import IntegerGMP + + class TestIntegerGMP(TestIntegerBase): + def setUp(self): + self.Integer = IntegerGMP + + tests += list_test_cases(TestIntegerGMP) + except (ImportError, OSError) as e: + if sys.platform == "win32": + sys.stdout.write("Skipping GMP tests on Windows\n") + else: + sys.stdout.write("Skipping GMP tests (%s)\n" % str(e) ) + + try: + from Cryptodome.Math._IntegerCustom import IntegerCustom + + class TestIntegerCustomModexp(TestIntegerBase): + def setUp(self): + self.Integer = IntegerCustom + + tests += list_test_cases(TestIntegerCustomModexp) + except (ImportError, OSError) as e: + sys.stdout.write("Skipping custom modexp tests (%s)\n" % str(e) ) + + tests += list_test_cases(testIntegerRandom) + return tests + +if __name__ == '__main__': + suite = lambda: unittest.TestSuite(get_tests()) + unittest.main(defaultTest='suite') diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Math/test_Primality.py b/venv/Lib/site-packages/Cryptodome/SelfTest/Math/test_Primality.py new file mode 100644 index 0000000..475d1d4 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/SelfTest/Math/test_Primality.py @@ -0,0 +1,118 @@ +# +# SelfTest/Math/test_Primality.py: Self-test for Primality module +# +# =================================================================== +# +# Copyright (c) 2014, Legrandin +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# =================================================================== + +"""Self-test for Math.Numbers""" + +import unittest + +from Cryptodome.SelfTest.st_common import list_test_cases + +from Cryptodome.Util.py3compat import * + +from Cryptodome.Math.Numbers import Integer +from Cryptodome.Math.Primality import ( + PROBABLY_PRIME, COMPOSITE, + miller_rabin_test, lucas_test, + test_probable_prime, + generate_probable_prime, + generate_probable_safe_prime, + ) + + +class TestPrimality(unittest.TestCase): + + primes = (1, 2, 3, 5, 7, 11, 13, 17, 19, 23, 2**127-1, 175637383534939453397801320455508570374088202376942372758907369518414308188137781042871856139027160010343454418881888953150175357127346872102307696660678617989191485418582475696230580407111841072614783095326672517315988762029036079794994990250662362650625650262324085116467511357592728695033227611029693067539) + composites = (0, 4, 6, 8, 9, 10, 12, 14, 15, 16, 18, 20, 21, 7*23, (2**19-1)*(2**67-1), 9746347772161,) + + def test_miller_rabin(self): + for prime in self.primes: + self.assertEqual(miller_rabin_test(prime, 3), PROBABLY_PRIME) + for composite in self.composites: + self.assertEqual(miller_rabin_test(composite, 3), COMPOSITE) + self.assertRaises(ValueError, miller_rabin_test, -1, 3) + + def test_lucas(self): + for prime in self.primes: + res = lucas_test(prime) + self.assertEqual(res, PROBABLY_PRIME) + for composite in self.composites: + res = lucas_test(composite) + self.assertEqual(res, COMPOSITE) + self.assertRaises(ValueError, lucas_test, -1) + + def test_is_prime(self): + primes = (170141183460469231731687303715884105727, + 19175002942688032928599, + 1363005552434666078217421284621279933627102780881053358473, + 2 ** 521 - 1) + for p in primes: + self.assertEqual(test_probable_prime(p), PROBABLY_PRIME) + + not_primes = ( + 4754868377601046732119933839981363081972014948522510826417784001, + 1334733877147062382486934807105197899496002201113849920496510541601, + 260849323075371835669784094383812120359260783810157225730623388382401, + ) + for np in not_primes: + self.assertEqual(test_probable_prime(np), COMPOSITE) + + from Cryptodome.Util.number import sieve_base + for p in sieve_base[:100]: + res = test_probable_prime(p) + self.assertEqual(res, PROBABLY_PRIME) + + def test_generate_prime_bit_size(self): + p = generate_probable_prime(exact_bits=512) + self.assertEqual(p.size_in_bits(), 512) + + def test_generate_prime_filter(self): + def ending_with_one(number): + return number % 10 == 1 + + for x in range(20): + q = generate_probable_prime(exact_bits=160, + prime_filter=ending_with_one) + self.assertEqual(q % 10, 1) + + def test_generate_safe_prime(self): + p = generate_probable_safe_prime(exact_bits=161) + self.assertEqual(p.size_in_bits(), 161) + +def get_tests(config={}): + tests = [] + tests += list_test_cases(TestPrimality) + return tests + +if __name__ == '__main__': + suite = lambda: unittest.TestSuite(get_tests()) + unittest.main(defaultTest='suite') diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Math/test_modexp.py b/venv/Lib/site-packages/Cryptodome/SelfTest/Math/test_modexp.py new file mode 100644 index 0000000..d63f43c --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/SelfTest/Math/test_modexp.py @@ -0,0 +1,201 @@ +# +# SelfTest/Math/test_modexp.py: Self-test for module exponentiation +# +# =================================================================== +# +# Copyright (c) 2017, Helder Eijs +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# =================================================================== + +"""Self-test for the custom module exponentiation""" + +import unittest + +from Cryptodome.SelfTest.st_common import list_test_cases + +from Cryptodome.Util.number import long_to_bytes, bytes_to_long + +from Cryptodome.Util.py3compat import * + +from Cryptodome.Util._raw_api import (load_pycryptodome_raw_lib, + create_string_buffer, + get_raw_buffer, + c_size_t, + c_ulonglong) + +from Cryptodome.Hash import SHAKE128 +from Cryptodome.Math.Numbers import Integer +from Cryptodome.Math._IntegerCustom import _raw_montgomery + +from Cryptodome.Random.random import StrongRandom + + +def create_rng(tag): + rng = StrongRandom(SHAKE128.new(data=tag)) + return rng + +class ExceptionModulus(ValueError): + pass + +def monty_pow(base, exp, modulus): + max_len = len(long_to_bytes(max(base, exp, modulus))) + + base_b, exp_b, modulus_b = [ long_to_bytes(x, max_len) for x in + (base, exp, modulus) ] + + out = create_string_buffer(max_len) + error = _raw_montgomery.monty_pow( + out, + base_b, + exp_b, + modulus_b, + c_size_t(max_len), + c_ulonglong(32) + ) + + if error == 17: + raise ExceptionModulus() + if error: + raise ValueError("monty_pow failed with error: %d" % error) + + result = bytes_to_long(get_raw_buffer(out)) + return result + +exponent1 = 0x2ce0af628901460a419a08ef950d498b9fd6f271a1a52ac293b86fe5c60efe8e8ba93fa1ebe1eb3d614d2e7b328cb60a2591440e163441a190ecf101ceec245f600fffdcf3f5b3a17a7baeacb96a424db1d7ec985e8ec998bb479fecfffed6a75f9a90fc97062fd973303bce855ad7b8d8272a94025e8532be9aabd54a183f303538d2a7e621b4131d59e823a4625f39bd7d518d7784f7c3a8f19061da74974ff42fa1c063dec2db97d461e291a7d6e721708a5229de166c1246363372854e27f3f08ae274bc16bfd205b028a4d81386494433d516dfbb35f495acba5e4e1d1843cb3c3129b6642a85fc7244ce5845fac071c7f622e4ee12ac43fabeeaa0cd01 +modulus1 = 0xd66691b20071be4d66d4b71032b37fa007cfabf579fcb91e50bfc2753b3f0ce7be74e216aef7e26d4ae180bc20d7bd3ea88a6cbf6f87380e613c8979b5b043b200a8ff8856a3b12875e36e98a7569f3852d028e967551000b02c19e9fa52e83115b89309aabb1e1cf1e2cb6369d637d46775ce4523ea31f64ad2794cbc365dd8a35e007ed3b57695877fbf102dbeb8b3212491398e494314e93726926e1383f8abb5889bea954eb8c0ca1c62c8e9d83f41888095c5e645ed6d32515fe0c58c1368cad84694e18da43668c6f43e61d7c9bca633ddcda7aef5b79bc396d4a9f48e2a9abe0836cc455e435305357228e93d25aaed46b952defae0f57339bf26f5a9 + + +class TestModExp(unittest.TestCase): + + def test_small(self): + self.assertEqual(1, monty_pow(11,12,19)) + + def test_large_1(self): + base = 0xfffffffffffffffffffffffffffffffffffffffffffffffffff + expected = pow(base, exponent1, modulus1) + result = monty_pow(base, exponent1, modulus1) + self.assertEqual(result, expected) + + def test_zero_exp(self): + base = 0xfffffffffffffffffffffffffffffffffffffffffffffffffff + result = monty_pow(base, 0, modulus1) + self.assertEqual(result, 1) + + def test_zero_base(self): + result = monty_pow(0, exponent1, modulus1) + self.assertEqual(result, 0) + + def test_zero_modulus(self): + base = 0xfffffffffffffffffffffffffffffffffffffffffffffffff + self.assertRaises(ExceptionModulus, monty_pow, base, exponent1, 0) + self.assertRaises(ExceptionModulus, monty_pow, 0, 0, 0) + + def test_larger_exponent(self): + base = modulus1 - 0xFFFFFFF + expected = pow(base, modulus1<<64, modulus1) + result = monty_pow(base, modulus1<<64, modulus1) + self.assertEqual(result, expected) + + def test_even_modulus(self): + base = modulus1 >> 4 + self.assertRaises(ExceptionModulus, monty_pow, base, exponent1, modulus1-1) + + def test_several_lengths(self): + prng = SHAKE128.new().update(b('Test')) + for length in range(1, 100): + modulus2 = Integer.from_bytes(prng.read(length)) | 1 + base = Integer.from_bytes(prng.read(length)) % modulus2 + exponent2 = Integer.from_bytes(prng.read(length)) + + expected = pow(base, exponent2, modulus2) + result = monty_pow(base, exponent2, modulus2) + self.assertEqual(result, expected) + + def test_variable_exponent(self): + prng = create_rng(b('Test variable exponent')) + for i in range(20): + for j in range(7): + modulus = prng.getrandbits(8*30) | 1 + base = prng.getrandbits(8*30) % modulus + exponent = prng.getrandbits(i*8+j) + + expected = pow(base, exponent, modulus) + result = monty_pow(base, exponent, modulus) + self.assertEqual(result, expected) + + exponent ^= (1 << (i*8+j)) - 1 + + expected = pow(base, exponent, modulus) + result = monty_pow(base, exponent, modulus) + self.assertEqual(result, expected) + + def test_stress_63(self): + prng = create_rng(b('Test 63')) + length = 63 + for _ in range(2000): + modulus = prng.getrandbits(8*length) | 1 + base = prng.getrandbits(8*length) % modulus + exponent = prng.getrandbits(8*length) + + expected = pow(base, exponent, modulus) + result = monty_pow(base, exponent, modulus) + self.assertEqual(result, expected) + + def test_stress_64(self): + prng = create_rng(b('Test 64')) + length = 64 + for _ in range(2000): + modulus = prng.getrandbits(8*length) | 1 + base = prng.getrandbits(8*length) % modulus + exponent = prng.getrandbits(8*length) + + expected = pow(base, exponent, modulus) + result = monty_pow(base, exponent, modulus) + self.assertEqual(result, expected) + + def test_stress_65(self): + prng = create_rng(b('Test 65')) + length = 65 + for _ in range(2000): + modulus = prng.getrandbits(8*length) | 1 + base = prng.getrandbits(8*length) % modulus + exponent = prng.getrandbits(8*length) + + expected = pow(base, exponent, modulus) + result = monty_pow(base, exponent, modulus) + self.assertEqual(result, expected) + + +def get_tests(config={}): + tests = [] + tests += list_test_cases(TestModExp) + return tests + + +if __name__ == '__main__': + suite = lambda: unittest.TestSuite(get_tests()) + unittest.main(defaultTest='suite') diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Math/test_modmult.py b/venv/Lib/site-packages/Cryptodome/SelfTest/Math/test_modmult.py new file mode 100644 index 0000000..df794e4 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/SelfTest/Math/test_modmult.py @@ -0,0 +1,120 @@ +# +# SelfTest/Math/test_modmult.py: Self-test for custom modular multiplication +# +# =================================================================== +# +# Copyright (c) 2023, Helder Eijs +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# =================================================================== + +"""Self-test for the custom modular multiplication""" + +import unittest + +from Cryptodome.SelfTest.st_common import list_test_cases + +from Cryptodome.Util.number import long_to_bytes, bytes_to_long + +from Cryptodome.Util._raw_api import (create_string_buffer, + get_raw_buffer, + c_size_t) + +from Cryptodome.Math._IntegerCustom import _raw_montgomery + + +class ExceptionModulus(ValueError): + pass + + +def monty_mult(term1, term2, modulus): + + if term1 >= modulus: + term1 %= modulus + if term2 >= modulus: + term2 %= modulus + + modulus_b = long_to_bytes(modulus) + numbers_len = len(modulus_b) + term1_b = long_to_bytes(term1, numbers_len) + term2_b = long_to_bytes(term2, numbers_len) + + out = create_string_buffer(numbers_len) + error = _raw_montgomery.monty_multiply( + out, + term1_b, + term2_b, + modulus_b, + c_size_t(numbers_len) + ) + + if error == 17: + raise ExceptionModulus() + if error: + raise ValueError("monty_multiply() failed with error: %d" % error) + + return get_raw_buffer(out) + + +modulus1 = 0xd66691b20071be4d66d4b71032b37fa007cfabf579fcb91e50bfc2753b3f0ce7be74e216aef7e26d4ae180bc20d7bd3ea88a6cbf6f87380e613c8979b5b043b200a8ff8856a3b12875e36e98a7569f3852d028e967551000b02c19e9fa52e83115b89309aabb1e1cf1e2cb6369d637d46775ce4523ea31f64ad2794cbc365dd8a35e007ed3b57695877fbf102dbeb8b3212491398e494314e93726926e1383f8abb5889bea954eb8c0ca1c62c8e9d83f41888095c5e645ed6d32515fe0c58c1368cad84694e18da43668c6f43e61d7c9bca633ddcda7aef5b79bc396d4a9f48e2a9abe0836cc455e435305357228e93d25aaed46b952defae0f57339bf26f5a9 + + +class TestModMultiply(unittest.TestCase): + + def test_small(self): + self.assertEqual(b"\x01", monty_mult(5, 6, 29)) + + def test_large(self): + numbers_len = (modulus1.bit_length() + 7) // 8 + + t1 = modulus1 // 2 + t2 = modulus1 - 90 + expect = b'\x00' * (numbers_len - 1) + b'\x2d' + self.assertEqual(expect, monty_mult(t1, t2, modulus1)) + + def test_zero_term(self): + numbers_len = (modulus1.bit_length() + 7) // 8 + expect = b'\x00' * numbers_len + self.assertEqual(expect, monty_mult(0x100, 0, modulus1)) + self.assertEqual(expect, monty_mult(0, 0x100, modulus1)) + + def test_larger_term(self): + t1 = 2**2047 + expect_int = 0x8edf4071f78e3d7ba622cdbbbef74612e301d69186776ae6bf87ff38c320d9aebaa64889c2f67de2324e6bccd2b10ad89e91fd21ba4bb523904d033eff5e70e62f01a84f41fa90a4f248ef249b82e1d2729253fdfc2a3b5b740198123df8bfbf7057d03e15244ad5f26eb9a099763b5c5972121ec076b0bf899f59bd95f7cc129abddccf24217bce52ca0f3a44c9ccc504765dbb89734205f3ae6a8cc560494a60ea84b27d8e00fa24bdd5b4f1d4232edb61e47d3d984c1fa50a3820a2e580fbc3fc8bc11e99df53b9efadf5a40ac75d384e400905aa6f1d88950cd53b1c54dc2222115ad84a27260fa4d978155c1434c551de1ee7361a17a2f79d4388f78a5d + res = bytes_to_long(monty_mult(t1, t1, modulus1)) + self.assertEqual(res, expect_int) + + +def get_tests(config={}): + tests = [] + tests += list_test_cases(TestModMultiply) + return tests + + +if __name__ == '__main__': + def suite(): + return unittest.TestSuite(get_tests()) + unittest.main(defaultTest='suite') diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Protocol/__init__.py b/venv/Lib/site-packages/Cryptodome/SelfTest/Protocol/__init__.py new file mode 100644 index 0000000..e40f772 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/SelfTest/Protocol/__init__.py @@ -0,0 +1,45 @@ +# SelfTest/Protocol/__init__.py: Self-tests for Cryptodome.Protocol +# +# Written in 2008 by Dwayne C. Litzenberger +# +# =================================================================== +# The contents of this file are dedicated to the public domain. To +# the extent that dedication to the public domain is not available, +# everyone is granted a worldwide, perpetual, royalty-free, +# non-exclusive license to exercise all rights associated with the +# contents of this file for any purpose whatsoever. +# No rights are reserved. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# =================================================================== + +import sys + +"""Self-test for Cryptodome.Protocol""" + +def get_tests(config={}): + tests = [] + from Cryptodome.SelfTest.Protocol import test_rfc1751; tests += test_rfc1751.get_tests(config=config) + from Cryptodome.SelfTest.Protocol import test_KDF; tests += test_KDF.get_tests(config=config) + from Cryptodome.SelfTest.Protocol import test_ecdh; tests += test_ecdh.get_tests(config=config) + + from Cryptodome.SelfTest.Protocol import test_SecretSharing + tests += test_SecretSharing.get_tests(config=config) + + if sys.version_info >= (3, 9): + from Cryptodome.SelfTest.Protocol import test_HPKE + tests += test_HPKE.get_tests(config=config) + + return tests + +if __name__ == '__main__': + import unittest + suite = lambda: unittest.TestSuite(get_tests()) + unittest.main(defaultTest='suite') diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Protocol/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/SelfTest/Protocol/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000..db882e5 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/SelfTest/Protocol/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Protocol/__pycache__/test_HPKE.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/SelfTest/Protocol/__pycache__/test_HPKE.cpython-312.pyc new file mode 100644 index 0000000..74ad427 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/SelfTest/Protocol/__pycache__/test_HPKE.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Protocol/__pycache__/test_KDF.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/SelfTest/Protocol/__pycache__/test_KDF.cpython-312.pyc new file mode 100644 index 0000000..f83dd20 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/SelfTest/Protocol/__pycache__/test_KDF.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Protocol/__pycache__/test_SecretSharing.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/SelfTest/Protocol/__pycache__/test_SecretSharing.cpython-312.pyc new file mode 100644 index 0000000..53ac58f Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/SelfTest/Protocol/__pycache__/test_SecretSharing.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Protocol/__pycache__/test_ecdh.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/SelfTest/Protocol/__pycache__/test_ecdh.cpython-312.pyc new file mode 100644 index 0000000..f67151d Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/SelfTest/Protocol/__pycache__/test_ecdh.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Protocol/__pycache__/test_rfc1751.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/SelfTest/Protocol/__pycache__/test_rfc1751.cpython-312.pyc new file mode 100644 index 0000000..a4672c4 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/SelfTest/Protocol/__pycache__/test_rfc1751.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Protocol/test_HPKE.py b/venv/Lib/site-packages/Cryptodome/SelfTest/Protocol/test_HPKE.py new file mode 100644 index 0000000..d633967 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/SelfTest/Protocol/test_HPKE.py @@ -0,0 +1,491 @@ +import os +import json +import unittest +from binascii import unhexlify + +from Cryptodome.Protocol import HPKE +from Cryptodome.Protocol.HPKE import DeserializeError + +from Cryptodome.PublicKey import ECC +from Cryptodome.SelfTest.st_common import list_test_cases + +from Cryptodome.Protocol import DH +from Cryptodome.Hash import SHA256, SHA384, SHA512 + + +class HPKE_Tests(unittest.TestCase): + + key1 = ECC.generate(curve='p256') + key2 = ECC.generate(curve='p256') + + # name, size of enc + curves = { + 'p256': 65, + 'p384': 97, + 'p521': 133, + 'curve25519': 32, + 'curve448': 56, + } + + def round_trip(self, curve, aead_id): + key1 = ECC.generate(curve=curve) + aead_id = aead_id + + encryptor = HPKE.new(receiver_key=key1.public_key(), + aead_id=aead_id) + self.assertEqual(len(encryptor.enc), self.curves[curve]) + + # First message + ct = encryptor.seal(b'ABC', auth_data=b'DEF') + + decryptor = HPKE.new(receiver_key=key1, + aead_id=aead_id, + enc=encryptor.enc) + + pt = decryptor.unseal(ct, auth_data=b'DEF') + self.assertEqual(b'ABC', pt) + + # Second message + ct2 = encryptor.seal(b'GHI') + pt2 = decryptor.unseal(ct2) + self.assertEqual(b'GHI', pt2) + + def test_round_trip(self): + for curve in self.curves.keys(): + for aead_id in HPKE.AEAD: + self.round_trip(curve, aead_id) + + def test_psk(self): + aead_id = HPKE.AEAD.AES128_GCM + HPKE.new(receiver_key=self.key1.public_key(), + aead_id=aead_id, + psk=(b'a', b'c' * 32)) + + def test_info(self): + aead_id = HPKE.AEAD.AES128_GCM + HPKE.new(receiver_key=self.key1.public_key(), + aead_id=aead_id, + info=b'baba') + + def test_neg_unsupported_curve(self): + key3 = ECC.generate(curve='p224') + with self.assertRaises(ValueError) as cm: + HPKE.new(receiver_key=key3.public_key(), + aead_id=HPKE.AEAD.AES128_GCM) + self.assertIn("Unsupported curve", str(cm.exception)) + + def test_neg_too_many_private_keys(self): + with self.assertRaises(ValueError) as cm: + HPKE.new(receiver_key=self.key1, + sender_key=self.key2, + aead_id=HPKE.AEAD.AES128_GCM) + self.assertIn("Exactly 1 private key", str(cm.exception)) + + def test_neg_curve_mismatch(self): + key3 = ECC.generate(curve='p384') + with self.assertRaises(ValueError) as cm: + HPKE.new(receiver_key=self.key1.public_key(), + sender_key=key3, + aead_id=HPKE.AEAD.AES128_GCM) + self.assertIn("but recipient key", str(cm.exception)) + + def test_neg_psk(self): + with self.assertRaises(ValueError) as cm: + HPKE.new(receiver_key=self.key1.public_key(), + psk=(b'', b'G' * 32), + aead_id=HPKE.AEAD.AES128_GCM) + + with self.assertRaises(ValueError) as cm: + HPKE.new(receiver_key=self.key1.public_key(), + psk=(b'JJJ', b''), + aead_id=HPKE.AEAD.AES128_GCM) + + with self.assertRaises(ValueError) as cm: + HPKE.new(receiver_key=self.key1.public_key(), + psk=(b'JJJ', b'Y' * 31), + aead_id=HPKE.AEAD.AES128_GCM) + self.assertIn("at least 32", str(cm.exception)) + + def test_neg_wrong_enc(self): + wrong_enc = b'\xFF' + b'8' * 64 + with self.assertRaises(DeserializeError): + HPKE.new(receiver_key=self.key1, + aead_id=HPKE.AEAD.AES128_GCM, + enc=wrong_enc) + + with self.assertRaises(ValueError) as cm: + HPKE.new(receiver_key=self.key1.public_key(), + enc=self.key1.public_key().export_key(format='raw'), + aead_id=HPKE.AEAD.AES128_GCM) + self.assertIn("'enc' cannot be an input", str(cm.exception)) + + with self.assertRaises(ValueError) as cm: + HPKE.new(receiver_key=self.key1, + aead_id=HPKE.AEAD.AES128_GCM) + self.assertIn("'enc' required", str(cm.exception)) + + def test_neg_unseal_wrong_ct(self): + decryptor = HPKE.new(receiver_key=self.key1, + aead_id=HPKE.AEAD.CHACHA20_POLY1305, + enc=self.key2.public_key().export_key(format='raw')) + + with self.assertRaises(ValueError): + decryptor.unseal(b'XYZ' * 20) + + def test_neg_unseal_no_auth_data(self): + aead_id = HPKE.AEAD.CHACHA20_POLY1305 + + encryptor = HPKE.new(receiver_key=self.key1.public_key(), + aead_id=aead_id) + + ct = encryptor.seal(b'ABC', auth_data=b'DEF') + + decryptor = HPKE.new(receiver_key=self.key1, + aead_id=aead_id, + enc=encryptor.enc) + + with self.assertRaises(ValueError): + decryptor.unseal(ct) + + def test_x25519_mode_0(self): + # RFC x9180, A.1.1.1, seq 0 and 1 + + keyR_hex = "4612c550263fc8ad58375df3f557aac531d26850903e55a9f23f21d8534e8ac8" + keyR = DH.import_x25519_private_key(bytes.fromhex(keyR_hex)) + + pt_hex = "4265617574792069732074727574682c20747275746820626561757479" + pt = bytes.fromhex(pt_hex) + + ct0_hex = "f938558b5d72f1a23810b4be2ab4f84331acc02fc97babc53a52ae8218a355a96d8770ac83d07bea87e13c512a" + ct0 = bytes.fromhex(ct0_hex) + + enc_hex = "37fda3567bdbd628e88668c3c8d7e97d1d1253b6d4ea6d44c150f741f1bf4431" + enc = bytes.fromhex(enc_hex) + + aad0_hex = "436f756e742d30" + aad0 = bytes.fromhex(aad0_hex) + + aad1_hex = "436f756e742d31" + aad1 = bytes.fromhex(aad1_hex) + + info_hex = "4f6465206f6e2061204772656369616e2055726e" + info = bytes.fromhex(info_hex) + + ct1_hex = "af2d7e9ac9ae7e270f46ba1f975be53c09f8d875bdc8535458c2494e8a6eab251c03d0c22a56b8ca42c2063b84" + ct1 = bytes.fromhex(ct1_hex) + + aead_id = HPKE.AEAD.AES128_GCM + + decryptor = HPKE.new(receiver_key=keyR, + aead_id=aead_id, + info=info, + enc=enc) + + pt_X0 = decryptor.unseal(ct0, aad0) + self.assertEqual(pt_X0, pt) + + pt_X1 = decryptor.unseal(ct1, aad1) + self.assertEqual(pt_X1, pt) + + def test_x25519_mode_1(self): + # RFC x9180, A.1.2.1, seq 0 and 1 + + keyR_hex = "c5eb01eb457fe6c6f57577c5413b931550a162c71a03ac8d196babbd4e5ce0fd" + keyR = DH.import_x25519_private_key(bytes.fromhex(keyR_hex)) + + psk_id_hex = "456e6e796e20447572696e206172616e204d6f726961" + psk_id = bytes.fromhex(psk_id_hex) + + psk_hex = "0247fd33b913760fa1fa51e1892d9f307fbe65eb171e8132c2af18555a738b82" + psk = bytes.fromhex(psk_hex) + + pt_hex = "4265617574792069732074727574682c20747275746820626561757479" + pt = bytes.fromhex(pt_hex) + + ct0_hex = "e52c6fed7f758d0cf7145689f21bc1be6ec9ea097fef4e959440012f4feb73fb611b946199e681f4cfc34db8ea" + ct0 = bytes.fromhex(ct0_hex) + + enc_hex = "0ad0950d9fb9588e59690b74f1237ecdf1d775cd60be2eca57af5a4b0471c91b" + enc = bytes.fromhex(enc_hex) + + aad0_hex = "436f756e742d30" + aad0 = bytes.fromhex(aad0_hex) + + aad1_hex = "436f756e742d31" + aad1 = bytes.fromhex(aad1_hex) + + info_hex = "4f6465206f6e2061204772656369616e2055726e" + info = bytes.fromhex(info_hex) + + ct1_hex = "49f3b19b28a9ea9f43e8c71204c00d4a490ee7f61387b6719db765e948123b45b61633ef059ba22cd62437c8ba" + ct1 = bytes.fromhex(ct1_hex) + + aead_id = HPKE.AEAD.AES128_GCM + + decryptor = HPKE.new(receiver_key=keyR, + aead_id=aead_id, + info=info, + psk=(psk_id, psk), + enc=enc) + + pt_X0 = decryptor.unseal(ct0, aad0) + self.assertEqual(pt_X0, pt) + + pt_X1 = decryptor.unseal(ct1, aad1) + self.assertEqual(pt_X1, pt) + + def test_x25519_mode_2(self): + # RFC x9180, A.1.3.1, seq 0 and 1 + + keyR_hex = "fdea67cf831f1ca98d8e27b1f6abeb5b7745e9d35348b80fa407ff6958f9137e" + keyR = DH.import_x25519_private_key(bytes.fromhex(keyR_hex)) + + keyS_hex = "dc4a146313cce60a278a5323d321f051c5707e9c45ba21a3479fecdf76fc69dd" + keyS = DH.import_x25519_private_key(bytes.fromhex(keyS_hex)) + + pt_hex = "4265617574792069732074727574682c20747275746820626561757479" + pt = bytes.fromhex(pt_hex) + + ct0_hex = "5fd92cc9d46dbf8943e72a07e42f363ed5f721212cd90bcfd072bfd9f44e06b80fd17824947496e21b680c141b" + ct0 = bytes.fromhex(ct0_hex) + + enc_hex = "23fb952571a14a25e3d678140cd0e5eb47a0961bb18afcf85896e5453c312e76" + enc = bytes.fromhex(enc_hex) + + aad0_hex = "436f756e742d30" + aad0 = bytes.fromhex(aad0_hex) + + aad1_hex = "436f756e742d31" + aad1 = bytes.fromhex(aad1_hex) + + info_hex = "4f6465206f6e2061204772656369616e2055726e" + info = bytes.fromhex(info_hex) + + ct1_hex = "d3736bb256c19bfa93d79e8f80b7971262cb7c887e35c26370cfed62254369a1b52e3d505b79dd699f002bc8ed" + ct1 = bytes.fromhex(ct1_hex) + + aead_id = HPKE.AEAD.AES128_GCM + + decryptor = HPKE.new(receiver_key=keyR, + sender_key=keyS.public_key(), + aead_id=aead_id, + info=info, + enc=enc) + + pt_X0 = decryptor.unseal(ct0, aad0) + self.assertEqual(pt_X0, pt) + + pt_X1 = decryptor.unseal(ct1, aad1) + self.assertEqual(pt_X1, pt) + + def test_x25519_mode_3(self): + # RFC x9180, A.1.4.1, seq 0 and 1 + + keyR_hex = "cb29a95649dc5656c2d054c1aa0d3df0493155e9d5da6d7e344ed8b6a64a9423" + keyR = DH.import_x25519_private_key(bytes.fromhex(keyR_hex)) + + keyS_hex = "fc1c87d2f3832adb178b431fce2ac77c7ca2fd680f3406c77b5ecdf818b119f4" + keyS = DH.import_x25519_private_key(bytes.fromhex(keyS_hex)) + + psk_id_hex = "456e6e796e20447572696e206172616e204d6f726961" + psk_id = bytes.fromhex(psk_id_hex) + + psk_hex = "0247fd33b913760fa1fa51e1892d9f307fbe65eb171e8132c2af18555a738b82" + psk = bytes.fromhex(psk_hex) + + pt_hex = "4265617574792069732074727574682c20747275746820626561757479" + pt = bytes.fromhex(pt_hex) + + ct0_hex = "a84c64df1e11d8fd11450039d4fe64ff0c8a99fca0bd72c2d4c3e0400bc14a40f27e45e141a24001697737533e" + ct0 = bytes.fromhex(ct0_hex) + + enc_hex = "820818d3c23993492cc5623ab437a48a0a7ca3e9639c140fe1e33811eb844b7c" + enc = bytes.fromhex(enc_hex) + + aad0_hex = "436f756e742d30" + aad0 = bytes.fromhex(aad0_hex) + + aad1_hex = "436f756e742d31" + aad1 = bytes.fromhex(aad1_hex) + + info_hex = "4f6465206f6e2061204772656369616e2055726e" + info = bytes.fromhex(info_hex) + + ct1_hex = "4d19303b848f424fc3c3beca249b2c6de0a34083b8e909b6aa4c3688505c05ffe0c8f57a0a4c5ab9da127435d9" + ct1 = bytes.fromhex(ct1_hex) + + aead_id = HPKE.AEAD.AES128_GCM + + decryptor = HPKE.new(receiver_key=keyR, + sender_key=keyS.public_key(), + aead_id=aead_id, + psk=(psk_id, psk), + info=info, + enc=enc) + + pt_X0 = decryptor.unseal(ct0, aad0) + self.assertEqual(pt_X0, pt) + + pt_X1 = decryptor.unseal(ct1, aad1) + self.assertEqual(pt_X1, pt) + + +class HPKE_TestVectors(unittest.TestCase): + + def setUp(self): + self.vectors = [] + try: + import pycryptodome_test_vectors # type: ignore + init_dir = os.path.dirname(pycryptodome_test_vectors.__file__) + full_file_name = os.path.join(init_dir, "Protocol", "wycheproof", "HPKE-test-vectors.json") + with open(full_file_name, "r") as f: + self.vectors = json.load(f) + except (FileNotFoundError, ImportError): + print("\nWarning: skipping extended tests for HPKE (install pycryptodome-test-vectors)") + + def import_private_key(self, key_hex, kem_id): + key_bin = unhexlify(key_hex) + if kem_id == 0x0010: + return ECC.construct(curve='p256', d=int.from_bytes(key_bin, + byteorder="big")) + elif kem_id == 0x0011: + return ECC.construct(curve='p384', d=int.from_bytes(key_bin, + byteorder="big")) + elif kem_id == 0x0012: + return ECC.construct(curve='p521', d=int.from_bytes(key_bin, + byteorder="big")) + elif kem_id == 0x0020: + return DH.import_x25519_private_key(key_bin) + elif kem_id == 0x0021: + return DH.import_x448_private_key(key_bin) + + def test_hpke_encap(self): + """Test HPKE encapsulation using test vectors.""" + + if not self.vectors: + self.skipTest("No test vectors available") + + for idx, vector in enumerate(self.vectors): + + kem_id = vector["kem_id"] + kdf_id = vector["kdf_id"] + aead_id = vector["aead_id"] + + # No export-only pseudo-cipher + if aead_id == 0xffff: + continue + + # We support only one KDF per curve + supported_combi = { + (0x10, 0x1): SHA256, + (0x11, 0x2): SHA384, + (0x12, 0x3): SHA512, + (0x20, 0x1): SHA256, + (0x21, 0x3): SHA512, + } + hashmod = supported_combi.get((kem_id, kdf_id)) + if hashmod is None: + continue + + with self.subTest(idx=idx, kem_id=kem_id, aead_id=aead_id): + + receiver_pub = self.import_private_key(vector["skRm"], + kem_id).public_key() + + sender_priv = None + if "skSm" in vector: + sender_priv = self.import_private_key(vector["skSm"], + kem_id) + + encap_key = self.import_private_key(vector["skEm"], kem_id) + + shared_secret, enc = HPKE.HPKE_Cipher._encap(receiver_pub, + kem_id, + hashmod, + sender_priv, + encap_key) + self.assertEqual(enc.hex(), vector["enc"]) + self.assertEqual(shared_secret, + unhexlify(vector["shared_secret"])) + + print(".", end="", flush=True) + + def test_hpke_unseal(self): + """Test HPKE encryption and decryption using test vectors.""" + + if not self.vectors: + self.skipTest("No test vectors available") + + for idx, vector in enumerate(self.vectors): + + kem_id = vector["kem_id"] + kdf_id = vector["kdf_id"] + aead_id = vector["aead_id"] + + # No export-only pseudo-cipher + if aead_id == 0xffff: + continue + + # We support only one KDF per curve + supported_combi = ( + (0x10, 0x1), + (0x11, 0x2), + (0x12, 0x3), + (0x20, 0x1), + (0x21, 0x3), + ) + if (kem_id, kdf_id) not in supported_combi: + continue + + with self.subTest(idx=idx, kem_id=kem_id, aead_id=aead_id): + + receiver_priv = self.import_private_key(vector["skRm"], + kem_id) + + sender_pub = None + if "skSm" in vector: + sender_priv = self.import_private_key(vector["skSm"], + kem_id) + sender_pub = sender_priv.public_key() + + encap_key = unhexlify(vector["enc"]) + + psk = None + if "psk_id" in vector: + psk = unhexlify(vector["psk_id"]), unhexlify(vector["psk"]) + + receiver_hpke = HPKE.new(receiver_key=receiver_priv, + aead_id=HPKE.AEAD(aead_id), + enc=encap_key, + sender_key=sender_pub, + psk=psk, + info=unhexlify(vector["info"])) + + for encryption in vector['encryptions']: + + plaintext = unhexlify(encryption["pt"]) + ciphertext = unhexlify(encryption["ct"]) + aad = unhexlify(encryption["aad"]) + + # Decrypt (unseal) + decrypted = receiver_hpke.unseal(ciphertext, aad) + self.assertEqual(decrypted, plaintext, "Decryption failed") + + print(".", end="", flush=True) + + +def get_tests(config={}): + + tests = [] + tests += list_test_cases(HPKE_Tests) + + if config.get('slow_tests'): + tests += list_test_cases(HPKE_TestVectors) + + return tests + + +if __name__ == '__main__': + def suite(): + return unittest.TestSuite(get_tests()) + unittest.main(defaultTest='suite') diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Protocol/test_KDF.py b/venv/Lib/site-packages/Cryptodome/SelfTest/Protocol/test_KDF.py new file mode 100644 index 0000000..eafe349 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/SelfTest/Protocol/test_KDF.py @@ -0,0 +1,809 @@ +# -*- coding: utf-8 -*- +# +# SelfTest/Protocol/test_KDF.py: Self-test for key derivation functions +# +# =================================================================== +# The contents of this file are dedicated to the public domain. To +# the extent that dedication to the public domain is not available, +# everyone is granted a worldwide, perpetual, royalty-free, +# non-exclusive license to exercise all rights associated with the +# contents of this file for any purpose whatsoever. +# No rights are reserved. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# =================================================================== + +import re +import unittest +from binascii import unhexlify + +from Cryptodome.Util.py3compat import b, bchr + +from Cryptodome.SelfTest.st_common import list_test_cases +from Cryptodome.SelfTest.loader import load_test_vectors, load_test_vectors_wycheproof +from Cryptodome.Hash import SHA1, HMAC, SHA256, MD5, SHA224, SHA384, SHA512 +from Cryptodome.Cipher import AES, DES3 + +from Cryptodome.Protocol.KDF import (PBKDF1, PBKDF2, _S2V, HKDF, scrypt, + bcrypt, bcrypt_check, + SP800_108_Counter) + +from Cryptodome.Protocol.KDF import _bcrypt_decode + + +def t2b(t): + if t is None: + return None + t2 = t.replace(" ", "").replace("\n", "") + return unhexlify(b(t2)) + + +class TestVector(object): + pass + + +class PBKDF1_Tests(unittest.TestCase): + + # List of tuples with test data. + # Each tuple is made up by: + # Item #0: a pass phrase + # Item #1: salt (8 bytes encoded in hex) + # Item #2: output key length + # Item #3: iterations to use + # Item #4: expected result (encoded in hex) + _testData = ( + # From http://www.di-mgt.com.au/cryptoKDFs.html#examplespbkdf + ("password", "78578E5A5D63CB06", 16, 1000, "DC19847E05C64D2FAF10EBFB4A3D2A20"), + ) + + def test1(self): + v = self._testData[0] + res = PBKDF1(v[0], t2b(v[1]), v[2], v[3], SHA1) + self.assertEqual(res, t2b(v[4])) + + +class PBKDF2_Tests(unittest.TestCase): + + # List of tuples with test data. + # Each tuple is made up by: + # Item #0: a pass phrase + # Item #1: salt (encoded in hex) + # Item #2: output key length + # Item #3: iterations to use + # Item #4: hash module + # Item #5: expected result (encoded in hex) + _testData = ( + # From http://www.di-mgt.com.au/cryptoKDFs.html#examplespbkdf + ("password","78578E5A5D63CB06",24,2048, SHA1, "BFDE6BE94DF7E11DD409BCE20A0255EC327CB936FFE93643"), + # From RFC 6050 + ("password","73616c74", 20, 1, SHA1, "0c60c80f961f0e71f3a9b524af6012062fe037a6"), + ("password","73616c74", 20, 2, SHA1, "ea6c014dc72d6f8ccd1ed92ace1d41f0d8de8957"), + ("password","73616c74", 20, 4096, SHA1, "4b007901b765489abead49d926f721d065a429c1"), + ("passwordPASSWORDpassword","73616c7453414c5473616c7453414c5473616c7453414c5473616c7453414c5473616c74", + 25, 4096, SHA1, "3d2eec4fe41c849b80c8d83662c0e44a8b291a964cf2f07038"), + ( 'pass\x00word',"7361006c74",16,4096, SHA1, "56fa6aa75548099dcc37d7f03425e0c3"), + # From draft-josefsson-scrypt-kdf-01, Chapter 10 + ( 'passwd', '73616c74', 64, 1, SHA256, "55ac046e56e3089fec1691c22544b605f94185216dde0465e68b9d57c20dacbc49ca9cccf179b645991664b39d77ef317c71b845b1e30bd509112041d3a19783"), + ( 'Password', '4e61436c', 64, 80000, SHA256, "4ddcd8f60b98be21830cee5ef22701f9641a4418d04c0414aeff08876b34ab56a1d425a1225833549adb841b51c9b3176a272bdebba1d078478f62b397f33c8d"), + ) + + def test1(self): + # Test only for HMAC-SHA1 as PRF + + def prf_SHA1(p,s): + return HMAC.new(p,s,SHA1).digest() + + def prf_SHA256(p,s): + return HMAC.new(p,s,SHA256).digest() + + for i in range(len(self._testData)): + v = self._testData[i] + password = v[0] + salt = t2b(v[1]) + out_len = v[2] + iters = v[3] + hash_mod = v[4] + expected = t2b(v[5]) + + if hash_mod is SHA1: + res = PBKDF2(password, salt, out_len, iters) + self.assertEqual(res, expected) + + res = PBKDF2(password, salt, out_len, iters, prf_SHA1) + self.assertEqual(res, expected) + else: + res = PBKDF2(password, salt, out_len, iters, prf_SHA256) + self.assertEqual(res, expected) + + def test2(self): + # Verify that prf and hmac_hash_module are mutual exclusive + def prf_SHA1(p,s): + return HMAC.new(p,s,SHA1).digest() + + self.assertRaises(ValueError, PBKDF2, b("xxx"), b("yyy"), 16, 100, + prf=prf_SHA1, hmac_hash_module=SHA1) + + def test3(self): + # Verify that hmac_hash_module works like prf + + password = b("xxx") + salt = b("yyy") + + for hashmod in (MD5, SHA1, SHA224, SHA256, SHA384, SHA512): + + pr1 = PBKDF2(password, salt, 16, 100, + prf=lambda p, s: HMAC.new(p,s,hashmod).digest()) + pr2 = PBKDF2(password, salt, 16, 100, hmac_hash_module=hashmod) + + self.assertEqual(pr1, pr2) + + def test4(self): + # Verify that PBKDF2 can take bytes or strings as password or salt + k1 = PBKDF2("xxx", b("yyy"), 16, 10) + k2 = PBKDF2(b("xxx"), b("yyy"), 16, 10) + self.assertEqual(k1, k2) + + k1 = PBKDF2(b("xxx"), "yyy", 16, 10) + k2 = PBKDF2(b("xxx"), b("yyy"), 16, 10) + self.assertEqual(k1, k2) + + +class S2V_Tests(unittest.TestCase): + + # Sequence of test vectors. + # Each test vector is made up by: + # Item #0: a tuple of strings + # Item #1: an AES key + # Item #2: the result + # Item #3: the cipher module S2V is based on + # Everything is hex encoded + _testData = [ + + # RFC5297, A.1 + ( + ( '101112131415161718191a1b1c1d1e1f2021222324252627', + '112233445566778899aabbccddee' ), + 'fffefdfcfbfaf9f8f7f6f5f4f3f2f1f0', + '85632d07c6e8f37f950acd320a2ecc93', + AES + ), + + # RFC5297, A.2 + ( + ( '00112233445566778899aabbccddeeffdeaddadadeaddadaffeeddcc'+ + 'bbaa99887766554433221100', + '102030405060708090a0', + '09f911029d74e35bd84156c5635688c0', + '7468697320697320736f6d6520706c61'+ + '696e7465787420746f20656e63727970'+ + '74207573696e67205349562d414553'), + '7f7e7d7c7b7a79787776757473727170', + '7bdb6e3b432667eb06f4d14bff2fbd0f', + AES + ), + + ] + + def test1(self): + """Verify correctness of test vector""" + for tv in self._testData: + s2v = _S2V.new(t2b(tv[1]), tv[3]) + for s in tv[0]: + s2v.update(t2b(s)) + result = s2v.derive() + self.assertEqual(result, t2b(tv[2])) + + def test2(self): + """Verify that no more than 127(AES) and 63(TDES) + components are accepted.""" + key = bchr(0) * 8 + bchr(255) * 8 + for module in (AES, DES3): + s2v = _S2V.new(key, module) + max_comps = module.block_size*8-1 + for i in range(max_comps): + s2v.update(b("XX")) + self.assertRaises(TypeError, s2v.update, b("YY")) + + +class HKDF_Tests(unittest.TestCase): + + # Test vectors from RFC5869, Appendix A + # Each tuple is made up by: + # Item #0: hash module + # Item #1: secret + # Item #2: salt + # Item #3: context + # Item #4: expected result + _test_vector = ( + ( + SHA256, + "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", + "000102030405060708090a0b0c", + "f0f1f2f3f4f5f6f7f8f9", + 42, + "3cb25f25faacd57a90434f64d0362f2a" + + "2d2d0a90cf1a5a4c5db02d56ecc4c5bf" + + "34007208d5b887185865" + ), + ( + SHA256, + "000102030405060708090a0b0c0d0e0f" + + "101112131415161718191a1b1c1d1e1f" + + "202122232425262728292a2b2c2d2e2f" + + "303132333435363738393a3b3c3d3e3f" + + "404142434445464748494a4b4c4d4e4f", + "606162636465666768696a6b6c6d6e6f" + + "707172737475767778797a7b7c7d7e7f" + + "808182838485868788898a8b8c8d8e8f" + + "909192939495969798999a9b9c9d9e9f" + + "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf", + "b0b1b2b3b4b5b6b7b8b9babbbcbdbebf" + + "c0c1c2c3c4c5c6c7c8c9cacbcccdcecf" + + "d0d1d2d3d4d5d6d7d8d9dadbdcdddedf" + + "e0e1e2e3e4e5e6e7e8e9eaebecedeeef" + + "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + 82, + "b11e398dc80327a1c8e7f78c596a4934" + + "4f012eda2d4efad8a050cc4c19afa97c" + + "59045a99cac7827271cb41c65e590e09" + + "da3275600c2f09b8367793a9aca3db71" + + "cc30c58179ec3e87c14c01d5c1f3434f" + + "1d87" + ), + ( + SHA256, + "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", + None, + None, + 42, + "8da4e775a563c18f715f802a063c5a31" + + "b8a11f5c5ee1879ec3454e5f3c738d2d" + + "9d201395faa4b61a96c8" + ), + ( + SHA1, + "0b0b0b0b0b0b0b0b0b0b0b", + "000102030405060708090a0b0c", + "f0f1f2f3f4f5f6f7f8f9", + 42, + "085a01ea1b10f36933068b56efa5ad81" + + "a4f14b822f5b091568a9cdd4f155fda2" + + "c22e422478d305f3f896" + ), + ( + SHA1, + "000102030405060708090a0b0c0d0e0f" + + "101112131415161718191a1b1c1d1e1f" + + "202122232425262728292a2b2c2d2e2f" + + "303132333435363738393a3b3c3d3e3f" + + "404142434445464748494a4b4c4d4e4f", + "606162636465666768696a6b6c6d6e6f" + + "707172737475767778797a7b7c7d7e7f" + + "808182838485868788898a8b8c8d8e8f" + + "909192939495969798999a9b9c9d9e9f" + + "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf", + "b0b1b2b3b4b5b6b7b8b9babbbcbdbebf" + + "c0c1c2c3c4c5c6c7c8c9cacbcccdcecf" + + "d0d1d2d3d4d5d6d7d8d9dadbdcdddedf" + + "e0e1e2e3e4e5e6e7e8e9eaebecedeeef" + + "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + 82, + "0bd770a74d1160f7c9f12cd5912a06eb" + + "ff6adcae899d92191fe4305673ba2ffe" + + "8fa3f1a4e5ad79f3f334b3b202b2173c" + + "486ea37ce3d397ed034c7f9dfeb15c5e" + + "927336d0441f4c4300e2cff0d0900b52" + + "d3b4" + ), + ( + SHA1, + "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", + "", + "", + 42, + "0ac1af7002b3d761d1e55298da9d0506" + + "b9ae52057220a306e07b6b87e8df21d0" + + "ea00033de03984d34918" + ), + ( + SHA1, + "0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c", + None, + "", + 42, + "2c91117204d745f3500d636a62f64f0a" + + "b3bae548aa53d423b0d1f27ebba6f5e5" + + "673a081d70cce7acfc48" + ) + ) + + def test1(self): + for tv in self._test_vector: + secret, salt, info, exp = [ t2b(tv[x]) for x in (1,2,3,5) ] + key_len, hashmod = [ tv[x] for x in (4,0) ] + + output = HKDF(secret, key_len, salt, hashmod, 1, info) + self.assertEqual(output, exp) + + def test2(self): + ref = HKDF(b("XXXXXX"), 12, b("YYYY"), SHA1) + + # Same output, but this time split over 2 keys + key1, key2 = HKDF(b("XXXXXX"), 6, b("YYYY"), SHA1, 2) + self.assertEqual((ref[:6], ref[6:]), (key1, key2)) + + # Same output, but this time split over 3 keys + key1, key2, key3 = HKDF(b("XXXXXX"), 4, b("YYYY"), SHA1, 3) + self.assertEqual((ref[:4], ref[4:8], ref[8:]), (key1, key2, key3)) + + +class scrypt_Tests(unittest.TestCase): + + # Test vectors taken from + # https://tools.ietf.org/html/rfc7914 + # - password + # - salt + # - N + # - r + # - p + data = ( + ( + "", + "", + 16, # 2K + 1, + 1, + """ + 77 d6 57 62 38 65 7b 20 3b 19 ca 42 c1 8a 04 97 + f1 6b 48 44 e3 07 4a e8 df df fa 3f ed e2 14 42 + fc d0 06 9d ed 09 48 f8 32 6a 75 3a 0f c8 1f 17 + e8 d3 e0 fb 2e 0d 36 28 cf 35 e2 0c 38 d1 89 06 + """ + ), + ( + "password", + "NaCl", + 1024, # 1M + 8, + 16, + """ + fd ba be 1c 9d 34 72 00 78 56 e7 19 0d 01 e9 fe + 7c 6a d7 cb c8 23 78 30 e7 73 76 63 4b 37 31 62 + 2e af 30 d9 2e 22 a3 88 6f f1 09 27 9d 98 30 da + c7 27 af b9 4a 83 ee 6d 83 60 cb df a2 cc 06 40 + """ + ), + ( + "pleaseletmein", + "SodiumChloride", + 16384, # 16M + 8, + 1, + """ + 70 23 bd cb 3a fd 73 48 46 1c 06 cd 81 fd 38 eb + fd a8 fb ba 90 4f 8e 3e a9 b5 43 f6 54 5d a1 f2 + d5 43 29 55 61 3f 0f cf 62 d4 97 05 24 2a 9a f9 + e6 1e 85 dc 0d 65 1e 40 df cf 01 7b 45 57 58 87 + """ + ), + ( + "pleaseletmein", + "SodiumChloride", + 1048576, # 1G + 8, + 1, + """ + 21 01 cb 9b 6a 51 1a ae ad db be 09 cf 70 f8 81 + ec 56 8d 57 4a 2f fd 4d ab e5 ee 98 20 ad aa 47 + 8e 56 fd 8f 4b a5 d0 9f fa 1c 6d 92 7c 40 f4 c3 + 37 30 40 49 e8 a9 52 fb cb f4 5c 6f a7 7a 41 a4 + """ + ), + ) + + def setUp(self): + new_test_vectors = [] + for tv in self.data: + new_tv = TestVector() + new_tv.P = b(tv[0]) + new_tv.S = b(tv[1]) + new_tv.N = tv[2] + new_tv.r = tv[3] + new_tv.p = tv[4] + new_tv.output = t2b(tv[5]) + new_tv.dkLen = len(new_tv.output) + new_test_vectors.append(new_tv) + self.data = new_test_vectors + + def test2(self): + + for tv in self.data: + try: + output = scrypt(tv.P, tv.S, tv.dkLen, tv.N, tv.r, tv.p) + except ValueError as e: + if " 2 " in str(e) and tv.N >= 1048576: + import warnings + warnings.warn("Not enough memory to unit test scrypt() with N=1048576", RuntimeWarning) + continue + else: + raise e + self.assertEqual(output, tv.output) + + def test3(self): + ref = scrypt(b("password"), b("salt"), 12, 16, 1, 1) + + # Same output, but this time split over 2 keys + key1, key2 = scrypt(b("password"), b("salt"), 6, 16, 1, 1, 2) + self.assertEqual((ref[:6], ref[6:]), (key1, key2)) + + # Same output, but this time split over 3 keys + key1, key2, key3 = scrypt(b("password"), b("salt"), 4, 16, 1, 1, 3) + self.assertEqual((ref[:4], ref[4:8], ref[8:]), (key1, key2, key3)) + + +class bcrypt_Tests(unittest.TestCase): + + def test_negative_cases(self): + self.assertRaises(ValueError, bcrypt, b"1" * 73, 10) + self.assertRaises(ValueError, bcrypt, b"1" * 10, 3) + self.assertRaises(ValueError, bcrypt, b"1" * 10, 32) + self.assertRaises(ValueError, bcrypt, b"1" * 10, 4, salt=b"") + self.assertRaises(ValueError, bcrypt, b"1" * 10, 4, salt=b"1") + self.assertRaises(ValueError, bcrypt, b"1" * 10, 4, salt=b"1" * 17) + self.assertRaises(ValueError, bcrypt, b"1\x00" * 10, 4) + + def test_bytearray_mismatch(self): + ref = bcrypt("pwd", 4) + bcrypt_check("pwd", ref) + bref = bytearray(ref) + bcrypt_check("pwd", bref) + + wrong = ref[:-1] + bchr(bref[-1] ^ 0x01) + self.assertRaises(ValueError, bcrypt_check, "pwd", wrong) + + wrong = b"x" + ref[1:] + self.assertRaises(ValueError, bcrypt_check, "pwd", wrong) + + # https://github.com/patrickfav/bcrypt/wiki/Published-Test-Vectors + + def test_empty_password(self): + # password, cost, salt, bcrypt hash + tvs = [ + (b"", 4, b"zVHmKQtGGQob.b/Nc7l9NO", b"$2a$04$zVHmKQtGGQob.b/Nc7l9NO8UlrYcW05FiuCj/SxsFO/ZtiN9.mNzy"), + (b"", 5, b"zVHmKQtGGQob.b/Nc7l9NO", b"$2a$05$zVHmKQtGGQob.b/Nc7l9NOWES.1hkVBgy5IWImh9DOjKNU8atY4Iy"), + (b"", 6, b"zVHmKQtGGQob.b/Nc7l9NO", b"$2a$06$zVHmKQtGGQob.b/Nc7l9NOjOl7l4oz3WSh5fJ6414Uw8IXRAUoiaO"), + (b"", 7, b"zVHmKQtGGQob.b/Nc7l9NO", b"$2a$07$zVHmKQtGGQob.b/Nc7l9NOBsj1dQpBA1HYNGpIETIByoNX9jc.hOi"), + (b"", 8, b"zVHmKQtGGQob.b/Nc7l9NO", b"$2a$08$zVHmKQtGGQob.b/Nc7l9NOiLTUh/9MDpX86/DLyEzyiFjqjBFePgO"), + ] + + for (idx, (password, cost, salt64, result)) in enumerate(tvs): + x = bcrypt(password, cost, salt=_bcrypt_decode(salt64)) + self.assertEqual(x, result) + bcrypt_check(password, result) + + def test_random_password_and_salt_short_pw(self): + # password, cost, salt, bcrypt hash + tvs = [ + (b"<.S.2K(Zq'", 4, b"VYAclAMpaXY/oqAo9yUpku", b"$2a$04$VYAclAMpaXY/oqAo9yUpkuWmoYywaPzyhu56HxXpVltnBIfmO9tgu"), + (b"5.rApO%5jA", 5, b"kVNDrnYKvbNr5AIcxNzeIu", b"$2a$05$kVNDrnYKvbNr5AIcxNzeIuRcyIF5cZk6UrwHGxENbxP5dVv.WQM/G"), + (b"oW++kSrQW^", 6, b"QLKkRMH9Am6irtPeSKN5sO", b"$2a$06$QLKkRMH9Am6irtPeSKN5sObJGr3j47cO6Pdf5JZ0AsJXuze0IbsNm"), + (b"ggJ\\KbTnDG", 7, b"4H896R09bzjhapgCPS/LYu", b"$2a$07$4H896R09bzjhapgCPS/LYuMzAQluVgR5iu/ALF8L8Aln6lzzYXwbq"), + (b"49b0:;VkH/", 8, b"hfvO2retKrSrx5f2RXikWe", b"$2a$08$hfvO2retKrSrx5f2RXikWeFWdtSesPlbj08t/uXxCeZoHRWDz/xFe"), + (b">9N^5jc##'", 9, b"XZLvl7rMB3EvM0c1.JHivu", b"$2a$09$XZLvl7rMB3EvM0c1.JHivuIDPJWeNJPTVrpjZIEVRYYB/mF6cYgJK"), + (b"\\$ch)s4WXp", 10, b"aIjpMOLK5qiS9zjhcHR5TO", b"$2a$10$aIjpMOLK5qiS9zjhcHR5TOU7v2NFDmcsBmSFDt5EHOgp/jeTF3O/q"), + (b"RYoj\\_>2P7", 12, b"esIAHiQAJNNBrsr5V13l7.", b"$2a$12$esIAHiQAJNNBrsr5V13l7.RFWWJI2BZFtQlkFyiWXjou05GyuREZa"), + ] + + for (idx, (password, cost, salt64, result)) in enumerate(tvs): + x = bcrypt(password, cost, salt=_bcrypt_decode(salt64)) + self.assertEqual(x, result) + bcrypt_check(password, result) + + def test_random_password_and_salt_long_pw(self): + # password, cost, salt, bcrypt hash + tvs = [ + (b"^Q&\"]A`%/A(BVGt>QaX0M-#1ghq_+\":Y0CRmY", 5, b"YuQvhokOGVnevctykUYpKu", b"$2a$05$YuQvhokOGVnevctykUYpKutZD2pWeGGYn3auyLOasguMY3/0BbIyq"), + (b"F%uN/j>[GuB7-jB'_Yj!Tnb7Y!u^6)", 6, b"5L3vpQ0tG9O7k5gQ8nAHAe", b"$2a$06$5L3vpQ0tG9O7k5gQ8nAHAe9xxQiOcOLh8LGcI0PLWhIznsDt.S.C6"), + (b"Z>BobP32ub\"Cfe*Q<-q-=tRSjOBh8\\mLNW.", 9, b"nArqOfdCsD9kIbVnAixnwe", b"$2a$09$nArqOfdCsD9kIbVnAixnwe6s8QvyPYWtQBpEXKir2OJF9/oNBsEFe"), + (b"/MH51`!BP&0tj3%YCA;Xk%e3S`o\\EI", 10, b"ePiAc.s.yoBi3B6p1iQUCe", b"$2a$10$ePiAc.s.yoBi3B6p1iQUCezn3mraLwpVJ5XGelVyYFKyp5FZn/y.u"), + (b"ptAP\"mcg6oH.\";c0U2_oll.OKi5?Ui\"^ai#iQH7ZFtNMfs3AROnIncE9\"BNNoEgO[[*Yk8;RQ(#S,;I+aT", + 5, b"wgkOlGNXIVE2fWkT3gyRoO", b"$2a$05$wgkOlGNXIVE2fWkT3gyRoOqWi4gbi1Wv2Q2Jx3xVs3apl1w.Wtj8C"), + (b"M.E1=dt<.L0Q&p;94NfGm_Oo23+Kpl@M5?WIAL.[@/:'S)W96G8N^AWb7_smmC]>7#fGoB", + 6, b"W9zTCl35nEvUukhhFzkKMe", b"$2a$06$W9zTCl35nEvUukhhFzkKMekjT9/pj7M0lihRVEZrX3m8/SBNZRX7i"), + ] + + for (idx, (password, cost, salt64, result)) in enumerate(tvs): + x = bcrypt(password, cost, salt=_bcrypt_decode(salt64)) + self.assertEqual(x, result) + bcrypt_check(password, result) + + def test_increasing_password_length(self): + # password, cost, salt, bcrypt hash + tvs = [ + (b"a", 4, b"5DCebwootqWMCp59ISrMJ.", b"$2a$04$5DCebwootqWMCp59ISrMJ.l4WvgHIVg17ZawDIrDM2IjlE64GDNQS"), + (b"aa", 4, b"5DCebwootqWMCp59ISrMJ.", b"$2a$04$5DCebwootqWMCp59ISrMJ.AyUxBk.ThHlsLvRTH7IqcG7yVHJ3SXq"), + (b"aaa", 4, b"5DCebwootqWMCp59ISrMJ.", b"$2a$04$5DCebwootqWMCp59ISrMJ.BxOVac5xPB6XFdRc/ZrzM9FgZkqmvbW"), + (b"aaaa", 4, b"5DCebwootqWMCp59ISrMJ.", b"$2a$04$5DCebwootqWMCp59ISrMJ.Qbr209bpCtfl5hN7UQlG/L4xiD3AKau"), + (b"aaaaa", 4, b"5DCebwootqWMCp59ISrMJ.", b"$2a$04$5DCebwootqWMCp59ISrMJ.oWszihPjDZI0ypReKsaDOW1jBl7oOii"), + (b"aaaaaa", 4, b"5DCebwootqWMCp59ISrMJ.", b"$2a$04$5DCebwootqWMCp59ISrMJ./k.Xxn9YiqtV/sxh3EHbnOHd0Qsq27K"), + (b"aaaaaaa", 4, b"5DCebwootqWMCp59ISrMJ.", b"$2a$04$5DCebwootqWMCp59ISrMJ.PYJqRFQbgRbIjMd5VNKmdKS4sBVOyDe"), + (b"aaaaaaaa", 4, b"5DCebwootqWMCp59ISrMJ.", b"$2a$04$5DCebwootqWMCp59ISrMJ..VMYfzaw1wP/SGxowpLeGf13fxCCt.q"), + (b"aaaaaaaaa", 4, b"5DCebwootqWMCp59ISrMJ.", b"$2a$04$5DCebwootqWMCp59ISrMJ.5B0p054nO5WgAD1n04XslDY/bqY9RJi"), + (b"aaaaaaaaaa", 4, b"5DCebwootqWMCp59ISrMJ.", b"$2a$04$5DCebwootqWMCp59ISrMJ.INBTgqm7sdlBJDg.J5mLMSRK25ri04y"), + (b"aaaaaaaaaaa", 4, b"5DCebwootqWMCp59ISrMJ.", b"$2a$04$5DCebwootqWMCp59ISrMJ.s3y7CdFD0OR5p6rsZw/eZ.Dla40KLfm"), + (b"aaaaaaaaaaaa", 4, b"5DCebwootqWMCp59ISrMJ.", b"$2a$04$5DCebwootqWMCp59ISrMJ.Jx742Djra6Q7PqJWnTAS.85c28g.Siq"), + (b"aaaaaaaaaaaaa", 4, b"5DCebwootqWMCp59ISrMJ.", b"$2a$04$5DCebwootqWMCp59ISrMJ.oKMXW3EZcPHcUV0ib5vDBnh9HojXnLu"), + (b"aaaaaaaaaaaaaa", 4, b"5DCebwootqWMCp59ISrMJ.", b"$2a$04$5DCebwootqWMCp59ISrMJ.w6nIjWpDPNSH5pZUvLjC1q25ONEQpeS"), + (b"aaaaaaaaaaaaaaa", 4, b"5DCebwootqWMCp59ISrMJ.", b"$2a$04$5DCebwootqWMCp59ISrMJ.k1b2/r9A/hxdwKEKurg6OCn4MwMdiGq"), + (b"aaaaaaaaaaaaaaaa", 4, b"5DCebwootqWMCp59ISrMJ.", b"$2a$04$5DCebwootqWMCp59ISrMJ.3prCNHVX1Ws.7Hm2bJxFUnQOX9f7DFa"), + ] + + for (idx, (password, cost, salt64, result)) in enumerate(tvs): + x = bcrypt(password, cost, salt=_bcrypt_decode(salt64)) + self.assertEqual(x, result) + bcrypt_check(password, result) + + def test_non_ascii_characters(self): + # password, cost, salt, bcrypt hash + tvs = [ + ("àèìòùÀÈÌÒÙáéíóúýÁÉÍÓÚÝðÐ", 4, b"D3qS2aoTVyqM7z8v8crLm.", b"$2a$04$D3qS2aoTVyqM7z8v8crLm.3nKt4CzBZJbyFB.ZebmfCvRw7BGs.Xm"), + ("àèìòùÀÈÌÒÙáéíóúýÁÉÍÓÚÝðÐ", 5, b"VA1FujiOCMPkUHQ8kF7IaO", b"$2a$05$VA1FujiOCMPkUHQ8kF7IaOg7NGaNvpxwWzSluQutxEVmbZItRTsAa"), + ("àèìòùÀÈÌÒÙáéíóúýÁÉÍÓÚÝðÐ", 6, b"TXiaNrPeBSz5ugiQlehRt.", b"$2a$06$TXiaNrPeBSz5ugiQlehRt.gwpeDQnXWteQL4z2FulouBr6G7D9KUi"), + ("âêîôûÂÊÎÔÛãñõÃÑÕäëïöüÿ", 4, b"YTn1Qlvps8e1odqMn6G5x.", b"$2a$04$YTn1Qlvps8e1odqMn6G5x.85pqKql6w773EZJAExk7/BatYAI4tyO"), + ("âêîôûÂÊÎÔÛãñõÃÑÕäëïöüÿ", 5, b"C.8k5vJKD2NtfrRI9o17DO", b"$2a$05$C.8k5vJKD2NtfrRI9o17DOfIW0XnwItA529vJnh2jzYTb1QdoY0py"), + ("âêîôûÂÊÎÔÛãñõÃÑÕäëïöüÿ", 6, b"xqfRPj3RYAgwurrhcA6uRO", b"$2a$06$xqfRPj3RYAgwurrhcA6uROtGlXDp/U6/gkoDYHwlubtcVcNft5.vW"), + ("ÄËÏÖÜŸåÅæÆœŒßçÇøØ¢¿¡€", 4, b"y8vGgMmr9EdyxP9rmMKjH.", b"$2a$04$y8vGgMmr9EdyxP9rmMKjH.wv2y3r7yRD79gykQtmb3N3zrwjKsyay"), + ("ÄËÏÖÜŸåÅæÆœŒßçÇøØ¢¿¡€", 5, b"iYH4XIKAOOm/xPQs7xKP1u", b"$2a$05$iYH4XIKAOOm/xPQs7xKP1upD0cWyMn3Jf0ZWiizXbEkVpS41K1dcO"), + ("ÄËÏÖÜŸåÅæÆœŒßçÇøØ¢¿¡€", 6, b"wCOob.D0VV8twafNDB2ape", b"$2a$06$wCOob.D0VV8twafNDB2apegiGD5nqF6Y1e6K95q6Y.R8C4QGd265q"), + ("ΔημοσιεύθηκεστηνΕφημερίδατης", 4, b"E5SQtS6P4568MDXW7cyUp.", b"$2a$04$E5SQtS6P4568MDXW7cyUp.18wfDisKZBxifnPZjAI1d/KTYMfHPYO"), + ("АБбВвГгДдЕеЁёЖжЗзИиЙйКкЛлМмН", 4, b"03e26gQFHhQwRNf81/ww9.", b"$2a$04$03e26gQFHhQwRNf81/ww9.p1UbrNwxpzWjLuT.zpTLH4t/w5WhAhC"), + ("нОоПпРрСсТтУуФфХхЦцЧчШшЩщЪъЫыЬьЭэЮю", 4, b"PHNoJwpXCfe32nUtLv2Upu", b"$2a$04$PHNoJwpXCfe32nUtLv2UpuhJXOzd4k7IdFwnEpYwfJVCZ/f/.8Pje"), + ("電电電島岛島兔兔兎龜龟亀國国国區区区", 4, b"wU4/0i1TmNl2u.1jIwBX.u", b"$2a$04$wU4/0i1TmNl2u.1jIwBX.uZUaOL3Rc5ID7nlQRloQh6q5wwhV/zLW"), + ("诶比伊艾弗豆贝尔维吾艾尺开艾丝维贼德", 4, b"P4kreGLhCd26d4WIy7DJXu", b"$2a$04$P4kreGLhCd26d4WIy7DJXusPkhxLvBouzV6OXkL5EB0jux0osjsry"), + ] + + for (idx, (password, cost, salt64, result)) in enumerate(tvs): + x = bcrypt(password, cost, salt=_bcrypt_decode(salt64)) + self.assertEqual(x, result) + bcrypt_check(password, result) + + def test_special_case_salt(self): + # password, cost, salt, bcrypt hash + tvs = [ + ("-O_=*N!2JP", 4, b"......................", b"$2a$04$......................JjuKLOX9OOwo5PceZZXSkaLDvdmgb82"), + ("7B[$Q<4b>U", 5, b"......................", b"$2a$05$......................DRiedDQZRL3xq5A5FL8y7/6NM8a2Y5W"), + (">d5-I_8^.h", 6, b"......................", b"$2a$06$......................5Mq1Ng8jgDY.uHNU4h5p/x6BedzNH2W"), + (")V`/UM/]1t", 4, b".OC/.OC/.OC/.OC/.OC/.O", b"$2a$04$.OC/.OC/.OC/.OC/.OC/.OQIvKRDAam.Hm5/IaV/.hc7P8gwwIbmi"), + (":@t2.bWuH]", 5, b".OC/.OC/.OC/.OC/.OC/.O", b"$2a$05$.OC/.OC/.OC/.OC/.OC/.ONDbUvdOchUiKmQORX6BlkPofa/QxW9e"), + ("b(#KljF5s\"", 6, b".OC/.OC/.OC/.OC/.OC/.O", b"$2a$06$.OC/.OC/.OC/.OC/.OC/.OHfTd9e7svOu34vi1PCvOcAEq07ST7.K"), + ("@3YaJ^Xs]*", 4, b"eGA.eGA.eGA.eGA.eGA.e.", b"$2a$04$eGA.eGA.eGA.eGA.eGA.e.stcmvh.R70m.0jbfSFVxlONdj1iws0C"), + ("'\"5\\!k*C(p", 5, b"eGA.eGA.eGA.eGA.eGA.e.", b"$2a$05$eGA.eGA.eGA.eGA.eGA.e.vR37mVSbfdHwu.F0sNMvgn8oruQRghy"), + ("edEu7C?$'W", 6, b"eGA.eGA.eGA.eGA.eGA.e.", b"$2a$06$eGA.eGA.eGA.eGA.eGA.e.tSq0FN8MWHQXJXNFnHTPQKtA.n2a..G"), + ("N7dHmg\\PI^", 4, b"999999999999999999999u", b"$2a$04$999999999999999999999uCZfA/pLrlyngNDMq89r1uUk.bQ9icOu"), + ("\"eJuHh!)7*", 5, b"999999999999999999999u", b"$2a$05$999999999999999999999uj8Pfx.ufrJFAoWFLjapYBS5vVEQQ/hK"), + ("ZeDRJ:_tu:", 6, b"999999999999999999999u", b"$2a$06$999999999999999999999u6RB0P9UmbdbQgjoQFEJsrvrKe.BoU6q"), + ] + + for (idx, (password, cost, salt64, result)) in enumerate(tvs): + x = bcrypt(password, cost, salt=_bcrypt_decode(salt64)) + self.assertEqual(x, result) + bcrypt_check(password, result) + + +class TestVectorsHKDFWycheproof(unittest.TestCase): + + def __init__(self, wycheproof_warnings): + unittest.TestCase.__init__(self) + self._wycheproof_warnings = wycheproof_warnings + self._id = "None" + + def add_tests(self, filename): + + def filter_algo(root): + algo_name = root['algorithm'] + if algo_name == "HKDF-SHA-1": + return SHA1 + elif algo_name == "HKDF-SHA-256": + return SHA256 + elif algo_name == "HKDF-SHA-384": + return SHA384 + elif algo_name == "HKDF-SHA-512": + return SHA512 + else: + raise ValueError("Unknown algorithm " + algo_name) + + def filter_size(unit): + return int(unit['size']) + + result = load_test_vectors_wycheproof(("Protocol", "wycheproof"), + filename, + "Wycheproof HMAC (%s)" % filename, + root_tag={'hash_module': filter_algo}, + unit_tag={'size': filter_size}) + return result + + def setUp(self): + self.tv = [] + self.add_tests("hkdf_sha1_test.json") + self.add_tests("hkdf_sha256_test.json") + self.add_tests("hkdf_sha384_test.json") + self.add_tests("hkdf_sha512_test.json") + + def shortDescription(self): + return self._id + + def warn(self, tv): + if tv.warning and self._wycheproof_warnings: + import warnings + warnings.warn("Wycheproof warning: %s (%s)" % (self._id, tv.comment)) + + def test_verify(self, tv): + self._id = "Wycheproof HKDF Test #%d (%s, %s)" % (tv.id, tv.comment, tv.filename) + + try: + key = HKDF(tv.ikm, tv.size, tv.salt, tv.hash_module, 1, tv.info) + except ValueError: + assert not tv.valid + else: + if key != tv.okm: + assert not tv.valid + else: + assert tv.valid + self.warn(tv) + + def runTest(self): + for tv in self.tv: + self.test_verify(tv) + + +def load_hash_by_name(hash_name): + return __import__("Cryptodome.Hash." + hash_name, globals(), locals(), ["new"]) + + +class SP800_108_Counter_Tests(unittest.TestCase): + + def test_negative_zeroes(self): + def prf(s, x): + return HMAC.new(s, x, SHA256).digest() + + try: + _ = SP800_108_Counter(b'0' * 16, 1, prf, label=b'A\x00B') + except ValueError: + self.fail('SP800_108_Counter failed with zero in label') + self.assertRaises(ValueError, SP800_108_Counter, b'0' * 16, 1, prf, + context=b'A\x00B') + + def test_multiple_keys(self): + def prf(s, x): + return HMAC.new(s, x, SHA256).digest() + + key = b'0' * 16 + expected = SP800_108_Counter(key, 2*3*23, prf) + for r in (1, 2, 3, 23): + dks = SP800_108_Counter(key, r, prf, 138//r) + self.assertEqual(len(dks), 138//r) + self.assertEqual(len(dks[0]), r) + self.assertEqual(b''.join(dks), expected) + + +def add_tests_sp800_108_counter(cls): + + test_vectors_sp800_108_counter = load_test_vectors(("Protocol", ), + "KDF_SP800_108_COUNTER.txt", + "NIST SP 800 108 KDF Counter Mode", + {'count': lambda x: int(x)}, + ) or [] + + mac_type = None + for idx, tv in enumerate(test_vectors_sp800_108_counter): + + if isinstance(tv, str): + res = re.match(r"\[HMAC-(SHA-[0-9]+)\]", tv) + if res: + hash_name = res.group(1).replace("-", "") + hash_module = load_hash_by_name(hash_name) + mac_type = "hmac" + continue + res = re.match(r"\[CMAC-AES-128\]", tv) + if res: + mac_type = "cmac" + continue + assert res + + if mac_type == "hmac": + def prf(s, x, hash_module=hash_module): + return HMAC.new(s, x, hash_module).digest() + elif mac_type == "cmac": + def prf(s, x, hash_module=hash_module): + return CMAC.new(s, x, AES).digest() + continue + + def kdf_test(self, prf=prf, kin=tv.kin, label=tv.label, + context=tv.context, kout=tv.kout, count=tv.count): + result = SP800_108_Counter(kin, len(kout), prf, 1, label, context) + assert(len(result) == len(kout)) + self.assertEqual(result, kout) + + setattr(cls, "test_kdf_sp800_108_counter_%d" % idx, kdf_test) + + +add_tests_sp800_108_counter(SP800_108_Counter_Tests) + + +def get_tests(config={}): + wycheproof_warnings = config.get('wycheproof_warnings') + + if not config.get('slow_tests'): + PBKDF2_Tests._testData = PBKDF2_Tests._testData[:3] + scrypt_Tests.data = scrypt_Tests.data[:3] + + tests = [] + tests += list_test_cases(PBKDF1_Tests) + tests += list_test_cases(PBKDF2_Tests) + tests += list_test_cases(S2V_Tests) + tests += list_test_cases(HKDF_Tests) + tests += [TestVectorsHKDFWycheproof(wycheproof_warnings)] + tests += list_test_cases(scrypt_Tests) + tests += list_test_cases(bcrypt_Tests) + tests += list_test_cases(SP800_108_Counter_Tests) + + return tests + + +if __name__ == '__main__': + suite = lambda: unittest.TestSuite(get_tests()) + unittest.main(defaultTest='suite') diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Protocol/test_SecretSharing.py b/venv/Lib/site-packages/Cryptodome/SelfTest/Protocol/test_SecretSharing.py new file mode 100644 index 0000000..afcbb23 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/SelfTest/Protocol/test_SecretSharing.py @@ -0,0 +1,290 @@ +# +# SelfTest/Protocol/test_secret_sharing.py: Self-test for secret sharing protocols +# +# =================================================================== +# +# Copyright (c) 2014, Legrandin +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# =================================================================== + +from unittest import main, TestCase, TestSuite +from binascii import unhexlify, hexlify + +from Cryptodome.Util.py3compat import * +from Cryptodome.Hash import SHAKE128 +from Cryptodome.SelfTest.st_common import list_test_cases + +from Cryptodome.Protocol.SecretSharing import Shamir, _Element, \ + _mult_gf2, _div_gf2 + + +class GF2_Tests(TestCase): + + def test_mult_gf2(self): + # Prove mult by zero + x = _mult_gf2(0,0) + self.assertEqual(x, 0) + + # Prove mult by unity + x = _mult_gf2(34, 1) + self.assertEqual(x, 34) + + z = 3 # (x+1) + y = _mult_gf2(z, z) + self.assertEqual(y, 5) # (x+1)^2 = x^2 + 1 + y = _mult_gf2(y, z) + self.assertEqual(y, 15) # (x+1)^3 = x^3 + x^2 + x + 1 + y = _mult_gf2(y, z) + self.assertEqual(y, 17) # (x+1)^4 = x^4 + 1 + + # Prove linearity works + comps = [1, 4, 128, 2**34] + sum_comps = 1+4+128+2**34 + y = 908 + z = _mult_gf2(sum_comps, y) + w = 0 + for x in comps: + w ^= _mult_gf2(x, y) + self.assertEqual(w, z) + + def test_div_gf2(self): + from Cryptodome.Util.number import size as deg + + x, y = _div_gf2(567, 7) + self.assertTrue(deg(y) < deg(7)) + + w = _mult_gf2(x, 7) ^ y + self.assertEqual(567, w) + + x, y = _div_gf2(7, 567) + self.assertEqual(x, 0) + self.assertEqual(y, 7) + +class Element_Tests(TestCase): + + def test1(self): + # Test encondings + e = _Element(256) + self.assertEqual(int(e), 256) + self.assertEqual(e.encode(), bchr(0)*14 + b("\x01\x00")) + + e = _Element(bchr(0)*14 + b("\x01\x10")) + self.assertEqual(int(e), 0x110) + self.assertEqual(e.encode(), bchr(0)*14 + b("\x01\x10")) + + # Only 16 byte string are a valid encoding + self.assertRaises(ValueError, _Element, bchr(0)) + + def test2(self): + # Test addition + e = _Element(0x10) + f = _Element(0x0A) + self.assertEqual(int(e+f), 0x1A) + + def test3(self): + # Test multiplication + zero = _Element(0) + one = _Element(1) + two = _Element(2) + + x = _Element(6) * zero + self.assertEqual(int(x), 0) + + x = _Element(6) * one + self.assertEqual(int(x), 6) + + x = _Element(2**127) * two + self.assertEqual(int(x), 1 + 2 + 4 + 128) + + def test4(self): + # Test inversion + one = _Element(1) + + x = one.inverse() + self.assertEqual(int(x), 1) + + x = _Element(82323923) + y = x.inverse() + self.assertEqual(int(x * y), 1) + + +class Shamir_Tests(TestCase): + + def test1(self): + # Test splitting + shares = Shamir.split(2, 3, bchr(90)*16) + self.assertEqual(len(shares), 3) + for index in range(3): + self.assertEqual(shares[index][0], index+1) + self.assertEqual(len(shares[index][1]), 16) + + def test2(self): + # Test recombine + from itertools import permutations + + # Generated by ssss (index, secret, shares) + # in hex mode, without "diffusion" mode + test_vectors = ( + (2, "d9fe73909bae28b3757854c0af7ad405", + "1-594ae8964294174d95c33756d2504170", + "2-d897459d29da574eb40e93ec552ffe6e", + "3-5823de9bf0e068b054b5f07a28056b1b", + "4-db2c1f8bff46d748f795da995bd080cb"), + (2, "bf4f902d9a7efafd1f3ffd9291fd5de9", + "1-557bd3b0748064b533469722d1cc7935", + "2-6b2717164783c66d47cd28f2119f14d0", + "3-8113548ba97d58256bb4424251ae300c", + "4-179e9e5a218483ddaeda57539139cf04"), + (3, "ec96aa5c14c9faa699354cf1da74e904", + "1-64579fbf1908d66f7239bf6e2b4e41e1", + "2-6cd9428df8017b52322561e8c672ae3e", + "3-e418776ef5c0579bd9299277374806dd", + "4-ab3f77a0107398d23b323e581bb43f5d", + "5-23fe42431db2b41bd03ecdc7ea8e97ac"), + (3, "44cf249b68b80fcdc27b47be60c2c145", + "1-d6515a3905cd755119b86e311c801e31", + "2-16693d9ac9f10c254036ced5f8917fa3", + "3-84f74338a48476b99bf5e75a84d3a0d1", + "4-3fe8878dc4a5d35811cf3cbcd33dbe52", + "5-ad76f92fa9d0a9c4ca0c1533af7f6132"), + (5, "5398717c982db935d968eebe53a47f5a", + "1-be7be2dd4c068e7ef576aaa1b1c11b01", + "2-f821f5848441cb98b3eb467e2733ee21", + "3-25ee52f53e203f6e29a0297b5ab486b5", + "4-fc9fb58ef74dab947fbf9acd9d5d83cd", + "5-b1949cce46d81552e65f248d3f74cc5c", + "6-d64797f59977c4d4a7956ad916da7699", + "7-ab608a6546a8b9af8820ff832b1135c7"), + (5, "4a78db90fbf35da5545d2fb728e87596", + "1-08daf9a25d8aa184cfbf02b30a0ed6a0", + "2-dda28261e36f0b14168c2cf153fb734e", + "3-e9fdec5505d674a57f9836c417c1ecaa", + "4-4dce5636ae06dee42d2c82e65f06c735", + "5-3963dc118afc2ba798fa1d452b28ef00", + "6-6dfe6ff5b09e94d2f84c382b12f42424", + "7-6faea9d4d4a4e201bf6c90b9000630c3"), + (10, "eccbf6d66d680b49b073c4f1ddf804aa", + "01-7d8ac32fe4ae209ead1f3220fda34466", + "02-f9144e76988aad647d2e61353a6e96d5", + "03-b14c3b80179203363922d60760271c98", + "04-770bb2a8c28f6cee89e00f4d5cc7f861", + "05-6e3d7073ea368334ef67467871c66799", + "06-248792bc74a98ce024477c13c8fb5f8d", + "07-fcea4640d2db820c0604851e293d2487", + "08-2776c36fb714bb1f8525a0be36fc7dba", + "09-6ee7ac8be773e473a4bf75ee5f065762", + "10-33657fc073354cf91d4a68c735aacfc8", + "11-7645c65094a5868bf225c516fdee2d0c", + "12-840485aacb8226631ecd9c70e3018086"), + (10, "377e63bdbb5f7d4dc58a483d035212bb", + "01-32c53260103be431c843b1a633afe3bd", + "02-0107eb16cb8695084d452d2cc50bc7d6", + "03-df1e5c66cd755287fb0446faccd72a06", + "04-361bbcd5d40797f49dfa1898652da197", + "05-160d3ad1512f7dec7fd9344aed318591", + "06-659af6d95df4f25beca4fb9bfee3b7e8", + "07-37f3b208977bad50b3724566b72bfa9d", + "08-6c1de2dfc69c2986142c26a8248eb316", + "09-5e19220837a396bd4bc8cd685ff314c3", + "10-86e7b864fb0f3d628e46d50c1ba92f1c", + "11-065d0082c80b1aea18f4abe0c49df72e", + "12-84a09430c1d20ea9f388f3123c3733a3"), + ) + + def get_share(p): + pos = p.find('-') + return int(p[:pos]), unhexlify(p[pos + 1:]) + + for tv in test_vectors: + k = tv[0] + secret = unhexlify(tv[1]) + max_perms = 10 + for perm, shares_idx in enumerate(permutations(range(2, len(tv)), k)): + if perm > max_perms: + break + shares = [ get_share(tv[x]) for x in shares_idx ] + result = Shamir.combine(shares, True) + self.assertEqual(secret, result) + + def test3(self): + # Loopback split/recombine + + rng = SHAKE128.new(b"test3") + + for _ in range(100): + + secret = rng.read(16) + + shares = Shamir.split(2, 3, secret) + + secret2 = Shamir.combine(shares[:2]) + self.assertEqual(secret, secret2) + + secret3 = Shamir.combine([ shares[0], shares[2] ]) + self.assertEqual(secret, secret3) + + def test4(self): + # Loopback split/recombine (SSSS) + + rng = SHAKE128.new(b"test4") + + for _ in range(10): + secret = rng.read(16) + + shares = Shamir.split(2, 3, secret, ssss=True) + + secret2 = Shamir.combine(shares[:2], ssss=True) + self.assertEqual(secret, secret2) + + for _ in range(10): + secret = rng.read(16) + + shares = Shamir.split(3, 7, secret, ssss=True) + + secret2 = Shamir.combine([shares[3], shares[4], shares[6]], ssss=True) + self.assertEqual(secret, secret2) + + + def test5(self): + # Detect duplicate shares + secret = unhexlify(b("000102030405060708090a0b0c0d0e0f")) + + shares = Shamir.split(2, 3, secret) + self.assertRaises(ValueError, Shamir.combine, (shares[0], shares[0])) + + +def get_tests(config={}): + tests = [] + tests += list_test_cases(GF2_Tests) + tests += list_test_cases(Element_Tests) + tests += list_test_cases(Shamir_Tests) + return tests + +if __name__ == '__main__': + suite = lambda: TestSuite(get_tests()) + main(defaultTest='suite') + diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Protocol/test_ecdh.py b/venv/Lib/site-packages/Cryptodome/SelfTest/Protocol/test_ecdh.py new file mode 100644 index 0000000..8bea787 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/SelfTest/Protocol/test_ecdh.py @@ -0,0 +1,770 @@ +import re +import base64 +import unittest +from binascii import hexlify, unhexlify + +from Cryptodome.Util.py3compat import bord + +from Cryptodome.Hash import SHA256 +from Cryptodome.PublicKey import ECC +from Cryptodome.SelfTest.st_common import list_test_cases +from Cryptodome.SelfTest.loader import load_test_vectors, load_test_vectors_wycheproof + +from Cryptodome.Protocol import DH +from Cryptodome.Protocol.DH import (key_agreement, + import_x25519_public_key, + import_x25519_private_key, + import_x448_public_key, + import_x448_private_key) + + +class FIPS_ECDH_Tests_KAT(unittest.TestCase): + pass + + +test_vectors_verify = load_test_vectors(("Protocol", ), + "KAS_ECC_CDH_PrimitiveTest.txt", + "ECC CDH Primitive (SP800-56A Section 5.7.1.2)", + { + 'qcavsx': lambda x: int(x, 16), + 'qcavsy': lambda x: int(x, 16), + 'diut': lambda x: int(x, 16), + 'qiutx': lambda x: int(x, 16), + 'qiuty': lambda x: int(x, 16), + }) or [] + +for idx, tv in enumerate(test_vectors_verify): + + # Stand-alone header with curve name + if isinstance(tv, str): + res = re.match(r"\[([A-Za-z0-9-]+)\]", tv) + assert res + curve_name = res.group(1) + continue + + public_key = ECC.construct(curve=curve_name, + point_x=tv.qcavsx, + point_y=tv.qcavsy) + + private_key = ECC.construct(curve=curve_name, + d=tv.diut) + + exp_response = tv.ziut + + def ecdh_test(self, + public_key=public_key, + private_key=private_key, + exp_response=exp_response): + z = key_agreement( + static_pub=public_key, + static_priv=private_key, + kdf=lambda x: x) + self.assertEqual(z, exp_response) + + def ecdh_test_rev(self, + public_key=public_key, + private_key=private_key, + exp_response=exp_response): + z = key_agreement( + static_pub=public_key, + static_priv=private_key, + kdf=lambda x: x) + self.assertEqual(z, exp_response) + + setattr(FIPS_ECDH_Tests_KAT, "test_verify_positive_%d" % idx, ecdh_test) + if idx == 1: + setattr(FIPS_ECDH_Tests_KAT, "test_verify_positive_rev_%d" % idx, ecdh_test_rev) + + +class TestVectorsECDHWycheproof(unittest.TestCase): + + desc = "Wycheproof ECDH tests" + + def add_tests(self, filename): + + def curve(g): + return g['curve'] + + def private(u): + return int(u['private'], 16) + + result = load_test_vectors_wycheproof(("Protocol", "wycheproof"), + filename, + "Wycheproof ECDH (%s)" + % filename, + group_tag={'curve': curve}, + unit_tag={'private': private}, + ) + self.tv += result + + def setUp(self): + self.tv = [] + self.desc = None + + self.add_tests("ecdh_secp224r1_ecpoint_test.json") + self.add_tests("ecdh_secp256r1_ecpoint_test.json") + self.add_tests("ecdh_secp384r1_ecpoint_test.json") + self.add_tests("ecdh_secp521r1_ecpoint_test.json") + + self.add_tests("ecdh_secp224r1_test.json") + self.add_tests("ecdh_secp256r1_test.json") + self.add_tests("ecdh_secp384r1_test.json") + self.add_tests("ecdh_secp521r1_test.json") + + def shortDescription(self): + return self.desc + + def test_verify(self, tv): + + if len(tv.public) == 0: + return + + try: + if bord(tv.public[0]) == 4: # SEC1 + public_key = ECC.import_key(tv.public, curve_name=tv.curve) + else: + public_key = ECC.import_key(tv.public) + except ValueError: + assert tv.warning or not tv.valid + return + + private_key = ECC.construct(curve=tv.curve, d=tv.private) + + try: + z = key_agreement(static_pub=public_key, + static_priv=private_key, + kdf=lambda x: x) + except ValueError: + assert not tv.valid + except TypeError as e: + assert not tv.valid + assert "incompatible curve" in str(e) + else: + self.assertEqual(z, tv.shared) + assert tv.valid + + def runTest(self): + for tv in self.tv: + self.desc = "Wycheproof ECDH Verify Test #%d (%s, %s)" % (tv.id, tv.comment, tv.filename) + self.test_verify(tv) + + +class ECDH_Tests(unittest.TestCase): + + static_priv = ECC.import_key('-----BEGIN PRIVATE KEY-----\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg9VHFVKh2a1aVFifH\n+BiyNaRa2kttEg3165Ye/dJxJ7KhRANCAARImIEXro5ZOcyWU2mq/+d79FEZXtTA\nbKkz1aICQXihQdCMzRNbeNtC9LFLzhu1slRKJ2xsDAlw9r6w6vwtkRzr\n-----END PRIVATE KEY-----') + static_pub = ECC.import_key('-----BEGIN PRIVATE KEY-----\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgHhmv8zmZ+Nw8fsZd\ns8tlZflyfw2NE1CRS9DWr3Y3O46hRANCAAS3hZVUCbk+uk3w4S/YOraEVGG+WYpk\nNO/vrwzufUUks2GV2OnBQESe0EBk4Jq8gn4ij8Lvs3rZX2yT+XfeATYd\n-----END PRIVATE KEY-----').public_key() + + eph_priv = ECC.import_key('-----BEGIN PRIVATE KEY-----\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgGPdJmFFFKzLPspIr\nE1T2cEjeIf4ajS9CpneP0e2b3AyhRANCAAQBexAA5BYDcXHs2KOksTYUsst4HhPt\nkp0zkgI2virc3OGJFNGPaCCPfFCQJHwLRaEpiq3SoQlgoBwSc8ZPsl3y\n-----END PRIVATE KEY-----') + + eph_pub = ECC.import_key('-----BEGIN PRIVATE KEY-----\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQghaVZXElSEGEojFKF\nOU0JCpxWUWHvWQUR81gwWrOp76ShRANCAATi1Ib2K+YR3AckD8wxypWef7pw5PRw\ntBaB3RDPyE7IjHZC6yu1DbcXoCdtaw+F5DM+4zpl59n5ZaIy/Yl1BdIy\n-----END PRIVATE KEY-----') + + def test_1(self): + # C(0, 2s) + kdf = lambda x: SHA256.new(x).digest() + z = key_agreement( + kdf=kdf, + static_pub=self.static_pub, + static_priv=self.static_priv) + self.assertEqual(hexlify(z), + b"3960a1101d1193cbaffef4cc7202ebff783c22c6d2e0d5d530ffc66dc197ea9c") + + def test_2(self): + # C(2e, 2s) + kdf = lambda x: SHA256.new(x).digest() + z = key_agreement( + kdf=kdf, + static_pub=self.static_pub, + static_priv=self.static_priv, + eph_pub=self.eph_pub, + eph_priv=self.eph_priv) + self.assertEqual(hexlify(z), + b"7447b733d40c8fab2c633b3dc61e4a8c742f3a6af7e16fb0cc486f5bdb5d6ba2") + + def test_3(self): + # C(1e, 2s) + kdf = lambda x: SHA256.new(x).digest() + z = key_agreement( + kdf=kdf, + static_pub=self.static_pub, + static_priv=self.static_priv, + eph_priv=self.eph_priv) + self.assertEqual(hexlify(z), + b"9e977ae45f33bf67f285d064d83e6632bcafe3a7d33fe571233bab4794ace759") + + def test_4(self): + # C(1e, 2s) + kdf = lambda x: SHA256.new(x).digest() + z = key_agreement( + kdf=kdf, + static_pub=self.static_pub, + static_priv=self.static_priv, + eph_pub=self.eph_pub) + self.assertEqual(hexlify(z), + b"c9532df6aa7e9dbe5fe85da31ee25ff19c179c88691ec4b8328cc2036dcdadf2") + + def test_5(self): + # C(2e, 1s) is not supported + kdf = lambda x: SHA256.new(x).digest() + self.assertRaises(ValueError, + key_agreement, + kdf=kdf, + static_priv=self.static_priv, + eph_pub=self.eph_pub, + eph_priv=self.eph_priv) + + def test_6(self): + # C(2e, 1s) is not supported + kdf = lambda x: SHA256.new(x).digest() + self.assertRaises(ValueError, + key_agreement, + kdf=kdf, + static_pub=self.static_pub, + eph_pub=self.eph_pub, + eph_priv=self.eph_priv) + + def test_7(self): + # C(2e, 0) + kdf = lambda x: SHA256.new(x).digest() + z = key_agreement( + kdf=kdf, + eph_pub=self.eph_pub, + eph_priv=self.eph_priv) + self.assertEqual(hexlify(z), + b"feb257ebe063078b1391aac07913283d7b642ad7df61b46dfc9cd6f420bb896a") + + def test_8(self): + # C(1e, 1s) + kdf = lambda x: SHA256.new(x).digest() + z = key_agreement( + kdf=kdf, + static_priv=self.static_priv, + eph_pub=self.eph_pub) + self.assertEqual(hexlify(z), + b"ee4dc995117476ed57fd17ff0ed44e9f0466d46b929443bc0db9380317583b04") + + def test_9(self): + # C(1e, 1s) + kdf = lambda x: SHA256.new(x).digest() + z = key_agreement( + kdf=kdf, + static_pub=self.static_pub, + eph_priv=self.eph_priv) + self.assertEqual(hexlify(z), + b"2351cc2014f7c40468fa072b5d30f706eeaeef7507311cd8e59bab3b43f03c51") + + def test_10(self): + # No private (local) keys + kdf = lambda x: SHA256.new(x).digest() + self.assertRaises(ValueError, + key_agreement, + kdf=kdf, + static_pub=self.static_pub, + eph_pub=self.eph_pub) + + def test_11(self): + # No public (peer) keys + kdf = lambda x: SHA256.new(x).digest() + self.assertRaises(ValueError, + key_agreement, + kdf=kdf, + static_priv=self.static_priv, + eph_priv=self.eph_priv) + + def test_12(self): + # failure if kdf is missing + self.assertRaises(ValueError, + key_agreement, + static_pub=self.static_pub, + static_priv=self.static_priv) + + +class X25519_Tests(unittest.TestCase): + + def test_rfc7748_1(self): + tvs = ( + ("a546e36bf0527c9d3b16154b82465edd62144c0ac1fc5a18506a2244ba449ac4", + "e6db6867583030db3594c1a424b15f7c726624ec26b3353b10a903a6d0ab1c4c", + "c3da55379de9c6908e94ea4df28d084f32eccf03491c71f754b4075577a28552"), + ("4b66e9d4d1b4673c5ad22691957d6af5c11b6421e0ea01d42ca4169e7918ba0d", + "e5210f12786811d3f4b7959d0538ae2c31dbe7106fc03c3efc4cd549c715a493", + "95cbde9476e8907d7aade45cb4b873f88b595a68799fa152e6f8f7647aac7957"), + ) + + for tv1, tv2, tv3 in tvs: + priv_key = DH.import_x25519_private_key(unhexlify(tv1)) + pub_key = DH.import_x25519_public_key(unhexlify(tv2)) + result = key_agreement(static_pub=pub_key, + static_priv=priv_key, + kdf=lambda x: x) + self.assertEqual(result, unhexlify(tv3)) + + def test_rfc7748_2(self): + k = unhexlify("0900000000000000000000000000000000000000000000000000000000000000") + + priv_key = DH.import_x25519_private_key(k) + pub_key = DH.import_x25519_public_key(k) + result = key_agreement(static_pub=pub_key, + static_priv=priv_key, + kdf=lambda x: x) + self.assertEqual( + result, + unhexlify("422c8e7a6227d7bca1350b3e2bb7279f7897b87bb6854b783c60e80311ae3079") + ) + + for _ in range(999): + priv_key = DH.import_x25519_private_key(result) + pub_key = DH.import_x25519_public_key(k) + k = result + result = key_agreement(static_pub=pub_key, + static_priv=priv_key, + kdf=lambda x: x) + + self.assertEqual( + result, + unhexlify("684cf59ba83309552800ef566f2f4d3c1c3887c49360e3875f2eb94d99532c51") + ) + + def test_rfc7748_3(self): + tv1 = "77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a" + tv2 = "8520f0098930a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98eaa9b4e6a" + tv3 = "5dab087e624a8a4b79e17f8b83800ee66f3bb1292618b6fd1c2f8b27ff88e0eb" + tv4 = "de9edb7d7b7dc1b4d35b61c2ece435373f8343c85b78674dadfc7e146f882b4f" + tv5 = "4a5d9d5ba4ce2de1728e3bf480350f25e07e21c947d19e3376f09b3c1e161742" + + alice_priv_key = DH.import_x25519_private_key(unhexlify(tv1)) + alice_pub_key = DH.import_x25519_public_key(unhexlify(tv2)) + bob_priv_key = DH.import_x25519_private_key(unhexlify(tv3)) + bob_pub_key = DH.import_x25519_public_key(unhexlify(tv4)) + secret = unhexlify(tv5) + + result1 = key_agreement(static_pub=alice_pub_key, + static_priv=bob_priv_key, + kdf=lambda x: x) + result2 = key_agreement(static_pub=bob_pub_key, + static_priv=alice_priv_key, + kdf=lambda x: x) + self.assertEqual(result1, secret) + self.assertEqual(result2, secret) + + def test_weak(self): + + weak_keys = ( + "0000000000000000000000000000000000000000000000000000000000000000", + "0100000000000000000000000000000000000000000000000000000000000000", + "e0eb7a7c3b41b8ae1656e3faf19fc46ada098deb9c32b1fd866205165f49b800", + "5f9c95bca3508c24b1d0b1559c83ef5b04445cc4581c8e86d8224eddd09f1157", + "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + # The implementation will accept these value, but only because + # it will set the MSB to zero (as required by RFC7748, Section 5), + # therefore leading to another public key (and to a point which is + # not of low order anymore). + # "cdeb7a7c3b41b8ae1656e3faf19fc46ada098deb9c32b1fd866205165f49b880", + # "4c9c95bca3508c24b1d0b1559c83ef5b04445cc4581c8e86d8224eddd09f11d7", + # "d9ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + # "daffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + # "dbffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + ) + + for x in weak_keys: + self.assertRaises(ValueError, + DH.import_x25519_public_key, + unhexlify(x)) + + +class X448_Tests(unittest.TestCase): + + def test_rfc7748_1(self): + tvs = ( + ("3d262fddf9ec8e88495266fea19a34d28882acef045104d0d1aae121700a779c984c24f8cdd78fbff44943eba368f54b29259a4f1c600ad3", + "06fce640fa3487bfda5f6cf2d5263f8aad88334cbd07437f020f08f9814dc031ddbdc38c19c6da2583fa5429db94ada18aa7a7fb4ef8a086", + "ce3e4ff95a60dc6697da1db1d85e6afbdf79b50a2412d7546d5f239fe14fbaadeb445fc66a01b0779d98223961111e21766282f73dd96b6f"), + ("203d494428b8399352665ddca42f9de8fef600908e0d461cb021f8c538345dd77c3e4806e25f46d3315c44e0a5b4371282dd2c8d5be3095f", + "0fbcc2f993cd56d3305b0b7d9e55d4c1a8fb5dbb52f8e9a1e9b6201b165d015894e56c4d3570bee52fe205e28a78b91cdfbde71ce8d157db", + "884a02576239ff7a2f2f63b2db6a9ff37047ac13568e1e30fe63c4a7ad1b3ee3a5700df34321d62077e63633c575c1c954514e99da7c179d"), + ) + + for tv1, tv2, tv3 in tvs: + priv_key = DH.import_x448_private_key(unhexlify(tv1)) + pub_key = DH.import_x448_public_key(unhexlify(tv2)) + result = key_agreement(static_pub=pub_key, + static_priv=priv_key, + kdf=lambda x: x) + self.assertEqual(result, unhexlify(tv3)) + + def test_rfc7748_2(self): + k = unhexlify("0500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000") + + priv_key = DH.import_x448_private_key(k) + pub_key = DH.import_x448_public_key(k) + result = key_agreement(static_pub=pub_key, + static_priv=priv_key, + kdf=lambda x: x) + self.assertEqual( + result, + unhexlify("3f482c8a9f19b01e6c46ee9711d9dc14fd4bf67af30765c2ae2b846a4d23a8cd0db897086239492caf350b51f833868b9bc2b3bca9cf4113") + ) + + for _ in range(999): + priv_key = DH.import_x448_private_key(result) + pub_key = DH.import_x448_public_key(k) + k = result + result = key_agreement(static_pub=pub_key, + static_priv=priv_key, + kdf=lambda x: x) + + self.assertEqual( + result, + unhexlify("aa3b4749d55b9daf1e5b00288826c467274ce3ebbdd5c17b975e09d4af6c67cf10d087202db88286e2b79fceea3ec353ef54faa26e219f38") + ) + + def test_rfc7748_3(self): + tv1 = "9a8f4925d1519f5775cf46b04b5800d4ee9ee8bae8bc5565d498c28dd9c9baf574a9419744897391006382a6f127ab1d9ac2d8c0a598726b" + tv2 = "9b08f7cc31b7e3e67d22d5aea121074a273bd2b83de09c63faa73d2c22c5d9bbc836647241d953d40c5b12da88120d53177f80e532c41fa0" + tv3 = "1c306a7ac2a0e2e0990b294470cba339e6453772b075811d8fad0d1d6927c120bb5ee8972b0d3e21374c9c921b09d1b0366f10b65173992d" + tv4 = "3eb7a829b0cd20f5bcfc0b599b6feccf6da4627107bdb0d4f345b43027d8b972fc3e34fb4232a13ca706dcb57aec3dae07bdc1c67bf33609" + tv5 = "07fff4181ac6cc95ec1c16a94a0f74d12da232ce40a77552281d282bb60c0b56fd2464c335543936521c24403085d59a449a5037514a879d" + + alice_priv_key = DH.import_x448_private_key(unhexlify(tv1)) + alice_pub_key = DH.import_x448_public_key(unhexlify(tv2)) + bob_priv_key = DH.import_x448_private_key(unhexlify(tv3)) + bob_pub_key = DH.import_x448_public_key(unhexlify(tv4)) + secret = unhexlify(tv5) + + result1 = key_agreement(static_pub=alice_pub_key, + static_priv=bob_priv_key, + kdf=lambda x: x) + result2 = key_agreement(static_pub=bob_pub_key, + static_priv=alice_priv_key, + kdf=lambda x: x) + self.assertEqual(result1, secret) + self.assertEqual(result2, secret) + + def test_weak(self): + + weak_keys = ( + "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "0100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "fefffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "00000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + ) + + for x in weak_keys: + self.assertRaises(ValueError, + DH.import_x448_public_key, + unhexlify(x)) + + +class TestVectorsX25519Wycheproof(unittest.TestCase): + + desc = "Wycheproof X25519 tests" + + def add_tests_hex(self, filename): + + def encoding(g): + return g['type'] + + def private(u): + return unhexlify(u['private']) + + result = load_test_vectors_wycheproof(("Protocol", "wycheproof"), + filename, + "Wycheproof ECDH (%s)" + % filename, + group_tag={'encoding': encoding}, + unit_tag={'private': private} + ) + self.tv += result + + def add_tests_ascii(self, filename): + + def encoding(g): + return g['type'] + + def public(u): + return u['public'] + + def private(u): + return u['private'] + + result = load_test_vectors_wycheproof(("Protocol", "wycheproof"), + filename, + "Wycheproof ECDH (%s)" + % filename, + group_tag={'encoding': encoding}, + unit_tag={'public': public, + 'private': private} + ) + self.tv += result + + def setUp(self): + self.tv = [] + self.desc = None + + self.add_tests_hex("x25519_test.json") + self.add_tests_hex("x25519_asn_test.json") + self.add_tests_ascii("x25519_pem_test.json") + self.add_tests_ascii("x25519_jwk_test.json") + + def shortDescription(self): + return self.desc + + def test_verify(self, tv): + + if tv.encoding == "XdhComp": + try: + public_key = import_x25519_public_key(tv.public) + except ValueError as e: + assert tv.valid + assert tv.warning + assert "LowOrderPublic" in tv.flags + assert "Invalid Curve25519" in str(e) + return + private_key = import_x25519_private_key(tv.private) + elif tv.encoding in ("XdhAsnComp", "XdhPemComp"): + try: + public_key = ECC.import_key(tv.public) + private_key = ECC.import_key(tv.private) + except ECC.UnsupportedEccFeature as e: + assert not tv.valid + assert "Unsupported ECC" in str(e) + return + except ValueError: + assert tv.valid + assert tv.warning + assert "LowOrderPublic" in tv.flags + return + elif tv.encoding == "XdhJwkComp": + + if 'y' in tv.public: + return + if 'x' not in tv.public: + return + if 'x' not in tv.private: + return + if tv.public.get('kty') != 'OKP': + return + if tv.public.get('crv') != 'X25519': + return + if tv.private.get('crv') != 'X25519': + return + + def base64url_decode(input_str): + input_str = input_str.replace('-', '+').replace('_', '/') + padding = 4 - (len(input_str) % 4) + if padding != 4: + input_str += '=' * padding + decoded_bytes = base64.b64decode(input_str) + return decoded_bytes + + jwk_public = base64url_decode(tv.public['x']) + jwk_private = base64url_decode(tv.private['d']) + + try: + public_key = import_x25519_public_key(jwk_public) + private_key = import_x25519_private_key(jwk_private) + except ValueError as e: + if tv.valid: + assert tv.warning + assert "LowOrderPublic" in tv.flags + assert "Invalid Curve25519" in str(e) + return + else: + assert "Incorrect length" in str(e) + return + except ValueError: + assert tv.valid + else: + raise ValueError("Unknown encoding", tv.encoding) + + try: + z = key_agreement(static_pub=public_key, + static_priv=private_key, + kdf=lambda x: x) + except ValueError: + assert not tv.valid + except TypeError as e: + assert not tv.valid + assert "incompatible curve" in str(e) + else: + self.assertEqual(z, tv.shared) + assert tv.valid + + def runTest(self): + for tv in self.tv: + self.desc = "Wycheproof XECDH Verify Test #%d (%s, %s)" % (tv.id, tv.comment, tv.filename) + self.test_verify(tv) + + +class TestVectorsX448Wycheproof(unittest.TestCase): + + desc = "Wycheproof X448 tests" + + def add_tests_hex(self, filename): + + def encoding(g): + return g['type'] + + def private(u): + return unhexlify(u['private']) + + result = load_test_vectors_wycheproof(("Protocol", "wycheproof"), + filename, + "Wycheproof ECDH (%s)" + % filename, + group_tag={'encoding': encoding}, + unit_tag={'private': private} + ) + self.tv += result + + def add_tests_ascii(self, filename): + + def encoding(g): + return g['type'] + + def public(u): + return u['public'] + + def private(u): + return u['private'] + + result = load_test_vectors_wycheproof(("Protocol", "wycheproof"), + filename, + "Wycheproof ECDH (%s)" + % filename, + group_tag={'encoding': encoding}, + unit_tag={'public': public, + 'private': private} + ) + self.tv += result + + def setUp(self): + self.tv = [] + self.desc = None + + self.add_tests_hex("x448_test.json") + self.add_tests_hex("x448_asn_test.json") + self.add_tests_ascii("x448_pem_test.json") + self.add_tests_ascii("x448_jwk_test.json") + + def shortDescription(self): + return self.desc + + def test_verify(self, tv): + + if tv.encoding == "XdhComp": + try: + public_key = import_x448_public_key(tv.public) + except ValueError as e: + assert tv.valid + assert tv.warning + if len(tv.public) == 56: + assert "LowOrderPublic" in tv.flags + assert "Invalid Curve448" in str(e) + else: + assert "Incorrect Curve448" in str(e) + return + private_key = import_x448_private_key(tv.private) + elif tv.encoding in ("XdhAsnComp", "XdhPemComp"): + try: + public_key = ECC.import_key(tv.public) + private_key = ECC.import_key(tv.private) + except ECC.UnsupportedEccFeature as e: + assert not tv.valid + assert "Unsupported ECC" in str(e) + return + except ValueError as e: + assert tv.valid + assert tv.warning + assert "LowOrderPublic" in tv.flags or "NonCanonicalPublic" in tv.flags + return + elif tv.encoding == "XdhJwkComp": + + if 'y' in tv.public: + return + if 'x' not in tv.public: + return + if 'x' not in tv.private: + return + if tv.public.get('kty') != 'OKP': + return + if tv.public.get('crv') != 'X448': + return + if tv.private.get('crv') != 'X448': + return + + def base64url_decode(input_str): + input_str = input_str.replace('-', '+').replace('_', '/') + padding = 4 - (len(input_str) % 4) + if padding != 4: + input_str += '=' * padding + decoded_bytes = base64.b64decode(input_str) + return decoded_bytes + + jwk_public = base64url_decode(tv.public['x']) + jwk_private = base64url_decode(tv.private['d']) + + try: + public_key = import_x448_public_key(jwk_public) + private_key = import_x448_private_key(jwk_private) + except ValueError as e: + if tv.valid: + assert tv.warning + if len(tv.public['x']) == 75: + assert "LowOrderPublic" in tv.flags or \ + "NonCanonicalPublic" in tv.flags + assert "Invalid Curve448" in str(e) + else: + assert "Incorrect Curve448" in str(e) + return + else: + assert "Incorrect length" in str(e) + return + except ValueError: + assert tv.valid + else: + raise ValueError("Unknown encoding", tv.encoding) + + try: + z = key_agreement(static_pub=public_key, + static_priv=private_key, + kdf=lambda x: x) + except ValueError: + assert not tv.valid + except TypeError as e: + assert not tv.valid + assert "incompatible curve" in str(e) + else: + self.assertEqual(z, tv.shared) + assert tv.valid + + def runTest(self): + for tv in self.tv: + self.desc = "Wycheproof XECDH Verify Test #%d (%s, %s)" % (tv.id, tv.comment, tv.filename) + self.test_verify(tv) + + +def get_tests(config={}): + + tests = [] + tests += list_test_cases(FIPS_ECDH_Tests_KAT) + tests += [TestVectorsECDHWycheproof()] + tests += list_test_cases(ECDH_Tests) + tests += list_test_cases(X25519_Tests) + tests += list_test_cases(X448_Tests) + tests += [TestVectorsX25519Wycheproof()] + tests += [TestVectorsX448Wycheproof()] + + slow_tests = config.get('slow_tests') + if slow_tests: + pass + + return tests + + +if __name__ == '__main__': + def suite(): + return unittest.TestSuite(get_tests()) + unittest.main(defaultTest='suite') diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Protocol/test_rfc1751.py b/venv/Lib/site-packages/Cryptodome/SelfTest/Protocol/test_rfc1751.py new file mode 100644 index 0000000..a79769c --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/SelfTest/Protocol/test_rfc1751.py @@ -0,0 +1,62 @@ +# +# Test script for Cryptodome.Util.RFC1751. +# +# Part of the Python Cryptography Toolkit +# +# Written by Andrew Kuchling and others +# +# =================================================================== +# The contents of this file are dedicated to the public domain. To +# the extent that dedication to the public domain is not available, +# everyone is granted a worldwide, perpetual, royalty-free, +# non-exclusive license to exercise all rights associated with the +# contents of this file for any purpose whatsoever. +# No rights are reserved. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# =================================================================== + +__revision__ = "$Id$" + +import binascii +import unittest +from Cryptodome.Util import RFC1751 +from Cryptodome.Util.py3compat import * + +test_data = [('EB33F77EE73D4053', 'TIDE ITCH SLOW REIN RULE MOT'), + ('CCAC2AED591056BE4F90FD441C534766', + 'RASH BUSH MILK LOOK BAD BRIM AVID GAFF BAIT ROT POD LOVE'), + ('EFF81F9BFBC65350920CDD7416DE8009', + 'TROD MUTE TAIL WARM CHAR KONG HAAG CITY BORE O TEAL AWL') + ] + +class RFC1751Test_k2e (unittest.TestCase): + + def runTest (self): + "Check converting keys to English" + for key, words in test_data: + key=binascii.a2b_hex(b(key)) + self.assertEqual(RFC1751.key_to_english(key), words) + +class RFC1751Test_e2k (unittest.TestCase): + + def runTest (self): + "Check converting English strings to keys" + for key, words in test_data: + key=binascii.a2b_hex(b(key)) + self.assertEqual(RFC1751.english_to_key(words), key) + +# class RFC1751Test + +def get_tests(config={}): + return [RFC1751Test_k2e(), RFC1751Test_e2k()] + +if __name__ == "__main__": + unittest.main() diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/PublicKey/__init__.py b/venv/Lib/site-packages/Cryptodome/SelfTest/PublicKey/__init__.py new file mode 100644 index 0000000..f16a6ff --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/SelfTest/PublicKey/__init__.py @@ -0,0 +1,63 @@ +# -*- coding: utf-8 -*- +# +# SelfTest/PublicKey/__init__.py: Self-test for public key crypto +# +# Written in 2008 by Dwayne C. Litzenberger +# +# =================================================================== +# The contents of this file are dedicated to the public domain. To +# the extent that dedication to the public domain is not available, +# everyone is granted a worldwide, perpetual, royalty-free, +# non-exclusive license to exercise all rights associated with the +# contents of this file for any purpose whatsoever. +# No rights are reserved. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# =================================================================== + +"""Self-test for public-key crypto""" + +import unittest +from Cryptodome.SelfTest.PublicKey import (test_DSA, test_RSA, + test_ECC_NIST, + test_ECC_Ed25519, + test_ECC_Curve25519, + test_ECC_Ed448, + test_ECC_Curve448, + test_import_DSA, test_import_RSA, + test_import_ECC, test_ElGamal, + test_import_Curve25519, + test_import_Curve448) + + +def get_tests(config={}): + tests = [] + tests += test_DSA.get_tests(config=config) + tests += test_RSA.get_tests(config=config) + tests += test_ECC_NIST.get_tests(config=config) + tests += test_ECC_Ed25519.get_tests(config=config) + tests += test_ECC_Curve25519.get_tests(config=config) + tests += test_ECC_Ed448.get_tests(config=config) + tests += test_ECC_Curve448.get_tests(config=config) + + tests += test_import_DSA.get_tests(config=config) + tests += test_import_RSA.get_tests(config=config) + tests += test_import_ECC.get_tests(config=config) + tests += test_import_Curve25519.get_tests(config=config) + tests += test_import_Curve448.get_tests(config=config) + + tests += test_ElGamal.get_tests(config=config) + return tests + + +if __name__ == '__main__': + def suite(): + return unittest.TestSuite(get_tests()) + unittest.main(defaultTest='suite') diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/PublicKey/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/SelfTest/PublicKey/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000..47a9ce2 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/SelfTest/PublicKey/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/PublicKey/__pycache__/test_DSA.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/SelfTest/PublicKey/__pycache__/test_DSA.cpython-312.pyc new file mode 100644 index 0000000..46205af Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/SelfTest/PublicKey/__pycache__/test_DSA.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/PublicKey/__pycache__/test_ECC_Curve25519.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/SelfTest/PublicKey/__pycache__/test_ECC_Curve25519.cpython-312.pyc new file mode 100644 index 0000000..6fdff75 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/SelfTest/PublicKey/__pycache__/test_ECC_Curve25519.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/PublicKey/__pycache__/test_ECC_Curve448.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/SelfTest/PublicKey/__pycache__/test_ECC_Curve448.cpython-312.pyc new file mode 100644 index 0000000..208edaf Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/SelfTest/PublicKey/__pycache__/test_ECC_Curve448.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/PublicKey/__pycache__/test_ECC_Ed25519.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/SelfTest/PublicKey/__pycache__/test_ECC_Ed25519.cpython-312.pyc new file mode 100644 index 0000000..86dd55f Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/SelfTest/PublicKey/__pycache__/test_ECC_Ed25519.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/PublicKey/__pycache__/test_ECC_Ed448.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/SelfTest/PublicKey/__pycache__/test_ECC_Ed448.cpython-312.pyc new file mode 100644 index 0000000..5358269 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/SelfTest/PublicKey/__pycache__/test_ECC_Ed448.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/PublicKey/__pycache__/test_ECC_NIST.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/SelfTest/PublicKey/__pycache__/test_ECC_NIST.cpython-312.pyc new file mode 100644 index 0000000..c38e5ab Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/SelfTest/PublicKey/__pycache__/test_ECC_NIST.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/PublicKey/__pycache__/test_ElGamal.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/SelfTest/PublicKey/__pycache__/test_ElGamal.cpython-312.pyc new file mode 100644 index 0000000..ac17aea Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/SelfTest/PublicKey/__pycache__/test_ElGamal.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/PublicKey/__pycache__/test_RSA.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/SelfTest/PublicKey/__pycache__/test_RSA.cpython-312.pyc new file mode 100644 index 0000000..5161444 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/SelfTest/PublicKey/__pycache__/test_RSA.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/PublicKey/__pycache__/test_import_Curve25519.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/SelfTest/PublicKey/__pycache__/test_import_Curve25519.cpython-312.pyc new file mode 100644 index 0000000..7544515 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/SelfTest/PublicKey/__pycache__/test_import_Curve25519.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/PublicKey/__pycache__/test_import_Curve448.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/SelfTest/PublicKey/__pycache__/test_import_Curve448.cpython-312.pyc new file mode 100644 index 0000000..73fe4f5 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/SelfTest/PublicKey/__pycache__/test_import_Curve448.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/PublicKey/__pycache__/test_import_DSA.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/SelfTest/PublicKey/__pycache__/test_import_DSA.cpython-312.pyc new file mode 100644 index 0000000..74b071c Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/SelfTest/PublicKey/__pycache__/test_import_DSA.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/PublicKey/__pycache__/test_import_ECC.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/SelfTest/PublicKey/__pycache__/test_import_ECC.cpython-312.pyc new file mode 100644 index 0000000..5928d3e Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/SelfTest/PublicKey/__pycache__/test_import_ECC.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/PublicKey/__pycache__/test_import_RSA.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/SelfTest/PublicKey/__pycache__/test_import_RSA.cpython-312.pyc new file mode 100644 index 0000000..6f44519 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/SelfTest/PublicKey/__pycache__/test_import_RSA.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/PublicKey/test_DSA.py b/venv/Lib/site-packages/Cryptodome/SelfTest/PublicKey/test_DSA.py new file mode 100644 index 0000000..160d882 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/SelfTest/PublicKey/test_DSA.py @@ -0,0 +1,247 @@ +# -*- coding: utf-8 -*- +# +# SelfTest/PublicKey/test_DSA.py: Self-test for the DSA primitive +# +# Written in 2008 by Dwayne C. Litzenberger +# +# =================================================================== +# The contents of this file are dedicated to the public domain. To +# the extent that dedication to the public domain is not available, +# everyone is granted a worldwide, perpetual, royalty-free, +# non-exclusive license to exercise all rights associated with the +# contents of this file for any purpose whatsoever. +# No rights are reserved. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# =================================================================== + +"""Self-test suite for Cryptodome.PublicKey.DSA""" + +import os +from Cryptodome.Util.py3compat import * + +import unittest +from Cryptodome.SelfTest.st_common import list_test_cases, a2b_hex, b2a_hex + +def _sws(s): + """Remove whitespace from a text or byte string""" + if isinstance(s,str): + return "".join(s.split()) + else: + return b("").join(s.split()) + +class DSATest(unittest.TestCase): + # Test vector from "Appendix 5. Example of the DSA" of + # "Digital Signature Standard (DSS)", + # U.S. Department of Commerce/National Institute of Standards and Technology + # FIPS 186-2 (+Change Notice), 2000 January 27. + # http://csrc.nist.gov/publications/fips/fips186-2/fips186-2-change1.pdf + + y = _sws("""19131871 d75b1612 a819f29d 78d1b0d7 346f7aa7 7bb62a85 + 9bfd6c56 75da9d21 2d3a36ef 1672ef66 0b8c7c25 5cc0ec74 + 858fba33 f44c0669 9630a76b 030ee333""") + + g = _sws("""626d0278 39ea0a13 413163a5 5b4cb500 299d5522 956cefcb + 3bff10f3 99ce2c2e 71cb9de5 fa24babf 58e5b795 21925c9c + c42e9f6f 464b088c c572af53 e6d78802""") + + p = _sws("""8df2a494 492276aa 3d25759b b06869cb eac0d83a fb8d0cf7 + cbb8324f 0d7882e5 d0762fc5 b7210eaf c2e9adac 32ab7aac + 49693dfb f83724c2 ec0736ee 31c80291""") + + q = _sws("""c773218c 737ec8ee 993b4f2d ed30f48e dace915f""") + + x = _sws("""2070b322 3dba372f de1c0ffc 7b2e3b49 8b260614""") + + k = _sws("""358dad57 1462710f 50e254cf 1a376b2b deaadfbf""") + k_inverse = _sws("""0d516729 8202e49b 4116ac10 4fc3f415 ae52f917""") + m = b2a_hex(b("abc")) + m_hash = _sws("""a9993e36 4706816a ba3e2571 7850c26c 9cd0d89d""") + r = _sws("""8bac1ab6 6410435c b7181f95 b16ab97c 92b341c0""") + s = _sws("""41e2345f 1f56df24 58f426d1 55b4ba2d b6dcd8c8""") + + def setUp(self): + global DSA, Random, bytes_to_long, size + from Cryptodome.PublicKey import DSA + from Cryptodome import Random + from Cryptodome.Util.number import bytes_to_long, inverse, size + + self.dsa = DSA + + def test_generate_1arg(self): + """DSA (default implementation) generated key (1 argument)""" + dsaObj = self.dsa.generate(1024) + self._check_private_key(dsaObj) + pub = dsaObj.public_key() + self._check_public_key(pub) + + def test_generate_2arg(self): + """DSA (default implementation) generated key (2 arguments)""" + dsaObj = self.dsa.generate(1024, Random.new().read) + self._check_private_key(dsaObj) + pub = dsaObj.public_key() + self._check_public_key(pub) + + def test_construct_4tuple(self): + """DSA (default implementation) constructed key (4-tuple)""" + (y, g, p, q) = [bytes_to_long(a2b_hex(param)) for param in (self.y, self.g, self.p, self.q)] + dsaObj = self.dsa.construct((y, g, p, q)) + self._test_verification(dsaObj) + + def test_construct_5tuple(self): + """DSA (default implementation) constructed key (5-tuple)""" + (y, g, p, q, x) = [bytes_to_long(a2b_hex(param)) for param in (self.y, self.g, self.p, self.q, self.x)] + dsaObj = self.dsa.construct((y, g, p, q, x)) + self._test_signing(dsaObj) + self._test_verification(dsaObj) + + def test_construct_bad_key4(self): + (y, g, p, q) = [bytes_to_long(a2b_hex(param)) for param in (self.y, self.g, self.p, self.q)] + tup = (y, g, p+1, q) + self.assertRaises(ValueError, self.dsa.construct, tup) + + tup = (y, g, p, q+1) + self.assertRaises(ValueError, self.dsa.construct, tup) + + tup = (y, 1, p, q) + self.assertRaises(ValueError, self.dsa.construct, tup) + + def test_construct_bad_key5(self): + (y, g, p, q, x) = [bytes_to_long(a2b_hex(param)) for param in (self.y, self.g, self.p, self.q, self.x)] + tup = (y, g, p, q, x+1) + self.assertRaises(ValueError, self.dsa.construct, tup) + + tup = (y, g, p, q, q+10) + self.assertRaises(ValueError, self.dsa.construct, tup) + + def _check_private_key(self, dsaObj): + # Check capabilities + self.assertEqual(1, dsaObj.has_private()) + self.assertEqual(1, dsaObj.can_sign()) + self.assertEqual(0, dsaObj.can_encrypt()) + + # Sanity check key data + self.assertEqual(1, dsaObj.p > dsaObj.q) # p > q + self.assertEqual(160, size(dsaObj.q)) # size(q) == 160 bits + self.assertEqual(0, (dsaObj.p - 1) % dsaObj.q) # q is a divisor of p-1 + self.assertEqual(dsaObj.y, pow(dsaObj.g, dsaObj.x, dsaObj.p)) # y == g**x mod p + self.assertEqual(1, 0 < dsaObj.x < dsaObj.q) # 0 < x < q + + def _check_public_key(self, dsaObj): + k = bytes_to_long(a2b_hex(self.k)) + m_hash = bytes_to_long(a2b_hex(self.m_hash)) + + # Check capabilities + self.assertEqual(0, dsaObj.has_private()) + self.assertEqual(1, dsaObj.can_sign()) + self.assertEqual(0, dsaObj.can_encrypt()) + + # Check that private parameters are all missing + self.assertEqual(0, hasattr(dsaObj, 'x')) + + # Sanity check key data + self.assertEqual(1, dsaObj.p > dsaObj.q) # p > q + self.assertEqual(160, size(dsaObj.q)) # size(q) == 160 bits + self.assertEqual(0, (dsaObj.p - 1) % dsaObj.q) # q is a divisor of p-1 + + # Public-only key objects should raise an error when .sign() is called + self.assertRaises(TypeError, dsaObj._sign, m_hash, k) + + # Check __eq__ and __ne__ + self.assertEqual(dsaObj.public_key() == dsaObj.public_key(),True) # assert_ + self.assertEqual(dsaObj.public_key() != dsaObj.public_key(),False) # assertFalse + + self.assertEqual(dsaObj.public_key(), dsaObj.publickey()) + + def _test_signing(self, dsaObj): + k = bytes_to_long(a2b_hex(self.k)) + m_hash = bytes_to_long(a2b_hex(self.m_hash)) + r = bytes_to_long(a2b_hex(self.r)) + s = bytes_to_long(a2b_hex(self.s)) + (r_out, s_out) = dsaObj._sign(m_hash, k) + self.assertEqual((r, s), (r_out, s_out)) + + def _test_verification(self, dsaObj): + m_hash = bytes_to_long(a2b_hex(self.m_hash)) + r = bytes_to_long(a2b_hex(self.r)) + s = bytes_to_long(a2b_hex(self.s)) + self.assertTrue(dsaObj._verify(m_hash, (r, s))) + self.assertFalse(dsaObj._verify(m_hash + 1, (r, s))) + + def test_repr(self): + (y, g, p, q) = [bytes_to_long(a2b_hex(param)) for param in (self.y, self.g, self.p, self.q)] + dsaObj = self.dsa.construct((y, g, p, q)) + repr(dsaObj) + + +class DSADomainTest(unittest.TestCase): + + def test_domain1(self): + """Verify we can generate new keys in a given domain""" + dsa_key_1 = DSA.generate(1024) + domain_params = dsa_key_1.domain() + + dsa_key_2 = DSA.generate(1024, domain=domain_params) + self.assertEqual(dsa_key_1.p, dsa_key_2.p) + self.assertEqual(dsa_key_1.q, dsa_key_2.q) + self.assertEqual(dsa_key_1.g, dsa_key_2.g) + + self.assertEqual(dsa_key_1.domain(), dsa_key_2.domain()) + + def _get_weak_domain(self): + + from Cryptodome.Math.Numbers import Integer + from Cryptodome.Math import Primality + + p = Integer(4) + while p.size_in_bits() != 1024 or Primality.test_probable_prime(p) != Primality.PROBABLY_PRIME: + q1 = Integer.random(exact_bits=80) + q2 = Integer.random(exact_bits=80) + q = q1 * q2 + z = Integer.random(exact_bits=1024-160) + p = z * q + 1 + + h = Integer(2) + g = 1 + while g == 1: + g = pow(h, z, p) + h += 1 + + return (p, q, g) + + + def test_generate_error_weak_domain(self): + """Verify that domain parameters with composite q are rejected""" + + domain_params = self._get_weak_domain() + self.assertRaises(ValueError, DSA.generate, 1024, domain=domain_params) + + + def test_construct_error_weak_domain(self): + """Verify that domain parameters with composite q are rejected""" + + from Cryptodome.Math.Numbers import Integer + + p, q, g = self._get_weak_domain() + y = pow(g, 89, p) + self.assertRaises(ValueError, DSA.construct, (y, g, p, q)) + + +def get_tests(config={}): + tests = [] + tests += list_test_cases(DSATest) + tests += list_test_cases(DSADomainTest) + return tests + +if __name__ == '__main__': + suite = lambda: unittest.TestSuite(get_tests()) + unittest.main(defaultTest='suite') + +# vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/PublicKey/test_ECC_Curve25519.py b/venv/Lib/site-packages/Cryptodome/SelfTest/PublicKey/test_ECC_Curve25519.py new file mode 100644 index 0000000..8defd00 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/SelfTest/PublicKey/test_ECC_Curve25519.py @@ -0,0 +1,283 @@ +# =================================================================== +# +# Copyright (c) 2024, Helder Eijs +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# =================================================================== + +import unittest +from binascii import unhexlify + +from Cryptodome.SelfTest.st_common import list_test_cases +from Cryptodome.Math.Numbers import Integer +from Cryptodome.Hash import SHAKE128 + +from Cryptodome.PublicKey import ECC +from Cryptodome.PublicKey.ECC import EccKey, EccXPoint, _curves + +# Test vectors for scalar multiplication using point with X=9 as base +# generated with nickovs' Python-only code https://gist.github.com/nickovs/cc3c22d15f239a2640c185035c06f8a3 +# The order is 0x1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3ed +# Each tuple is (exponent, X-coordinate) +scalar_base9_test = [ + (1, 9), + (2, 0x20d342d51873f1b7d9750c687d1571148f3f5ced1e350b5c5cae469cdd684efb), + (3, 0x1c12bc1a6d57abe645534d91c21bba64f8824e67621c0859c00a03affb713c12), + (4, 0x79ce98b7e0689d7de7d1d074a15b315ffe1805dfcd5d2a230fee85e4550013ef), + (6, 0x26954ccdc99ebf34f8f1dde5e6bb080685fec73640494c28f9fe0bfa8c794531), + (9, 0x192b929197d07748db44600da41bab7499b1c2e6e2f87c6f0e337980668164ba), + (129, 0x7332096a738900085e721103fce2cbf13aee50fef0788ea0d669008eb09ceab7), + (255, 0x1534582fc2b1cea45e8cb776547e209da4fd54a9e473b50c5b8c6b0ae023a9b3), + (256, 0x4300017536976a742ec8747f7505cd6bc80e610d669acab1a1eed36f680d98e8), + (257, 0x6c410611cb484c9016adfb884d37a0e682e075daca1d46f45bb7a4afed10b125), + (0x10101, 0xa679e9d7e043bf76c03362576e2c88abe9093c5d4f6b4a202c64a8397467cf), + (0xAA55CC, 0x2cc02f84c067e3586f4278326689be163e606d69ccae505bb09488e11f295887), + (0x1B29A0E579E0A000567, 0x50c38a72d7bfd7864c8b9083fa123e8d359068e6b491a019a885036e073f6604), + (0x1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3ed + 1, 9), +] + + +class TestEccPoint_Curve25519(unittest.TestCase): + + v1 = 0x09fa78b39b00a72930bcd8039be789a0997830bb99f79aeeb93493715390b4e8 + v2 = 0x15210f12786811d3f4b7959d0538ae2c31dbe7106fc03c3efc4cd549c715a493 + + def test_init(self): + EccXPoint(9, "curve25519") + EccXPoint(2**255 - 19 + 5, "curve25519") + + def test_curve_attribute(self): + point = EccXPoint(9, "curve25519") + self.assertEqual(point.curve, "Curve25519") + + def test_init_fail(self): + self.assertRaises(ValueError, EccXPoint, 3*(2**255 - 19), "curve25519") + self.assertRaises(ValueError, EccXPoint, 9, "curve25518") + + def test_equal_set(self): + point1 = EccXPoint(self.v1, "curve25519") + point2 = EccXPoint(self.v2, "curve25519") + + self.assertEqual(point1, point1) + self.assertNotEqual(point1, point2) + + point2.set(point1) + self.assertEqual(point1.x, point2.x) + + def test_copy(self): + point1 = EccXPoint(self.v1, "curve25519") + point2 = point1.copy() + self.assertEqual(point1.x, point2.x) + + def test_pai(self): + point1 = EccXPoint(self.v1, "curve25519") + pai = point1.point_at_infinity() + self.assertTrue(pai.point_at_infinity()) + + point2 = EccXPoint(None, "curve25519") + self.assertTrue(point2.point_at_infinity()) + + def test_scalar_multiply(self): + base = EccXPoint(9, "curve25519") + + pointH = 0 * base + self.assertTrue(pointH.point_at_infinity()) + + pointH = 0x1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3ed * base + self.assertTrue(pointH.point_at_infinity()) + + pointH = base * 1 + self.assertEqual(pointH.x, 9) + + for d, result in scalar_base9_test: + pointH = d * base + self.assertEqual(pointH.x, result) + + def test_sizes(self): + point = EccXPoint(9, "curve25519") + self.assertEqual(point.size_in_bits(), 255) + self.assertEqual(point.size_in_bytes(), 32) + + +class TestEccKey_Curve25519(unittest.TestCase): + + def test_private_key(self): + # RFC7748 Section 6.1 - Alice + alice_priv = unhexlify("77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a") + alice_pub = unhexlify("8520f0098930a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98eaa9b4e6a") + alice_pub_x = Integer.from_bytes(alice_pub, byteorder='little') + + key = EccKey(curve="Curve25519", seed=alice_priv) + self.assertEqual(key.seed, alice_priv) + self.assertTrue(key.has_private()) + self.assertEqual(key.pointQ.x, alice_pub_x) + + # RFC7748 Section 6.1 - Bob + bob_priv = unhexlify("5dab087e624a8a4b79e17f8b83800ee66f3bb1292618b6fd1c2f8b27ff88e0eb") + bob_pub = unhexlify("de9edb7d7b7dc1b4d35b61c2ece435373f8343c85b78674dadfc7e146f882b4f") + bob_pub_x = Integer.from_bytes(bob_pub, byteorder='little') + + key = EccKey(curve="Curve25519", seed=bob_priv) + self.assertEqual(key.seed, bob_priv) + self.assertTrue(key.has_private()) + self.assertEqual(key.pointQ.x, bob_pub_x) + + # Other names + key = EccKey(curve="curve25519", seed=alice_priv) + + # Must not accept d parameter + self.assertRaises(ValueError, EccKey, curve="curve25519", d=1) + + def test_public_key(self): + point = EccXPoint(_curves['curve25519'].Gx, + curve='curve25519') + key = EccKey(curve="curve25519", point=point) + self.assertFalse(key.has_private()) + self.assertEqual(key.pointQ, point) + + def test_public_key_derived(self): + priv_key = EccKey(curve="curve25519", seed=b'H'*32) + pub_key = priv_key.public_key() + self.assertFalse(pub_key.has_private()) + self.assertEqual(priv_key.pointQ, pub_key.pointQ) + + def test_invalid_seed(self): + self.assertRaises(ValueError, lambda: EccKey(curve="curve25519", seed=b'H' * 31)) + + def test_equality(self): + private_key = ECC.construct(seed=b'H'*32, curve="Curve25519") + private_key2 = ECC.construct(seed=b'H'*32, curve="curve25519") + private_key3 = ECC.construct(seed=b'C'*32, curve="Curve25519") + + public_key = private_key.public_key() + public_key2 = private_key2.public_key() + public_key3 = private_key3.public_key() + + self.assertEqual(private_key, private_key2) + self.assertNotEqual(private_key, private_key3) + + self.assertEqual(public_key, public_key2) + self.assertNotEqual(public_key, public_key3) + + self.assertNotEqual(public_key, private_key) + + def test_name_consistency(self): + key = ECC.generate(curve='curve25519') + self.assertIn("curve='Curve25519'", repr(key)) + self.assertEqual(key.curve, 'Curve25519') + self.assertEqual(key.public_key().curve, 'Curve25519') + + +class TestEccModule_Curve25519(unittest.TestCase): + + def test_generate(self): + key = ECC.generate(curve="Curve25519") + self.assertTrue(key.has_private()) + point = EccXPoint(_curves['Curve25519'].Gx, curve="Curve25519") * key.d + self.assertEqual(key.pointQ, point) + + # Always random + key2 = ECC.generate(curve="Curve25519") + self.assertNotEqual(key, key2) + + # Other names + ECC.generate(curve="curve25519") + + # Random source + key1 = ECC.generate(curve="Curve25519", randfunc=SHAKE128.new().read) + key2 = ECC.generate(curve="Curve25519", randfunc=SHAKE128.new().read) + self.assertEqual(key1, key2) + + def test_construct(self): + seed = unhexlify("77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a") + point_hex = unhexlify("8520f0098930a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98eaa9b4e6a") + Px = Integer.from_bytes(point_hex, byteorder='little') + point = EccXPoint(Px, curve="Curve25519") + + # Private key only + key = ECC.construct(curve="Curve25519", seed=seed) + self.assertEqual(key.pointQ, point) + self.assertTrue(key.has_private()) + + # Public key only + key = ECC.construct(curve="Curve25519", point_x=Px) + self.assertEqual(key.pointQ, point) + self.assertFalse(key.has_private()) + + # Private and public key + key = ECC.construct(curve="Curve25519", seed=seed, point_x=Px) + self.assertEqual(key.pointQ, point) + self.assertTrue(key.has_private()) + + # Other names + key = ECC.construct(curve="curve25519", seed=seed) + + def test_negative_construct(self): + coordG = dict(point_x=_curves['curve25519'].Gx) + + self.assertRaises(ValueError, ECC.construct, curve="Curve25519", d=2, **coordG) + self.assertRaises(ValueError, ECC.construct, curve="Curve25519", seed=b'H'*31) + + # Verify you cannot construct weak keys (small-order points) + self.assertRaises(ValueError, ECC.construct, curve="Curve25519", + point_x=0) + self.assertRaises(ValueError, ECC.construct, curve="Curve25519", + point_x=1) + self.assertRaises(ValueError, ECC.construct, curve="Curve25519", + point_x=325606250916557431795983626356110631294008115727848805560023387167927233504) + self.assertRaises(ValueError, ECC.construct, curve="Curve25519", + point_x=39382357235489614581723060781553021112529911719440698176882885853963445705823) + p = 2**255 - 19 + self.assertRaises(ValueError, ECC.construct, curve="Curve25519", + point_x=p-1) + self.assertRaises(ValueError, ECC.construct, curve="Curve25519", + point_x=p) + self.assertRaises(ValueError, ECC.construct, curve="Curve25519", + point_x=p+1) + self.assertRaises(ValueError, ECC.construct, curve="Curve25519", + point_x=p+325606250916557431795983626356110631294008115727848805560023387167927233504) + self.assertRaises(ValueError, ECC.construct, curve="Curve25519", + point_x=p+39382357235489614581723060781553021112529911719440698176882885853963445705823) + self.assertRaises(ValueError, ECC.construct, curve="Curve25519", + point_x=p*2-1) + self.assertRaises(ValueError, ECC.construct, curve="Curve25519", + point_x=p*2) + self.assertRaises(ValueError, ECC.construct, curve="Curve25519", + point_x=p*2+1) + + +def get_tests(config={}): + tests = [] + tests += list_test_cases(TestEccPoint_Curve25519) + tests += list_test_cases(TestEccKey_Curve25519) + tests += list_test_cases(TestEccModule_Curve25519) + return tests + + +if __name__ == '__main__': + def suite(): + return unittest.TestSuite(get_tests()) + unittest.main(defaultTest='suite') diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/PublicKey/test_ECC_Curve448.py b/venv/Lib/site-packages/Cryptodome/SelfTest/PublicKey/test_ECC_Curve448.py new file mode 100644 index 0000000..6a05a9b --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/SelfTest/PublicKey/test_ECC_Curve448.py @@ -0,0 +1,246 @@ +# This file is licensed under the BSD 2-Clause License. +# See https://opensource.org/licenses/BSD-2-Clause for details. + +import unittest +from binascii import unhexlify + +from Cryptodome.SelfTest.st_common import list_test_cases +from Cryptodome.Math.Numbers import Integer +from Cryptodome.Hash import SHAKE128 + +from Cryptodome.PublicKey import ECC +from Cryptodome.PublicKey.ECC import EccKey, EccXPoint, _curves + +CURVE448_P = 2**448 - 2**224 - 1 +CURVE448_ORDER = 2**446 - 0x8335dc163bb124b65129c96fde933d8d723a70aadc873d6d54a7bb0d + +# Test vectors for scalar multiplication using point with X=5 as base +# Each tuple is (exponent, X-coordinate) +scalar_base5_test = [ + (1, 5), + (2, 0x6391322257cae3d49aef4665d8bd5cccac9abefb511e83d75f3c766616266fc1bf3747f1da00ed7125e8f0255a1208087d32a4bc1c743cb6), + (3, 0x1fbe4b3584cab86170c14b9325840b8a2429b61fb93c42492c002a2807a4e7ea63138ea59bf95652ce9a7d13d0321c7511e3314d0553f34c), + (4, 0x93b44a7b78726ba8d0b048bd7144074f8bdad24ef9d0a6c8264f6c00b135ffcea11545e80d18364acc8ebfbcc45358e0da5fd5e5146e2b1), + (6, 0x693d165f453bd62871e5e53845f33e9e5b18b24d79c1f9102608aa7ba6f18ac24864012171d64c90b698f5ce5631cd02cee4e4336b1ad88c), + (9, 0xb970d576e7d9aa427dbf7cb9b7dd65170721d04ee060c9ea8d499dc361d4cfde1ceb19068eae853bac8f5d92827bdbf3d94c22de2fb42dae), + (129, 0x9fbdb50a1450438fe656aa32aa1bb2548d077d5c3a5d327689093a2996a4f94eacd1fb4f90315edb2afe41908a759f0d6db83fa791df80db), + (255, 0x31bc3e9385dfd12e1238927061eb0c911466da394e459bf058ba3b08260a258a3c392b0f85ddbd23828657137b88577a85b83774139fab9e), + (256, 0x735c7f30e6872e5e4215c0147c8a112d697f668c9bd0f92f5f1e4e6badc128a0b654e697cd4bae2144d54e726b54c1fa63a09b00dd3c17f), + (257, 0x95c1b0ce01286dc047aeb5922a5e62b3effb5b9296273a5004eb456f592728dd494a6fb5996a2ea7011ae6423874a48c2927bfa62d8ce8b0), + (0x10101, 0x113bb172c9dc52ab45bd665dd9751ed44e33b8596f943c6cb2f8dd329160ece802960b3eb0d2c21ef3a3ac12c20fccbc2a271fc2f061c1b2), + (0xAA55CC, 0xcf42585d2e0b1e45c0bfd601c91af4b137d7faf139fc761178c7ded432417c307ee1759af2deec6a14dbaf6b868eb13a6039fbdde4b61898), + (0x1B29A0E579E0A000567, 0x7bd9ec9775a664f4d860d82d6be60895113a7c36f92db25583dbba5dc17f09c136ec27e14857bfd6a705311327030aa657dd036325fad330), + (CURVE448_ORDER + 1, 5), +] + + +class TestEccPoint_Curve448(unittest.TestCase): + + v1 = 0x09fa78b39b00a72930bcd8039be789a0997830bb99f79aeeb93493715390b4e8 + v2 = 0x15210f12786811d3f4b7959d0538ae2c31dbe7106fc03c3efc4cd549c715a493 + + def test_init(self): + EccXPoint(5, "curve448") + EccXPoint(CURVE448_P - 5, "curve448") + + def test_curve_attribute(self): + point = EccXPoint(5, "curve448") + self.assertEqual(point.curve, "Curve448") + + def test_init_fail(self): + self.assertRaises(ValueError, EccXPoint, 3*CURVE448_P, "curve448") + self.assertRaises(ValueError, EccXPoint, 3, "curve449") + + def test_equal_set(self): + point1 = EccXPoint(self.v1, "curve448") + point2 = EccXPoint(self.v2, "curve448") + + self.assertEqual(point1, point1) + self.assertNotEqual(point1, point2) + + point2.set(point1) + self.assertEqual(point1.x, point2.x) + + def test_copy(self): + point1 = EccXPoint(self.v1, "curve448") + point2 = point1.copy() + self.assertEqual(point1.x, point2.x) + + def test_pai(self): + point1 = EccXPoint(self.v1, "curve448") + pai = point1.point_at_infinity() + self.assertTrue(pai.point_at_infinity()) + + point2 = EccXPoint(None, "curve448") + self.assertTrue(point2.point_at_infinity()) + + def test_scalar_multiply(self): + base = EccXPoint(5, "curve448") + + pointH = 0 * base + self.assertTrue(pointH.point_at_infinity()) + + pointH = CURVE448_ORDER * base + self.assertTrue(pointH.point_at_infinity()) + + pointH = base * 1 + self.assertEqual(pointH.x, 5) + + for d, result in scalar_base5_test: + pointH = d * base + self.assertEqual(pointH.x, result) + + def test_sizes(self): + point = EccXPoint(5, "curve448") + self.assertEqual(point.size_in_bits(), 448) + self.assertEqual(point.size_in_bytes(), 56) + + +class TestEccKey_Curve448(unittest.TestCase): + + def test_private_key(self): + # RFC7748 Section 6.2 - Alice + alice_priv = unhexlify("9a8f4925d1519f5775cf46b04b5800d4ee9ee8bae8bc5565d498c28dd9c9baf574a9419744897391006382a6f127ab1d9ac2d8c0a598726b") + alice_pub = unhexlify("9b08f7cc31b7e3e67d22d5aea121074a273bd2b83de09c63faa73d2c22c5d9bbc836647241d953d40c5b12da88120d53177f80e532c41fa0") + alice_pub_x = Integer.from_bytes(alice_pub, byteorder='little') + + key = EccKey(curve="Curve448", seed=alice_priv) + self.assertEqual(key.seed, alice_priv) + self.assertTrue(key.has_private()) + self.assertEqual(key.pointQ.x, alice_pub_x) + + # RFC7748 Section 6.2 - Bob + bob_priv = unhexlify("1c306a7ac2a0e2e0990b294470cba339e6453772b075811d8fad0d1d6927c120bb5ee8972b0d3e21374c9c921b09d1b0366f10b65173992d") + bob_pub = unhexlify("3eb7a829b0cd20f5bcfc0b599b6feccf6da4627107bdb0d4f345b43027d8b972fc3e34fb4232a13ca706dcb57aec3dae07bdc1c67bf33609") + bob_pub_x = Integer.from_bytes(bob_pub, byteorder='little') + + key = EccKey(curve="Curve448", seed=bob_priv) + self.assertEqual(key.seed, bob_priv) + self.assertTrue(key.has_private()) + self.assertEqual(key.pointQ.x, bob_pub_x) + + # Other names + key = EccKey(curve="curve448", seed=alice_priv) + + # Must not accept d parameter + self.assertRaises(ValueError, EccKey, curve="curve448", d=1) + + def test_public_key(self): + point = EccXPoint(_curves['curve448'].Gx, + curve='curve448') + key = EccKey(curve="curve448", point=point) + self.assertFalse(key.has_private()) + self.assertEqual(key.pointQ, point) + + def test_public_key_derived(self): + priv_key = EccKey(curve="curve448", seed=b'H'*56) + pub_key = priv_key.public_key() + self.assertFalse(pub_key.has_private()) + self.assertEqual(priv_key.pointQ, pub_key.pointQ) + + def test_invalid_seed(self): + self.assertRaises(ValueError, lambda: EccKey(curve="curve448", + seed=b'H' * 55)) + + def test_equality(self): + private_key = ECC.construct(seed=b'H'*56, curve="Curve448") + private_key2 = ECC.construct(seed=b'H'*56, curve="curve448") + private_key3 = ECC.construct(seed=b'C'*56, curve="Curve448") + + public_key = private_key.public_key() + public_key2 = private_key2.public_key() + public_key3 = private_key3.public_key() + + self.assertEqual(private_key, private_key2) + self.assertNotEqual(private_key, private_key3) + + self.assertEqual(public_key, public_key2) + self.assertNotEqual(public_key, public_key3) + + self.assertNotEqual(public_key, private_key) + + def test_name_consistency(self): + key = ECC.generate(curve='curve448') + self.assertIn("curve='Curve448'", repr(key)) + self.assertEqual(key.curve, 'Curve448') + self.assertEqual(key.public_key().curve, 'Curve448') + + +class TestEccModule_Curve448(unittest.TestCase): + + def test_generate(self): + key = ECC.generate(curve="Curve448") + self.assertTrue(key.has_private()) + point = EccXPoint(_curves['Curve448'].Gx, curve="Curve448") * key.d + self.assertEqual(key.pointQ, point) + + # Always random + key2 = ECC.generate(curve="Curve448") + self.assertNotEqual(key, key2) + + # Other names + ECC.generate(curve="curve448") + + # Random source + key1 = ECC.generate(curve="Curve448", randfunc=SHAKE128.new().read) + key2 = ECC.generate(curve="Curve448", randfunc=SHAKE128.new().read) + self.assertEqual(key1, key2) + + def test_construct(self): + seed = unhexlify("9a8f4925d1519f5775cf46b04b5800d4ee9ee8bae8bc5565d498c28dd9c9baf574a9419744897391006382a6f127ab1d9ac2d8c0a598726b") + point_hex = unhexlify("9b08f7cc31b7e3e67d22d5aea121074a273bd2b83de09c63faa73d2c22c5d9bbc836647241d953d40c5b12da88120d53177f80e532c41fa0") + Px = Integer.from_bytes(point_hex, byteorder='little') + point = EccXPoint(Px, curve="Curve448") + + # Private key only + key = ECC.construct(curve="Curve448", seed=seed) + self.assertEqual(key.pointQ, point) + self.assertTrue(key.has_private()) + + # Public key only + key = ECC.construct(curve="Curve448", point_x=Px) + self.assertEqual(key.pointQ, point) + self.assertFalse(key.has_private()) + + # Private and public key + key = ECC.construct(curve="Curve448", seed=seed, point_x=Px) + self.assertEqual(key.pointQ, point) + self.assertTrue(key.has_private()) + + # Other names + key = ECC.construct(curve="curve448", seed=seed) + + def test_negative_construct(self): + coordG = dict(point_x=_curves['curve448'].Gx) + + self.assertRaises(ValueError, ECC.construct, curve="Curve448", + d=2, **coordG) + self.assertRaises(ValueError, ECC.construct, curve="Curve448", + seed=b'H'*55) + + # Verify you cannot construct weak keys (small-order points) + self.assertRaises(ValueError, ECC.construct, curve="Curve448", + point_x=0) + self.assertRaises(ValueError, ECC.construct, curve="Curve448", + point_x=1) + p = 2**448 - 2**224 - 1 + self.assertRaises(ValueError, ECC.construct, curve="Curve448", + point_x=p-1) + self.assertRaises(ValueError, ECC.construct, curve="Curve448", + point_x=p) + self.assertRaises(ValueError, ECC.construct, curve="Curve448", + point_x=p+1) + + +def get_tests(config={}): + tests = [] + tests += list_test_cases(TestEccPoint_Curve448) + tests += list_test_cases(TestEccKey_Curve448) + tests += list_test_cases(TestEccModule_Curve448) + return tests + + +if __name__ == '__main__': + def suite(): + return unittest.TestSuite(get_tests()) + unittest.main(defaultTest='suite') diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/PublicKey/test_ECC_Ed25519.py b/venv/Lib/site-packages/Cryptodome/SelfTest/PublicKey/test_ECC_Ed25519.py new file mode 100644 index 0000000..5018552 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/SelfTest/PublicKey/test_ECC_Ed25519.py @@ -0,0 +1,341 @@ +# =================================================================== +# +# Copyright (c) 2022, Legrandin +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# =================================================================== + +import unittest +from binascii import unhexlify + +from Cryptodome.SelfTest.st_common import list_test_cases +from Cryptodome.SelfTest.loader import load_test_vectors + +from Cryptodome.PublicKey import ECC +from Cryptodome.PublicKey.ECC import EccPoint, _curves, EccKey + +from Cryptodome.Math.Numbers import Integer + +from Cryptodome.Hash import SHAKE128 + + +class TestEccPoint_Ed25519(unittest.TestCase): + + Gxy = {"x": 15112221349535400772501151409588531511454012693041857206046113283949847762202, + "y": 46316835694926478169428394003475163141307993866256225615783033603165251855960} + + G2xy = {"x": 24727413235106541002554574571675588834622768167397638456726423682521233608206, + "y": 15549675580280190176352668710449542251549572066445060580507079593062643049417} + + G3xy = {"x": 46896733464454938657123544595386787789046198280132665686241321779790909858396, + "y": 8324843778533443976490377120369201138301417226297555316741202210403726505172} + + pointG = EccPoint(Gxy['x'], Gxy['y'], curve="ed25519") + pointG2 = EccPoint(G2xy['x'], G2xy['y'], curve="ed25519") + pointG3 = EccPoint(G3xy['x'], G3xy['y'], curve="ed25519") + + def test_curve_attribute(self): + self.assertEqual(self.pointG.curve, "Ed25519") + + def test_init_xy(self): + EccPoint(self.Gxy['x'], self.Gxy['y'], curve="Ed25519") + + # Neutral point + pai = EccPoint(0, 1, curve="Ed25519") + self.assertEqual(pai.x, 0) + self.assertEqual(pai.y, 1) + self.assertEqual(pai.xy, (0, 1)) + + # G + bp = self.pointG.copy() + self.assertEqual(bp.x, 15112221349535400772501151409588531511454012693041857206046113283949847762202) + self.assertEqual(bp.y, 46316835694926478169428394003475163141307993866256225615783033603165251855960) + self.assertEqual(bp.xy, (bp.x, bp.y)) + + # 2G + bp2 = self.pointG2.copy() + self.assertEqual(bp2.x, 24727413235106541002554574571675588834622768167397638456726423682521233608206) + self.assertEqual(bp2.y, 15549675580280190176352668710449542251549572066445060580507079593062643049417) + self.assertEqual(bp2.xy, (bp2.x, bp2.y)) + + # 5G + EccPoint(x=33467004535436536005251147249499675200073690106659565782908757308821616914995, + y=43097193783671926753355113395909008640284023746042808659097434958891230611693, + curve="Ed25519") + + # Catch if point is not on the curve + self.assertRaises(ValueError, EccPoint, 34, 35, curve="Ed25519") + + def test_set(self): + pointW = EccPoint(0, 1, curve="Ed25519") + pointW.set(self.pointG) + self.assertEqual(pointW.x, self.pointG.x) + self.assertEqual(pointW.y, self.pointG.y) + + def test_copy(self): + pointW = self.pointG.copy() + self.assertEqual(pointW.x, self.pointG.x) + self.assertEqual(pointW.y, self.pointG.y) + + def test_equal(self): + pointH = self.pointG.copy() + pointI = self.pointG2.copy() + self.assertEqual(self.pointG, pointH) + self.assertNotEqual(self.pointG, pointI) + + def test_pai(self): + pai = EccPoint(0, 1, curve="Ed25519") + self.assertTrue(pai.is_point_at_infinity()) + self.assertEqual(pai, pai.point_at_infinity()) + + def test_negate(self): + negG = -self.pointG + G100 = self.pointG * 100 + sum_zero = G100 + negG * 100 + self.assertTrue(sum_zero.is_point_at_infinity()) + + sum_99 = G100 + negG + expected = self.pointG * 99 + self.assertEqual(sum_99, expected) + + def test_addition(self): + self.assertEqual(self.pointG + self.pointG2, self.pointG3) + self.assertEqual(self.pointG2 + self.pointG, self.pointG3) + self.assertEqual(self.pointG2 + self.pointG.point_at_infinity(), self.pointG2) + self.assertEqual(self.pointG.point_at_infinity() + self.pointG2, self.pointG2) + + G5 = self.pointG2 + self.pointG3 + self.assertEqual(G5.x, 33467004535436536005251147249499675200073690106659565782908757308821616914995) + self.assertEqual(G5.y, 43097193783671926753355113395909008640284023746042808659097434958891230611693) + + def test_inplace_addition(self): + pointH = self.pointG.copy() + pointH += self.pointG + self.assertEqual(pointH, self.pointG2) + pointH += self.pointG + self.assertEqual(pointH, self.pointG3) + pointH += self.pointG.point_at_infinity() + self.assertEqual(pointH, self.pointG3) + + def test_doubling(self): + pointH = self.pointG.copy() + pointH.double() + self.assertEqual(pointH.x, self.pointG2.x) + self.assertEqual(pointH.y, self.pointG2.y) + + # 2*0 + pai = self.pointG.point_at_infinity() + pointR = pai.copy() + pointR.double() + self.assertEqual(pointR, pai) + + def test_scalar_multiply(self): + d = 0 + pointH = d * self.pointG + self.assertEqual(pointH.x, 0) + self.assertEqual(pointH.y, 1) + + d = 1 + pointH = d * self.pointG + self.assertEqual(pointH.x, self.pointG.x) + self.assertEqual(pointH.y, self.pointG.y) + + d = 2 + pointH = d * self.pointG + self.assertEqual(pointH.x, self.pointG2.x) + self.assertEqual(pointH.y, self.pointG2.y) + + d = 3 + pointH = d * self.pointG + self.assertEqual(pointH.x, self.pointG3.x) + self.assertEqual(pointH.y, self.pointG3.y) + + d = 4 + pointH = d * self.pointG + self.assertEqual(pointH.x, 14582954232372986451776170844943001818709880559417862259286374126315108956272) + self.assertEqual(pointH.y, 32483318716863467900234833297694612235682047836132991208333042722294373421359) + + d = 5 + pointH = d * self.pointG + self.assertEqual(pointH.x, 33467004535436536005251147249499675200073690106659565782908757308821616914995) + self.assertEqual(pointH.y, 43097193783671926753355113395909008640284023746042808659097434958891230611693) + + d = 10 + pointH = d * self.pointG + self.assertEqual(pointH.x, 43500613248243327786121022071801015118933854441360174117148262713429272820047) + self.assertEqual(pointH.y, 45005105423099817237495816771148012388779685712352441364231470781391834741548) + + d = 20 + pointH = d * self.pointG + self.assertEqual(pointH.x, 46694936775300686710656303283485882876784402425210400817529601134760286812591) + self.assertEqual(pointH.y, 8786390172762935853260670851718824721296437982862763585171334833968259029560) + + d = 255 + pointH = d * self.pointG + self.assertEqual(pointH.x, 36843863416400016952258312492144504209624961884991522125275155377549541182230) + self.assertEqual(pointH.y, 22327030283879720808995671630924669697661065034121040761798775626517750047180) + + d = 256 + pointH = d * self.pointG + self.assertEqual(pointH.x, 42740085206947573681423002599456489563927820004573071834350074001818321593686) + self.assertEqual(pointH.y, 6935684722522267618220753829624209639984359598320562595061366101608187623111) + + def test_sizes(self): + self.assertEqual(self.pointG.size_in_bits(), 255) + self.assertEqual(self.pointG.size_in_bytes(), 32) + + +class TestEccKey_Ed25519(unittest.TestCase): + + def test_private_key(self): + seed = unhexlify("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60") + Px = 38815646466658113194383306759739515082307681141926459231621296960732224964046 + Py = 11903303657706407974989296177215005343713679411332034699907763981919547054807 + + key = EccKey(curve="Ed25519", seed=seed) + self.assertEqual(key.seed, seed) + self.assertEqual(key.d, 36144925721603087658594284515452164870581325872720374094707712194495455132720) + self.assertTrue(key.has_private()) + self.assertEqual(key.pointQ.x, Px) + self.assertEqual(key.pointQ.y, Py) + + point = EccPoint(Px, Py, "ed25519") + key = EccKey(curve="Ed25519", seed=seed, point=point) + self.assertEqual(key.d, 36144925721603087658594284515452164870581325872720374094707712194495455132720) + self.assertTrue(key.has_private()) + self.assertEqual(key.pointQ, point) + + # Other names + key = EccKey(curve="ed25519", seed=seed) + + # Must not accept d parameter + self.assertRaises(ValueError, EccKey, curve="ed25519", d=1) + + def test_public_key(self): + point = EccPoint(_curves['ed25519'].Gx, _curves['ed25519'].Gy, curve='ed25519') + key = EccKey(curve="ed25519", point=point) + self.assertFalse(key.has_private()) + self.assertEqual(key.pointQ, point) + + def test_public_key_derived(self): + priv_key = EccKey(curve="ed25519", seed=b'H'*32) + pub_key = priv_key.public_key() + self.assertFalse(pub_key.has_private()) + self.assertEqual(priv_key.pointQ, pub_key.pointQ) + + def test_invalid_seed(self): + self.assertRaises(ValueError, lambda: EccKey(curve="ed25519", seed=b'H' * 31)) + + def test_equality(self): + private_key = ECC.construct(seed=b'H'*32, curve="Ed25519") + private_key2 = ECC.construct(seed=b'H'*32, curve="ed25519") + private_key3 = ECC.construct(seed=b'C'*32, curve="Ed25519") + + public_key = private_key.public_key() + public_key2 = private_key2.public_key() + public_key3 = private_key3.public_key() + + self.assertEqual(private_key, private_key2) + self.assertNotEqual(private_key, private_key3) + + self.assertEqual(public_key, public_key2) + self.assertNotEqual(public_key, public_key3) + + self.assertNotEqual(public_key, private_key) + + def test_name_consistency(self): + key = ECC.generate(curve='ed25519') + self.assertIn("curve='Ed25519'", repr(key)) + self.assertEqual(key.curve, 'Ed25519') + self.assertEqual(key.public_key().curve, 'Ed25519') + + +class TestEccModule_Ed25519(unittest.TestCase): + + def test_generate(self): + key = ECC.generate(curve="Ed25519") + self.assertTrue(key.has_private()) + point = EccPoint(_curves['Ed25519'].Gx, _curves['Ed25519'].Gy, curve="Ed25519") * key.d + self.assertEqual(key.pointQ, point) + + # Always random + key2 = ECC.generate(curve="Ed25519") + self.assertNotEqual(key, key2) + + # Other names + ECC.generate(curve="Ed25519") + + # Random source + key1 = ECC.generate(curve="Ed25519", randfunc=SHAKE128.new().read) + key2 = ECC.generate(curve="Ed25519", randfunc=SHAKE128.new().read) + self.assertEqual(key1, key2) + + def test_construct(self): + seed = unhexlify("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60") + Px = 38815646466658113194383306759739515082307681141926459231621296960732224964046 + Py = 11903303657706407974989296177215005343713679411332034699907763981919547054807 + d = 36144925721603087658594284515452164870581325872720374094707712194495455132720 + point = EccPoint(Px, Py, curve="Ed25519") + + # Private key only + key = ECC.construct(curve="Ed25519", seed=seed) + self.assertEqual(key.pointQ, point) + self.assertTrue(key.has_private()) + + # Public key only + key = ECC.construct(curve="Ed25519", point_x=Px, point_y=Py) + self.assertEqual(key.pointQ, point) + self.assertFalse(key.has_private()) + + # Private and public key + key = ECC.construct(curve="Ed25519", seed=seed, point_x=Px, point_y=Py) + self.assertEqual(key.pointQ, point) + self.assertTrue(key.has_private()) + + # Other names + key = ECC.construct(curve="ed25519", seed=seed) + + def test_negative_construct(self): + coord = dict(point_x=10, point_y=4) + coordG = dict(point_x=_curves['ed25519'].Gx, point_y=_curves['ed25519'].Gy) + + self.assertRaises(ValueError, ECC.construct, curve="Ed25519", **coord) + self.assertRaises(ValueError, ECC.construct, curve="Ed25519", d=2, **coordG) + self.assertRaises(ValueError, ECC.construct, curve="Ed25519", seed=b'H'*31) + + +def get_tests(config={}): + tests = [] + tests += list_test_cases(TestEccPoint_Ed25519) + tests += list_test_cases(TestEccKey_Ed25519) + tests += list_test_cases(TestEccModule_Ed25519) + return tests + + +if __name__ == '__main__': + def suite(): + return unittest.TestSuite(get_tests()) + unittest.main(defaultTest='suite') diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/PublicKey/test_ECC_Ed448.py b/venv/Lib/site-packages/Cryptodome/SelfTest/PublicKey/test_ECC_Ed448.py new file mode 100644 index 0000000..3a7b0eb --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/SelfTest/PublicKey/test_ECC_Ed448.py @@ -0,0 +1,336 @@ +# =================================================================== +# +# Copyright (c) 2022, Legrandin +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# =================================================================== + +import unittest +from binascii import unhexlify + +from Cryptodome.SelfTest.st_common import list_test_cases +from Cryptodome.SelfTest.loader import load_test_vectors + +from Cryptodome.PublicKey import ECC +from Cryptodome.PublicKey.ECC import EccPoint, _curves, EccKey + +from Cryptodome.Math.Numbers import Integer + +from Cryptodome.Hash import SHAKE128 + + +class TestEccPoint_Ed448(unittest.TestCase): + + Gxy = {"x": 0x4f1970c66bed0ded221d15a622bf36da9e146570470f1767ea6de324a3d3a46412ae1af72ab66511433b80e18b00938e2626a82bc70cc05e, + "y": 0x693f46716eb6bc248876203756c9c7624bea73736ca3984087789c1e05a0c2d73ad3ff1ce67c39c4fdbd132c4ed7c8ad9808795bf230fa14} + + G2xy = {"x": 0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa955555555555555555555555555555555555555555555555555555555, + "y": 0xae05e9634ad7048db359d6205086c2b0036ed7a035884dd7b7e36d728ad8c4b80d6565833a2a3098bbbcb2bed1cda06bdaeafbcdea9386ed} + + G3xy = {"x": 0x865886b9108af6455bd64316cb6943332241b8b8cda82c7e2ba077a4a3fcfe8daa9cbf7f6271fd6e862b769465da8575728173286ff2f8f, + "y": 0xe005a8dbd5125cf706cbda7ad43aa6449a4a8d952356c3b9fce43c82ec4e1d58bb3a331bdb6767f0bffa9a68fed02dafb822ac13588ed6fc} + + pointG = EccPoint(Gxy['x'], Gxy['y'], curve="ed448") + pointG2 = EccPoint(G2xy['x'], G2xy['y'], curve="ed448") + pointG3 = EccPoint(G3xy['x'], G3xy['y'], curve="ed448") + + def test_curve_attribute(self): + self.assertEqual(self.pointG.curve, "Ed448") + + def test_init_xy(self): + EccPoint(self.Gxy['x'], self.Gxy['y'], curve="Ed448") + + # Neutral point + pai = EccPoint(0, 1, curve="Ed448") + self.assertEqual(pai.x, 0) + self.assertEqual(pai.y, 1) + self.assertEqual(pai.xy, (0, 1)) + + # G + bp = self.pointG.copy() + self.assertEqual(bp.x, 0x4f1970c66bed0ded221d15a622bf36da9e146570470f1767ea6de324a3d3a46412ae1af72ab66511433b80e18b00938e2626a82bc70cc05e) + self.assertEqual(bp.y, 0x693f46716eb6bc248876203756c9c7624bea73736ca3984087789c1e05a0c2d73ad3ff1ce67c39c4fdbd132c4ed7c8ad9808795bf230fa14) + self.assertEqual(bp.xy, (bp.x, bp.y)) + + # 2G + bp2 = self.pointG2.copy() + self.assertEqual(bp2.x, 0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa955555555555555555555555555555555555555555555555555555555) + self.assertEqual(bp2.y, 0xae05e9634ad7048db359d6205086c2b0036ed7a035884dd7b7e36d728ad8c4b80d6565833a2a3098bbbcb2bed1cda06bdaeafbcdea9386ed) + self.assertEqual(bp2.xy, (bp2.x, bp2.y)) + + # 5G + EccPoint(x=0x7a9f9335a48dcb0e2ba7601eedb50def80cbcf728562ada756d761e8958812808bc0d57a920c3c96f07b2d8cefc6f950d0a99d1092030034, + y=0xadfd751a2517edd3b9109ce4fd580ade260ca1823ab18fced86551f7b698017127d7a4ee59d2b33c58405512881f225443b4731472f435eb, + curve="Ed448") + + # Catch if point is not on the curve + self.assertRaises(ValueError, EccPoint, 34, 35, curve="Ed448") + + def test_set(self): + pointW = EccPoint(0, 1, curve="Ed448") + pointW.set(self.pointG) + self.assertEqual(pointW.x, self.pointG.x) + self.assertEqual(pointW.y, self.pointG.y) + + def test_copy(self): + pointW = self.pointG.copy() + self.assertEqual(pointW.x, self.pointG.x) + self.assertEqual(pointW.y, self.pointG.y) + + def test_equal(self): + pointH = self.pointG.copy() + pointI = self.pointG2.copy() + self.assertEqual(self.pointG, pointH) + self.assertNotEqual(self.pointG, pointI) + + def test_pai(self): + pai = EccPoint(0, 1, curve="Ed448") + self.assertTrue(pai.is_point_at_infinity()) + self.assertEqual(pai, pai.point_at_infinity()) + + def test_negate(self): + negG = -self.pointG + sum = self.pointG + negG + self.assertTrue(sum.is_point_at_infinity()) + + def test_addition(self): + self.assertEqual(self.pointG + self.pointG2, self.pointG3) + self.assertEqual(self.pointG2 + self.pointG, self.pointG3) + self.assertEqual(self.pointG2 + self.pointG.point_at_infinity(), self.pointG2) + self.assertEqual(self.pointG.point_at_infinity() + self.pointG2, self.pointG2) + + G5 = self.pointG2 + self.pointG3 + self.assertEqual(G5.x, 0x7a9f9335a48dcb0e2ba7601eedb50def80cbcf728562ada756d761e8958812808bc0d57a920c3c96f07b2d8cefc6f950d0a99d1092030034) + self.assertEqual(G5.y, 0xadfd751a2517edd3b9109ce4fd580ade260ca1823ab18fced86551f7b698017127d7a4ee59d2b33c58405512881f225443b4731472f435eb) + + def test_inplace_addition(self): + pointH = self.pointG.copy() + pointH += self.pointG + self.assertEqual(pointH, self.pointG2) + pointH += self.pointG + self.assertEqual(pointH, self.pointG3) + pointH += self.pointG.point_at_infinity() + self.assertEqual(pointH, self.pointG3) + + def test_doubling(self): + pointH = self.pointG.copy() + pointH.double() + self.assertEqual(pointH.x, self.pointG2.x) + self.assertEqual(pointH.y, self.pointG2.y) + + # 2*0 + pai = self.pointG.point_at_infinity() + pointR = pai.copy() + pointR.double() + self.assertEqual(pointR, pai) + + def test_scalar_multiply(self): + d = 0 + pointH = d * self.pointG + self.assertEqual(pointH.x, 0) + self.assertEqual(pointH.y, 1) + + d = 1 + pointH = d * self.pointG + self.assertEqual(pointH.x, self.pointG.x) + self.assertEqual(pointH.y, self.pointG.y) + + d = 2 + pointH = d * self.pointG + self.assertEqual(pointH.x, self.pointG2.x) + self.assertEqual(pointH.y, self.pointG2.y) + + d = 3 + pointH = d * self.pointG + self.assertEqual(pointH.x, self.pointG3.x) + self.assertEqual(pointH.y, self.pointG3.y) + + d = 4 + pointH = d * self.pointG + self.assertEqual(pointH.x, 0x49dcbc5c6c0cce2c1419a17226f929ea255a09cf4e0891c693fda4be70c74cc301b7bdf1515dd8ba21aee1798949e120e2ce42ac48ba7f30) + self.assertEqual(pointH.y, 0xd49077e4accde527164b33a5de021b979cb7c02f0457d845c90dc3227b8a5bc1c0d8f97ea1ca9472b5d444285d0d4f5b32e236f86de51839) + + d = 5 + pointH = d * self.pointG + self.assertEqual(pointH.x, 0x7a9f9335a48dcb0e2ba7601eedb50def80cbcf728562ada756d761e8958812808bc0d57a920c3c96f07b2d8cefc6f950d0a99d1092030034) + self.assertEqual(pointH.y, 0xadfd751a2517edd3b9109ce4fd580ade260ca1823ab18fced86551f7b698017127d7a4ee59d2b33c58405512881f225443b4731472f435eb) + + d = 10 + pointH = d * self.pointG + self.assertEqual(pointH.x, 0x77486f9d19f6411cdd35d30d1c3235f71936452c787e5c034134d3e8172278aca61622bc805761ce3dab65118a0122d73b403165d0ed303d) + self.assertEqual(pointH.y, 0x4d2fea0b026be11024f1f0fe7e94e618e8ac17381ada1d1bf7ee293a68ff5d0bf93c1997dc1aabdc0c7e6381428d85b6b1954a89e4cddf67) + + d = 20 + pointH = d * self.pointG + self.assertEqual(pointH.x, 0x3c236422354600fe6763defcc1503737e4ed89e262d0de3ec1e552020f2a56fe3b9e1e012d021072598c3c2821e18268bb8fb8339c0d1216) + self.assertEqual(pointH.y, 0xb555b9721f630ccb05fc466de4c74d3d2781e69eca88e1b040844f04cab39fd946f91c688fa42402bb38fb9c3e61231017020b219b4396e1) + + d = 255 + pointH = d * self.pointG + self.assertEqual(pointH.x, 0xbeb7f8388b05cd9c1aa2e3c0dcf31e2b563659361826225390e7748654f627d5c36cbe627e9019936b56d15d4dad7c337c09bac64ff4197f) + self.assertEqual(pointH.y, 0x1e37312b2dd4e9440c43c6e7725fc4fa3d11e582d4863f1d018e28f50c0efdb1f53f9b01ada7c87fa162b1f0d72401015d57613d25f1ad53) + + d = 256 + pointH = d * self.pointG + self.assertEqual(pointH.x, 0xf19c34feb56730e3e2be761ac0a2a2b24853b281dda019fc35a5ab58e3696beb39609ae756b0d20fb7ccf0d79aaf5f3bca2e4fdb25bfac1c) + self.assertEqual(pointH.y, 0x3beb69cc9111bffcaddc61d363ce6fe5dd44da4aadce78f52e92e985d5442344ced72c4611ed0daac9f4f5661eab73d7a12d25ce8a30241e) + + def test_sizes(self): + self.assertEqual(self.pointG.size_in_bits(), 448) + self.assertEqual(self.pointG.size_in_bytes(), 56) + + +class TestEccKey_Ed448(unittest.TestCase): + + def test_private_key(self): + seed = unhexlify("4adf5d37ac6785e83e99a924f92676d366a78690af59c92b6bdf14f9cdbcf26fdad478109607583d633b60078d61d51d81b7509c5433b0d4c9") + Px = 0x72a01eea003a35f9ac44231dc4aae2a382f351d80bf32508175b0855edcf389aa2bbf308dd961ce361a6e7c2091bc78957f6ebcf3002a617 + Py = 0x9e0d08d84586e9aeefecacb41d049b831f1a3ee0c3eada63e34557b30702b50ab59fb372feff7c30b8cbb7dd51afbe88444ec56238722ec1 + + key = EccKey(curve="Ed448", seed=seed) + self.assertEqual(key.seed, seed) + self.assertEqual(key.d, 0xb07cf179604f83433186e5178760c759c15125ee54ff6f8dcde46e872b709ac82ed0bd0a4e036d774034dcb18a9fb11894657a1485895f80) + self.assertTrue(key.has_private()) + self.assertEqual(key.pointQ.x, Px) + self.assertEqual(key.pointQ.y, Py) + + point = EccPoint(Px, Py, "ed448") + key = EccKey(curve="Ed448", seed=seed, point=point) + self.assertEqual(key.d, 0xb07cf179604f83433186e5178760c759c15125ee54ff6f8dcde46e872b709ac82ed0bd0a4e036d774034dcb18a9fb11894657a1485895f80) + self.assertTrue(key.has_private()) + self.assertEqual(key.pointQ, point) + + # Other names + key = EccKey(curve="ed448", seed=seed) + + # Must not accept d parameter + self.assertRaises(ValueError, EccKey, curve="ed448", d=1) + + def test_public_key(self): + point = EccPoint(_curves['ed448'].Gx, _curves['ed448'].Gy, curve='ed448') + key = EccKey(curve="ed448", point=point) + self.assertFalse(key.has_private()) + self.assertEqual(key.pointQ, point) + + def test_public_key_derived(self): + priv_key = EccKey(curve="ed448", seed=b'H'*57) + pub_key = priv_key.public_key() + self.assertFalse(pub_key.has_private()) + self.assertEqual(priv_key.pointQ, pub_key.pointQ) + + def test_invalid_seed(self): + self.assertRaises(ValueError, lambda: EccKey(curve="ed448", seed=b'H' * 56)) + + def test_equality(self): + private_key = ECC.construct(seed=b'H'*57, curve="Ed448") + private_key2 = ECC.construct(seed=b'H'*57, curve="ed448") + private_key3 = ECC.construct(seed=b'C'*57, curve="Ed448") + + public_key = private_key.public_key() + public_key2 = private_key2.public_key() + public_key3 = private_key3.public_key() + + self.assertEqual(private_key, private_key2) + self.assertNotEqual(private_key, private_key3) + + self.assertEqual(public_key, public_key2) + self.assertNotEqual(public_key, public_key3) + + self.assertNotEqual(public_key, private_key) + + def test_name_consistency(self): + key = ECC.generate(curve='ed448') + self.assertIn("curve='Ed448'", repr(key)) + self.assertEqual(key.curve, 'Ed448') + self.assertEqual(key.public_key().curve, 'Ed448') + + +class TestEccModule_Ed448(unittest.TestCase): + + def test_generate(self): + key = ECC.generate(curve="Ed448") + self.assertTrue(key.has_private()) + point = EccPoint(_curves['Ed448'].Gx, _curves['Ed448'].Gy, curve="Ed448") * key.d + self.assertEqual(key.pointQ, point) + + # Always random + key2 = ECC.generate(curve="Ed448") + self.assertNotEqual(key, key2) + + # Other names + ECC.generate(curve="Ed448") + + # Random source + key1 = ECC.generate(curve="Ed448", randfunc=SHAKE128.new().read) + key2 = ECC.generate(curve="Ed448", randfunc=SHAKE128.new().read) + self.assertEqual(key1, key2) + + def test_construct(self): + seed = unhexlify("4adf5d37ac6785e83e99a924f92676d366a78690af59c92b6bdf14f9cdbcf26fdad478109607583d633b60078d61d51d81b7509c5433b0d4c9") + Px = 0x72a01eea003a35f9ac44231dc4aae2a382f351d80bf32508175b0855edcf389aa2bbf308dd961ce361a6e7c2091bc78957f6ebcf3002a617 + Py = 0x9e0d08d84586e9aeefecacb41d049b831f1a3ee0c3eada63e34557b30702b50ab59fb372feff7c30b8cbb7dd51afbe88444ec56238722ec1 + d = 0xb07cf179604f83433186e5178760c759c15125ee54ff6f8dcde46e872b709ac82ed0bd0a4e036d774034dcb18a9fb11894657a1485895f80 + point = EccPoint(Px, Py, curve="Ed448") + + # Private key only + key = ECC.construct(curve="Ed448", seed=seed) + self.assertEqual(key.pointQ, point) + self.assertTrue(key.has_private()) + + # Public key only + key = ECC.construct(curve="Ed448", point_x=Px, point_y=Py) + self.assertEqual(key.pointQ, point) + self.assertFalse(key.has_private()) + + # Private and public key + key = ECC.construct(curve="Ed448", seed=seed, point_x=Px, point_y=Py) + self.assertEqual(key.pointQ, point) + self.assertTrue(key.has_private()) + + # Other names + key = ECC.construct(curve="ed448", seed=seed) + + def test_negative_construct(self): + coord = dict(point_x=10, point_y=4) + coordG = dict(point_x=_curves['ed448'].Gx, point_y=_curves['ed448'].Gy) + + self.assertRaises(ValueError, ECC.construct, curve="Ed448", **coord) + self.assertRaises(ValueError, ECC.construct, curve="Ed448", d=2, **coordG) + self.assertRaises(ValueError, ECC.construct, curve="Ed448", seed=b'H'*58) + + +def get_tests(config={}): + tests = [] + tests += list_test_cases(TestEccPoint_Ed448) + tests += list_test_cases(TestEccKey_Ed448) + tests += list_test_cases(TestEccModule_Ed448) + return tests + + +if __name__ == '__main__': + def suite(): + return unittest.TestSuite(get_tests()) + unittest.main(defaultTest='suite') diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/PublicKey/test_ECC_NIST.py b/venv/Lib/site-packages/Cryptodome/SelfTest/PublicKey/test_ECC_NIST.py new file mode 100644 index 0000000..ae790b1 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/SelfTest/PublicKey/test_ECC_NIST.py @@ -0,0 +1,1440 @@ +# =================================================================== +# +# Copyright (c) 2015, Legrandin +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# =================================================================== + +import unittest +from binascii import unhexlify + +from Cryptodome.SelfTest.st_common import list_test_cases +from Cryptodome.SelfTest.loader import load_test_vectors + +from Cryptodome.PublicKey import ECC +from Cryptodome.PublicKey.ECC import EccPoint, _curves, EccKey + +from Cryptodome.Math.Numbers import Integer + + +class TestEccPoint(unittest.TestCase): + + def test_mix(self): + + p1 = ECC.generate(curve='P-256').pointQ + p2 = ECC.generate(curve='P-384').pointQ + + try: + p1 + p2 + assert(False) + except ValueError as e: + assert "not on the same curve" in str(e) + + try: + p1 += p2 + assert(False) + except ValueError as e: + assert "not on the same curve" in str(e) + + class OtherKeyType: + pass + + self.assertFalse(p1 == OtherKeyType()) + self.assertTrue(p1 != OtherKeyType()) + + def test_repr(self): + p1 = ECC.construct(curve='P-256', + d=75467964919405407085864614198393977741148485328036093939970922195112333446269, + point_x=20573031766139722500939782666697015100983491952082159880539639074939225934381, + point_y=108863130203210779921520632367477406025152638284581252625277850513266505911389) + self.assertEqual(repr(p1), "EccKey(curve='NIST P-256', point_x=20573031766139722500939782666697015100983491952082159880539639074939225934381, point_y=108863130203210779921520632367477406025152638284581252625277850513266505911389, d=75467964919405407085864614198393977741148485328036093939970922195112333446269)") + + +class TestEccPoint_NIST_P192(unittest.TestCase): + """Tests defined in section 4.1 of https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.204.9073&rep=rep1&type=pdf""" + + pointS = EccPoint( + 0xd458e7d127ae671b0c330266d246769353a012073e97acf8, + 0x325930500d851f336bddc050cf7fb11b5673a1645086df3b, + curve='p192') + + pointT = EccPoint( + 0xf22c4395213e9ebe67ddecdd87fdbd01be16fb059b9753a4, + 0x264424096af2b3597796db48f8dfb41fa9cecc97691a9c79, + curve='p192') + + def test_curve_attribute(self): + self.assertEqual(self.pointS.curve, "NIST P-192") + + def test_set(self): + pointW = EccPoint(0, 0) + pointW.set(self.pointS) + self.assertEqual(pointW, self.pointS) + + def test_copy(self): + pointW = self.pointS.copy() + self.assertEqual(pointW, self.pointS) + pointW.set(self.pointT) + self.assertEqual(pointW, self.pointT) + self.assertNotEqual(self.pointS, self.pointT) + + def test_negate(self): + negS = -self.pointS + sum = self.pointS + negS + self.assertEqual(sum, self.pointS.point_at_infinity()) + + def test_addition(self): + pointRx = 0x48e1e4096b9b8e5ca9d0f1f077b8abf58e843894de4d0290 + pointRy = 0x408fa77c797cd7dbfb16aa48a3648d3d63c94117d7b6aa4b + + pointR = self.pointS + self.pointT + self.assertEqual(pointR.x, pointRx) + self.assertEqual(pointR.y, pointRy) + + pai = pointR.point_at_infinity() + + # S + 0 + pointR = self.pointS + pai + self.assertEqual(pointR, self.pointS) + + # 0 + S + pointR = pai + self.pointS + self.assertEqual(pointR, self.pointS) + + # 0 + 0 + pointR = pai + pai + self.assertEqual(pointR, pai) + + def test_inplace_addition(self): + pointRx = 0x48e1e4096b9b8e5ca9d0f1f077b8abf58e843894de4d0290 + pointRy = 0x408fa77c797cd7dbfb16aa48a3648d3d63c94117d7b6aa4b + + pointR = self.pointS.copy() + pointR += self.pointT + self.assertEqual(pointR.x, pointRx) + self.assertEqual(pointR.y, pointRy) + + pai = pointR.point_at_infinity() + + # S + 0 + pointR = self.pointS.copy() + pointR += pai + self.assertEqual(pointR, self.pointS) + + # 0 + S + pointR = pai.copy() + pointR += self.pointS + self.assertEqual(pointR, self.pointS) + + # 0 + 0 + pointR = pai.copy() + pointR += pai + self.assertEqual(pointR, pai) + + def test_doubling(self): + pointRx = 0x30c5bc6b8c7da25354b373dc14dd8a0eba42d25a3f6e6962 + pointRy = 0x0dde14bc4249a721c407aedbf011e2ddbbcb2968c9d889cf + + pointR = self.pointS.copy() + pointR.double() + self.assertEqual(pointR.x, pointRx) + self.assertEqual(pointR.y, pointRy) + + # 2*0 + pai = self.pointS.point_at_infinity() + pointR = pai.copy() + pointR.double() + self.assertEqual(pointR, pai) + + # S + S + pointR = self.pointS.copy() + pointR += pointR + self.assertEqual(pointR.x, pointRx) + self.assertEqual(pointR.y, pointRy) + + def test_scalar_multiply(self): + d = 0xa78a236d60baec0c5dd41b33a542463a8255391af64c74ee + pointRx = 0x1faee4205a4f669d2d0a8f25e3bcec9a62a6952965bf6d31 + pointRy = 0x5ff2cdfa508a2581892367087c696f179e7a4d7e8260fb06 + + pointR = self.pointS * d + self.assertEqual(pointR.x, pointRx) + self.assertEqual(pointR.y, pointRy) + + # 0*S + pai = self.pointS.point_at_infinity() + pointR = self.pointS * 0 + self.assertEqual(pointR, pai) + + # -1*S + self.assertRaises(ValueError, lambda: self.pointS * -1) + + # Reverse order + pointR = d * self.pointS + self.assertEqual(pointR.x, pointRx) + self.assertEqual(pointR.y, pointRy) + + pointR = Integer(d) * self.pointS + self.assertEqual(pointR.x, pointRx) + self.assertEqual(pointR.y, pointRy) + + def test_joint_scalar_multiply(self): + d = 0xa78a236d60baec0c5dd41b33a542463a8255391af64c74ee + e = 0xc4be3d53ec3089e71e4de8ceab7cce889bc393cd85b972bc + pointRx = 0x019f64eed8fa9b72b7dfea82c17c9bfa60ecb9e1778b5bde + pointRy = 0x16590c5fcd8655fa4ced33fb800e2a7e3c61f35d83503644 + + pointR = self.pointS * d + self.pointT * e + self.assertEqual(pointR.x, pointRx) + self.assertEqual(pointR.y, pointRy) + + def test_sizes(self): + self.assertEqual(self.pointS.size_in_bits(), 192) + self.assertEqual(self.pointS.size_in_bytes(), 24) + + +class TestEccPoint_NIST_P224(unittest.TestCase): + """Tests defined in section 4.2 of https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.204.9073&rep=rep1&type=pdf""" + + pointS = EccPoint( + 0x6eca814ba59a930843dc814edd6c97da95518df3c6fdf16e9a10bb5b, + 0xef4b497f0963bc8b6aec0ca0f259b89cd80994147e05dc6b64d7bf22, + curve='p224') + + pointT = EccPoint( + 0xb72b25aea5cb03fb88d7e842002969648e6ef23c5d39ac903826bd6d, + 0xc42a8a4d34984f0b71b5b4091af7dceb33ea729c1a2dc8b434f10c34, + curve='p224') + + def test_curve_attribute(self): + self.assertEqual(self.pointS.curve, "NIST P-224") + + def test_set(self): + pointW = EccPoint(0, 0) + pointW.set(self.pointS) + self.assertEqual(pointW, self.pointS) + + def test_copy(self): + pointW = self.pointS.copy() + self.assertEqual(pointW, self.pointS) + pointW.set(self.pointT) + self.assertEqual(pointW, self.pointT) + self.assertNotEqual(self.pointS, self.pointT) + + def test_negate(self): + negS = -self.pointS + sum = self.pointS + negS + self.assertEqual(sum, self.pointS.point_at_infinity()) + + def test_addition(self): + pointRx = 0x236f26d9e84c2f7d776b107bd478ee0a6d2bcfcaa2162afae8d2fd15 + pointRy = 0xe53cc0a7904ce6c3746f6a97471297a0b7d5cdf8d536ae25bb0fda70 + + pointR = self.pointS + self.pointT + self.assertEqual(pointR.x, pointRx) + self.assertEqual(pointR.y, pointRy) + + pai = pointR.point_at_infinity() + + # S + 0 + pointR = self.pointS + pai + self.assertEqual(pointR, self.pointS) + + # 0 + S + pointR = pai + self.pointS + self.assertEqual(pointR, self.pointS) + + # 0 + 0 + pointR = pai + pai + self.assertEqual(pointR, pai) + + def test_inplace_addition(self): + pointRx = 0x236f26d9e84c2f7d776b107bd478ee0a6d2bcfcaa2162afae8d2fd15 + pointRy = 0xe53cc0a7904ce6c3746f6a97471297a0b7d5cdf8d536ae25bb0fda70 + + pointR = self.pointS.copy() + pointR += self.pointT + self.assertEqual(pointR.x, pointRx) + self.assertEqual(pointR.y, pointRy) + + pai = pointR.point_at_infinity() + + # S + 0 + pointR = self.pointS.copy() + pointR += pai + self.assertEqual(pointR, self.pointS) + + # 0 + S + pointR = pai.copy() + pointR += self.pointS + self.assertEqual(pointR, self.pointS) + + # 0 + 0 + pointR = pai.copy() + pointR += pai + self.assertEqual(pointR, pai) + + def test_doubling(self): + pointRx = 0xa9c96f2117dee0f27ca56850ebb46efad8ee26852f165e29cb5cdfc7 + pointRy = 0xadf18c84cf77ced4d76d4930417d9579207840bf49bfbf5837dfdd7d + + pointR = self.pointS.copy() + pointR.double() + self.assertEqual(pointR.x, pointRx) + self.assertEqual(pointR.y, pointRy) + + # 2*0 + pai = self.pointS.point_at_infinity() + pointR = pai.copy() + pointR.double() + self.assertEqual(pointR, pai) + + # S + S + pointR = self.pointS.copy() + pointR += pointR + self.assertEqual(pointR.x, pointRx) + self.assertEqual(pointR.y, pointRy) + + def test_scalar_multiply(self): + d = 0xa78ccc30eaca0fcc8e36b2dd6fbb03df06d37f52711e6363aaf1d73b + pointRx = 0x96a7625e92a8d72bff1113abdb95777e736a14c6fdaacc392702bca4 + pointRy = 0x0f8e5702942a3c5e13cd2fd5801915258b43dfadc70d15dbada3ed10 + + pointR = self.pointS * d + self.assertEqual(pointR.x, pointRx) + self.assertEqual(pointR.y, pointRy) + + # 0*S + pai = self.pointS.point_at_infinity() + pointR = self.pointS * 0 + self.assertEqual(pointR, pai) + + # -1*S + self.assertRaises(ValueError, lambda: self.pointS * -1) + + # Reverse order + pointR = d * self.pointS + self.assertEqual(pointR.x, pointRx) + self.assertEqual(pointR.y, pointRy) + + pointR = Integer(d) * self.pointS + self.assertEqual(pointR.x, pointRx) + self.assertEqual(pointR.y, pointRy) + + def test_joing_scalar_multiply(self): + d = 0xa78ccc30eaca0fcc8e36b2dd6fbb03df06d37f52711e6363aaf1d73b + e = 0x54d549ffc08c96592519d73e71e8e0703fc8177fa88aa77a6ed35736 + pointRx = 0xdbfe2958c7b2cda1302a67ea3ffd94c918c5b350ab838d52e288c83e + pointRy = 0x2f521b83ac3b0549ff4895abcc7f0c5a861aacb87acbc5b8147bb18b + + pointR = self.pointS * d + self.pointT * e + self.assertEqual(pointR.x, pointRx) + self.assertEqual(pointR.y, pointRy) + + def test_sizes(self): + self.assertEqual(self.pointS.size_in_bits(), 224) + self.assertEqual(self.pointS.size_in_bytes(), 28) + + +class TestEccPoint_NIST_P256(unittest.TestCase): + """Tests defined in section 4.3 of https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.204.9073&rep=rep1&type=pdf""" + + pointS = EccPoint( + 0xde2444bebc8d36e682edd27e0f271508617519b3221a8fa0b77cab3989da97c9, + 0xc093ae7ff36e5380fc01a5aad1e66659702de80f53cec576b6350b243042a256) + + pointT = EccPoint( + 0x55a8b00f8da1d44e62f6b3b25316212e39540dc861c89575bb8cf92e35e0986b, + 0x5421c3209c2d6c704835d82ac4c3dd90f61a8a52598b9e7ab656e9d8c8b24316) + + def test_curve_attribute(self): + self.assertEqual(self.pointS.curve, "NIST P-256") + + def test_set(self): + pointW = EccPoint(0, 0) + pointW.set(self.pointS) + self.assertEqual(pointW, self.pointS) + + def test_copy(self): + pointW = self.pointS.copy() + self.assertEqual(pointW, self.pointS) + pointW.set(self.pointT) + self.assertEqual(pointW, self.pointT) + self.assertNotEqual(self.pointS, self.pointT) + + def test_negate(self): + negS = -self.pointS + sum = self.pointS + negS + self.assertEqual(sum, self.pointS.point_at_infinity()) + + def test_addition(self): + pointRx = 0x72b13dd4354b6b81745195e98cc5ba6970349191ac476bd4553cf35a545a067e + pointRy = 0x8d585cbb2e1327d75241a8a122d7620dc33b13315aa5c9d46d013011744ac264 + + pointR = self.pointS + self.pointT + self.assertEqual(pointR.x, pointRx) + self.assertEqual(pointR.y, pointRy) + + pai = pointR.point_at_infinity() + + # S + 0 + pointR = self.pointS + pai + self.assertEqual(pointR, self.pointS) + + # 0 + S + pointR = pai + self.pointS + self.assertEqual(pointR, self.pointS) + + # 0 + 0 + pointR = pai + pai + self.assertEqual(pointR, pai) + + def test_inplace_addition(self): + pointRx = 0x72b13dd4354b6b81745195e98cc5ba6970349191ac476bd4553cf35a545a067e + pointRy = 0x8d585cbb2e1327d75241a8a122d7620dc33b13315aa5c9d46d013011744ac264 + + pointR = self.pointS.copy() + pointR += self.pointT + self.assertEqual(pointR.x, pointRx) + self.assertEqual(pointR.y, pointRy) + + pai = pointR.point_at_infinity() + + # S + 0 + pointR = self.pointS.copy() + pointR += pai + self.assertEqual(pointR, self.pointS) + + # 0 + S + pointR = pai.copy() + pointR += self.pointS + self.assertEqual(pointR, self.pointS) + + # 0 + 0 + pointR = pai.copy() + pointR += pai + self.assertEqual(pointR, pai) + + def test_doubling(self): + pointRx = 0x7669e6901606ee3ba1a8eef1e0024c33df6c22f3b17481b82a860ffcdb6127b0 + pointRy = 0xfa878162187a54f6c39f6ee0072f33de389ef3eecd03023de10ca2c1db61d0c7 + + pointR = self.pointS.copy() + pointR.double() + self.assertEqual(pointR.x, pointRx) + self.assertEqual(pointR.y, pointRy) + + # 2*0 + pai = self.pointS.point_at_infinity() + pointR = pai.copy() + pointR.double() + self.assertEqual(pointR, pai) + + # S + S + pointR = self.pointS.copy() + pointR += pointR + self.assertEqual(pointR.x, pointRx) + self.assertEqual(pointR.y, pointRy) + + def test_scalar_multiply(self): + d = 0xc51e4753afdec1e6b6c6a5b992f43f8dd0c7a8933072708b6522468b2ffb06fd + pointRx = 0x51d08d5f2d4278882946d88d83c97d11e62becc3cfc18bedacc89ba34eeca03f + pointRy = 0x75ee68eb8bf626aa5b673ab51f6e744e06f8fcf8a6c0cf3035beca956a7b41d5 + + pointR = self.pointS * d + self.assertEqual(pointR.x, pointRx) + self.assertEqual(pointR.y, pointRy) + + # 0*S + pai = self.pointS.point_at_infinity() + pointR = self.pointS * 0 + self.assertEqual(pointR, pai) + + # -1*S + self.assertRaises(ValueError, lambda: self.pointS * -1) + + # Reverse order + pointR = d * self.pointS + self.assertEqual(pointR.x, pointRx) + self.assertEqual(pointR.y, pointRy) + + pointR = Integer(d) * self.pointS + self.assertEqual(pointR.x, pointRx) + self.assertEqual(pointR.y, pointRy) + + def test_joing_scalar_multiply(self): + d = 0xc51e4753afdec1e6b6c6a5b992f43f8dd0c7a8933072708b6522468b2ffb06fd + e = 0xd37f628ece72a462f0145cbefe3f0b355ee8332d37acdd83a358016aea029db7 + pointRx = 0xd867b4679221009234939221b8046245efcf58413daacbeff857b8588341f6b8 + pointRy = 0xf2504055c03cede12d22720dad69c745106b6607ec7e50dd35d54bd80f615275 + + pointR = self.pointS * d + self.pointT * e + self.assertEqual(pointR.x, pointRx) + self.assertEqual(pointR.y, pointRy) + + def test_sizes(self): + self.assertEqual(self.pointS.size_in_bits(), 256) + self.assertEqual(self.pointS.size_in_bytes(), 32) + + +class TestEccPoint_NIST_P384(unittest.TestCase): + """Tests defined in section 4.4 of https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.204.9073&rep=rep1&type=pdf""" + + pointS = EccPoint( + 0xfba203b81bbd23f2b3be971cc23997e1ae4d89e69cb6f92385dda82768ada415ebab4167459da98e62b1332d1e73cb0e, + 0x5ffedbaefdeba603e7923e06cdb5d0c65b22301429293376d5c6944e3fa6259f162b4788de6987fd59aed5e4b5285e45, + "p384") + + pointT = EccPoint( + 0xaacc05202e7fda6fc73d82f0a66220527da8117ee8f8330ead7d20ee6f255f582d8bd38c5a7f2b40bcdb68ba13d81051, + 0x84009a263fefba7c2c57cffa5db3634d286131afc0fca8d25afa22a7b5dce0d9470da89233cee178592f49b6fecb5092, + "p384") + + def test_curve_attribute(self): + self.assertEqual(self.pointS.curve, "NIST P-384") + + def test_set(self): + pointW = EccPoint(0, 0, "p384") + pointW.set(self.pointS) + self.assertEqual(pointW, self.pointS) + + def test_copy(self): + pointW = self.pointS.copy() + self.assertEqual(pointW, self.pointS) + pointW.set(self.pointT) + self.assertEqual(pointW, self.pointT) + self.assertNotEqual(self.pointS, self.pointT) + + def test_negate(self): + negS = -self.pointS + sum = self.pointS + negS + self.assertEqual(sum, self.pointS.point_at_infinity()) + + def test_addition(self): + pointRx = 0x12dc5ce7acdfc5844d939f40b4df012e68f865b89c3213ba97090a247a2fc009075cf471cd2e85c489979b65ee0b5eed + pointRy = 0x167312e58fe0c0afa248f2854e3cddcb557f983b3189b67f21eee01341e7e9fe67f6ee81b36988efa406945c8804a4b0 + + pointR = self.pointS + self.pointT + self.assertEqual(pointR.x, pointRx) + self.assertEqual(pointR.y, pointRy) + + pai = pointR.point_at_infinity() + + # S + 0 + pointR = self.pointS + pai + self.assertEqual(pointR, self.pointS) + + # 0 + S + pointR = pai + self.pointS + self.assertEqual(pointR, self.pointS) + + # 0 + 0 + pointR = pai + pai + self.assertEqual(pointR, pai) + + def _test_inplace_addition(self): + pointRx = 0x72b13dd4354b6b81745195e98cc5ba6970349191ac476bd4553cf35a545a067e + pointRy = 0x8d585cbb2e1327d75241a8a122d7620dc33b13315aa5c9d46d013011744ac264 + + pointR = self.pointS.copy() + pointR += self.pointT + self.assertEqual(pointR.x, pointRx) + self.assertEqual(pointR.y, pointRy) + + pai = pointR.point_at_infinity() + + # S + 0 + pointR = self.pointS.copy() + pointR += pai + self.assertEqual(pointR, self.pointS) + + # 0 + S + pointR = pai.copy() + pointR += self.pointS + self.assertEqual(pointR, self.pointS) + + # 0 + 0 + pointR = pai.copy() + pointR += pai + self.assertEqual(pointR, pai) + + def test_doubling(self): + pointRx = 0x2a2111b1e0aa8b2fc5a1975516bc4d58017ff96b25e1bdff3c229d5fac3bacc319dcbec29f9478f42dee597b4641504c + pointRy = 0xfa2e3d9dc84db8954ce8085ef28d7184fddfd1344b4d4797343af9b5f9d837520b450f726443e4114bd4e5bdb2f65ddd + + pointR = self.pointS.copy() + pointR.double() + self.assertEqual(pointR.x, pointRx) + self.assertEqual(pointR.y, pointRy) + + # 2*0 + pai = self.pointS.point_at_infinity() + pointR = pai.copy() + pointR.double() + self.assertEqual(pointR, pai) + + # S + S + pointR = self.pointS.copy() + pointR += pointR + self.assertEqual(pointR.x, pointRx) + self.assertEqual(pointR.y, pointRy) + + def test_scalar_multiply(self): + d = 0xa4ebcae5a665983493ab3e626085a24c104311a761b5a8fdac052ed1f111a5c44f76f45659d2d111a61b5fdd97583480 + pointRx = 0xe4f77e7ffeb7f0958910e3a680d677a477191df166160ff7ef6bb5261f791aa7b45e3e653d151b95dad3d93ca0290ef2 + pointRy = 0xac7dee41d8c5f4a7d5836960a773cfc1376289d3373f8cf7417b0c6207ac32e913856612fc9ff2e357eb2ee05cf9667f + + pointR = self.pointS * d + self.assertEqual(pointR.x, pointRx) + self.assertEqual(pointR.y, pointRy) + + # 0*S + pai = self.pointS.point_at_infinity() + pointR = self.pointS * 0 + self.assertEqual(pointR, pai) + + # -1*S + self.assertRaises(ValueError, lambda: self.pointS * -1) + + def test_joing_scalar_multiply(self): + d = 0xa4ebcae5a665983493ab3e626085a24c104311a761b5a8fdac052ed1f111a5c44f76f45659d2d111a61b5fdd97583480 + e = 0xafcf88119a3a76c87acbd6008e1349b29f4ba9aa0e12ce89bcfcae2180b38d81ab8cf15095301a182afbc6893e75385d + pointRx = 0x917ea28bcd641741ae5d18c2f1bd917ba68d34f0f0577387dc81260462aea60e2417b8bdc5d954fc729d211db23a02dc + pointRy = 0x1a29f7ce6d074654d77b40888c73e92546c8f16a5ff6bcbd307f758d4aee684beff26f6742f597e2585c86da908f7186 + + pointR = self.pointS * d + self.pointT * e + self.assertEqual(pointR.x, pointRx) + self.assertEqual(pointR.y, pointRy) + + def test_sizes(self): + self.assertEqual(self.pointS.size_in_bits(), 384) + self.assertEqual(self.pointS.size_in_bytes(), 48) + + +class TestEccPoint_NIST_P521(unittest.TestCase): + """Tests defined in section 4.5 of https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.204.9073&rep=rep1&type=pdf""" + + pointS = EccPoint( + 0x000001d5c693f66c08ed03ad0f031f937443458f601fd098d3d0227b4bf62873af50740b0bb84aa157fc847bcf8dc16a8b2b8bfd8e2d0a7d39af04b089930ef6dad5c1b4, + 0x00000144b7770963c63a39248865ff36b074151eac33549b224af5c8664c54012b818ed037b2b7c1a63ac89ebaa11e07db89fcee5b556e49764ee3fa66ea7ae61ac01823, + "p521") + + pointT = EccPoint( + 0x000000f411f2ac2eb971a267b80297ba67c322dba4bb21cec8b70073bf88fc1ca5fde3ba09e5df6d39acb2c0762c03d7bc224a3e197feaf760d6324006fe3be9a548c7d5, + 0x000001fdf842769c707c93c630df6d02eff399a06f1b36fb9684f0b373ed064889629abb92b1ae328fdb45534268384943f0e9222afe03259b32274d35d1b9584c65e305, + "p521") + + def test_curve_attribute(self): + self.assertEqual(self.pointS.curve, "NIST P-521") + + def test_set(self): + pointW = EccPoint(0, 0) + pointW.set(self.pointS) + self.assertEqual(pointW, self.pointS) + + def test_copy(self): + pointW = self.pointS.copy() + self.assertEqual(pointW, self.pointS) + pointW.set(self.pointT) + self.assertEqual(pointW, self.pointT) + self.assertNotEqual(self.pointS, self.pointT) + + def test_negate(self): + negS = -self.pointS + sum = self.pointS + negS + self.assertEqual(sum, self.pointS.point_at_infinity()) + + def test_addition(self): + pointRx = 0x000001264ae115ba9cbc2ee56e6f0059e24b52c8046321602c59a339cfb757c89a59c358a9a8e1f86d384b3f3b255ea3f73670c6dc9f45d46b6a196dc37bbe0f6b2dd9e9 + pointRy = 0x00000062a9c72b8f9f88a271690bfa017a6466c31b9cadc2fc544744aeb817072349cfddc5ad0e81b03f1897bd9c8c6efbdf68237dc3bb00445979fb373b20c9a967ac55 + + pointR = self.pointS + self.pointT + self.assertEqual(pointR.x, pointRx) + self.assertEqual(pointR.y, pointRy) + + pai = pointR.point_at_infinity() + + # S + 0 + pointR = self.pointS + pai + self.assertEqual(pointR, self.pointS) + + # 0 + S + pointR = pai + self.pointS + self.assertEqual(pointR, self.pointS) + + # 0 + 0 + pointR = pai + pai + self.assertEqual(pointR, pai) + + def test_inplace_addition(self): + pointRx = 0x000001264ae115ba9cbc2ee56e6f0059e24b52c8046321602c59a339cfb757c89a59c358a9a8e1f86d384b3f3b255ea3f73670c6dc9f45d46b6a196dc37bbe0f6b2dd9e9 + pointRy = 0x00000062a9c72b8f9f88a271690bfa017a6466c31b9cadc2fc544744aeb817072349cfddc5ad0e81b03f1897bd9c8c6efbdf68237dc3bb00445979fb373b20c9a967ac55 + + pointR = self.pointS.copy() + pointR += self.pointT + self.assertEqual(pointR.x, pointRx) + self.assertEqual(pointR.y, pointRy) + + pai = pointR.point_at_infinity() + + # S + 0 + pointR = self.pointS.copy() + pointR += pai + self.assertEqual(pointR, self.pointS) + + # 0 + S + pointR = pai.copy() + pointR += self.pointS + self.assertEqual(pointR, self.pointS) + + # 0 + 0 + pointR = pai.copy() + pointR += pai + self.assertEqual(pointR, pai) + + def test_doubling(self): + pointRx = 0x0000012879442f2450c119e7119a5f738be1f1eba9e9d7c6cf41b325d9ce6d643106e9d61124a91a96bcf201305a9dee55fa79136dc700831e54c3ca4ff2646bd3c36bc6 + pointRy = 0x0000019864a8b8855c2479cbefe375ae553e2393271ed36fadfc4494fc0583f6bd03598896f39854abeae5f9a6515a021e2c0eef139e71de610143f53382f4104dccb543 + + pointR = self.pointS.copy() + pointR.double() + self.assertEqual(pointR.x, pointRx) + self.assertEqual(pointR.y, pointRy) + + # 2*0 + pai = self.pointS.point_at_infinity() + pointR = pai.copy() + pointR.double() + self.assertEqual(pointR, pai) + + # S + S + pointR = self.pointS.copy() + pointR += pointR + self.assertEqual(pointR.x, pointRx) + self.assertEqual(pointR.y, pointRy) + + def test_scalar_multiply(self): + d = 0x000001eb7f81785c9629f136a7e8f8c674957109735554111a2a866fa5a166699419bfa9936c78b62653964df0d6da940a695c7294d41b2d6600de6dfcf0edcfc89fdcb1 + pointRx = 0x00000091b15d09d0ca0353f8f96b93cdb13497b0a4bb582ae9ebefa35eee61bf7b7d041b8ec34c6c00c0c0671c4ae063318fb75be87af4fe859608c95f0ab4774f8c95bb + pointRy = 0x00000130f8f8b5e1abb4dd94f6baaf654a2d5810411e77b7423965e0c7fd79ec1ae563c207bd255ee9828eb7a03fed565240d2cc80ddd2cecbb2eb50f0951f75ad87977f + + pointR = self.pointS * d + self.assertEqual(pointR.x, pointRx) + self.assertEqual(pointR.y, pointRy) + + # 0*S + pai = self.pointS.point_at_infinity() + pointR = self.pointS * 0 + self.assertEqual(pointR, pai) + + # -1*S + self.assertRaises(ValueError, lambda: self.pointS * -1) + + def test_joing_scalar_multiply(self): + d = 0x000001eb7f81785c9629f136a7e8f8c674957109735554111a2a866fa5a166699419bfa9936c78b62653964df0d6da940a695c7294d41b2d6600de6dfcf0edcfc89fdcb1 + e = 0x00000137e6b73d38f153c3a7575615812608f2bab3229c92e21c0d1c83cfad9261dbb17bb77a63682000031b9122c2f0cdab2af72314be95254de4291a8f85f7c70412e3 + pointRx = 0x0000009d3802642b3bea152beb9e05fba247790f7fc168072d363340133402f2585588dc1385d40ebcb8552f8db02b23d687cae46185b27528adb1bf9729716e4eba653d + pointRy = 0x0000000fe44344e79da6f49d87c1063744e5957d9ac0a505bafa8281c9ce9ff25ad53f8da084a2deb0923e46501de5797850c61b229023dd9cf7fc7f04cd35ebb026d89d + + pointR = self.pointS * d + pointR += self.pointT * e + self.assertEqual(pointR.x, pointRx) + self.assertEqual(pointR.y, pointRy) + + def test_sizes(self): + self.assertEqual(self.pointS.size_in_bits(), 521) + self.assertEqual(self.pointS.size_in_bytes(), 66) + + +class TestEccPoint_PAI_P192(unittest.TestCase): + """Test vectors from http://point-at-infinity.org/ecc/nisttv""" + + curve = _curves['p192'] + pointG = EccPoint(curve.Gx, curve.Gy, "p192") + + +tv_pai = load_test_vectors(("PublicKey", "ECC"), + "point-at-infinity.org-P192.txt", + "P-192 tests from point-at-infinity.org", + {"k": lambda k: int(k), + "x": lambda x: int(x, 16), + "y": lambda y: int(y, 16)}) or [] +for tv in tv_pai: + def new_test(self, scalar=tv.k, x=tv.x, y=tv.y): + result = self.pointG * scalar + self.assertEqual(result.x, x) + self.assertEqual(result.y, y) + setattr(TestEccPoint_PAI_P192, "test_%d" % tv.count, new_test) + + +class TestEccPoint_PAI_P224(unittest.TestCase): + """Test vectors from http://point-at-infinity.org/ecc/nisttv""" + + curve = _curves['p224'] + pointG = EccPoint(curve.Gx, curve.Gy, "p224") + + +tv_pai = load_test_vectors(("PublicKey", "ECC"), + "point-at-infinity.org-P224.txt", + "P-224 tests from point-at-infinity.org", + {"k": lambda k: int(k), + "x": lambda x: int(x, 16), + "y": lambda y: int(y, 16)}) or [] +for tv in tv_pai: + def new_test(self, scalar=tv.k, x=tv.x, y=tv.y): + result = self.pointG * scalar + self.assertEqual(result.x, x) + self.assertEqual(result.y, y) + setattr(TestEccPoint_PAI_P224, "test_%d" % tv.count, new_test) + + +class TestEccPoint_PAI_P256(unittest.TestCase): + """Test vectors from http://point-at-infinity.org/ecc/nisttv""" + + curve = _curves['p256'] + pointG = EccPoint(curve.Gx, curve.Gy, "p256") + + +tv_pai = load_test_vectors(("PublicKey", "ECC"), + "point-at-infinity.org-P256.txt", + "P-256 tests from point-at-infinity.org", + {"k": lambda k: int(k), + "x": lambda x: int(x, 16), + "y": lambda y: int(y, 16)}) or [] +for tv in tv_pai: + def new_test(self, scalar=tv.k, x=tv.x, y=tv.y): + result = self.pointG * scalar + self.assertEqual(result.x, x) + self.assertEqual(result.y, y) + setattr(TestEccPoint_PAI_P256, "test_%d" % tv.count, new_test) + + +class TestEccPoint_PAI_P384(unittest.TestCase): + """Test vectors from http://point-at-infinity.org/ecc/nisttv""" + + curve = _curves['p384'] + pointG = EccPoint(curve.Gx, curve.Gy, "p384") + + +tv_pai = load_test_vectors(("PublicKey", "ECC"), + "point-at-infinity.org-P384.txt", + "P-384 tests from point-at-infinity.org", + {"k": lambda k: int(k), + "x": lambda x: int(x, 16), + "y": lambda y: int(y, 16)}) or [] +for tv in tv_pai: + def new_test(self, scalar=tv.k, x=tv.x, y=tv.y): + result = self.pointG * scalar + self.assertEqual(result.x, x) + self.assertEqual(result.y, y) + setattr(TestEccPoint_PAI_P384, "test_%d" % tv.count, new_test) + + +class TestEccPoint_PAI_P521(unittest.TestCase): + """Test vectors from http://point-at-infinity.org/ecc/nisttv""" + + curve = _curves['p521'] + pointG = EccPoint(curve.Gx, curve.Gy, "p521") + + +tv_pai = load_test_vectors(("PublicKey", "ECC"), + "point-at-infinity.org-P521.txt", + "P-521 tests from point-at-infinity.org", + {"k": lambda k: int(k), + "x": lambda x: int(x, 16), + "y": lambda y: int(y, 16)}) or [] +for tv in tv_pai: + def new_test(self, scalar=tv.k, x=tv.x, y=tv.y): + result = self.pointG * scalar + self.assertEqual(result.x, x) + self.assertEqual(result.y, y) + setattr(TestEccPoint_PAI_P521, "test_%d" % tv.count, new_test) + + +class TestEccKey_P192(unittest.TestCase): + + def test_private_key(self): + + key = EccKey(curve="P-192", d=1) + self.assertEqual(key.d, 1) + self.assertTrue(key.has_private()) + self.assertEqual(key.pointQ.x, _curves['p192'].Gx) + self.assertEqual(key.pointQ.y, _curves['p192'].Gy) + + point = EccPoint(_curves['p192'].Gx, _curves['p192'].Gy, curve='P-192') + key = EccKey(curve="P-192", d=1, point=point) + self.assertEqual(key.d, 1) + self.assertTrue(key.has_private()) + self.assertEqual(key.pointQ, point) + + # Other names + key = EccKey(curve="secp192r1", d=1) + key = EccKey(curve="prime192v1", d=1) + + def test_public_key(self): + + point = EccPoint(_curves['p192'].Gx, _curves['p192'].Gy, curve='P-192') + key = EccKey(curve="P-192", point=point) + self.assertFalse(key.has_private()) + self.assertEqual(key.pointQ, point) + + def test_public_key_derived(self): + + priv_key = EccKey(curve="P-192", d=3) + pub_key = priv_key.public_key() + self.assertFalse(pub_key.has_private()) + self.assertEqual(priv_key.pointQ, pub_key.pointQ) + + def test_invalid_curve(self): + self.assertRaises(ValueError, lambda: EccKey(curve="P-193", d=1)) + + def test_invalid_d(self): + self.assertRaises(ValueError, lambda: EccKey(curve="P-192", d=0)) + self.assertRaises(ValueError, lambda: EccKey(curve="P-192", + d=_curves['p192'].order)) + + def test_equality(self): + + private_key = ECC.construct(d=3, curve="P-192") + private_key2 = ECC.construct(d=3, curve="P-192") + private_key3 = ECC.construct(d=4, curve="P-192") + + public_key = private_key.public_key() + public_key2 = private_key2.public_key() + public_key3 = private_key3.public_key() + + self.assertEqual(private_key, private_key2) + self.assertNotEqual(private_key, private_key3) + + self.assertEqual(public_key, public_key2) + self.assertNotEqual(public_key, public_key3) + + self.assertNotEqual(public_key, private_key) + + def test_name_consistency(self): + key = ECC.generate(curve='p192') + self.assertIn("curve='NIST P-192'", repr(key)) + self.assertEqual(key.curve, 'NIST P-192') + self.assertEqual(key.public_key().curve, 'NIST P-192') + + +class TestEccKey_P224(unittest.TestCase): + + def test_private_key(self): + + key = EccKey(curve="P-224", d=1) + self.assertEqual(key.d, 1) + self.assertTrue(key.has_private()) + self.assertEqual(key.pointQ.x, _curves['p224'].Gx) + self.assertEqual(key.pointQ.y, _curves['p224'].Gy) + + point = EccPoint(_curves['p224'].Gx, _curves['p224'].Gy, curve='P-224') + key = EccKey(curve="P-224", d=1, point=point) + self.assertEqual(key.d, 1) + self.assertTrue(key.has_private()) + self.assertEqual(key.pointQ, point) + + # Other names + key = EccKey(curve="secp224r1", d=1) + key = EccKey(curve="prime224v1", d=1) + + def test_public_key(self): + + point = EccPoint(_curves['p224'].Gx, _curves['p224'].Gy, curve='P-224') + key = EccKey(curve="P-224", point=point) + self.assertFalse(key.has_private()) + self.assertEqual(key.pointQ, point) + + def test_public_key_derived(self): + + priv_key = EccKey(curve="P-224", d=3) + pub_key = priv_key.public_key() + self.assertFalse(pub_key.has_private()) + self.assertEqual(priv_key.pointQ, pub_key.pointQ) + + def test_invalid_curve(self): + self.assertRaises(ValueError, lambda: EccKey(curve="P-225", d=1)) + + def test_invalid_d(self): + self.assertRaises(ValueError, lambda: EccKey(curve="P-224", d=0)) + self.assertRaises(ValueError, lambda: EccKey(curve="P-224", + d=_curves['p224'].order)) + + def test_equality(self): + + private_key = ECC.construct(d=3, curve="P-224") + private_key2 = ECC.construct(d=3, curve="P-224") + private_key3 = ECC.construct(d=4, curve="P-224") + + public_key = private_key.public_key() + public_key2 = private_key2.public_key() + public_key3 = private_key3.public_key() + + self.assertEqual(private_key, private_key2) + self.assertNotEqual(private_key, private_key3) + + self.assertEqual(public_key, public_key2) + self.assertNotEqual(public_key, public_key3) + + self.assertNotEqual(public_key, private_key) + + def test_name_consistency(self): + key = ECC.generate(curve='p224') + self.assertIn("curve='NIST P-224'", repr(key)) + self.assertEqual(key.curve, 'NIST P-224') + self.assertEqual(key.public_key().curve, 'NIST P-224') + + +class TestEccKey_P256(unittest.TestCase): + + def test_private_key(self): + + key = EccKey(curve="P-256", d=1) + self.assertEqual(key.d, 1) + self.assertTrue(key.has_private()) + self.assertEqual(key.pointQ.x, _curves['p256'].Gx) + self.assertEqual(key.pointQ.y, _curves['p256'].Gy) + + point = EccPoint(_curves['p256'].Gx, _curves['p256'].Gy) + key = EccKey(curve="P-256", d=1, point=point) + self.assertEqual(key.d, 1) + self.assertTrue(key.has_private()) + self.assertEqual(key.pointQ, point) + + # Other names + key = EccKey(curve="secp256r1", d=1) + key = EccKey(curve="prime256v1", d=1) + + # Must not accept d parameter + self.assertRaises(ValueError, EccKey, curve="p256", seed=b'H'*32) + + def test_public_key(self): + + point = EccPoint(_curves['p256'].Gx, _curves['p256'].Gy) + key = EccKey(curve="P-256", point=point) + self.assertFalse(key.has_private()) + self.assertEqual(key.pointQ, point) + + def test_public_key_derived(self): + + priv_key = EccKey(curve="P-256", d=3) + pub_key = priv_key.public_key() + self.assertFalse(pub_key.has_private()) + self.assertEqual(priv_key.pointQ, pub_key.pointQ) + + def test_invalid_curve(self): + self.assertRaises(ValueError, lambda: EccKey(curve="P-257", d=1)) + + def test_invalid_d(self): + self.assertRaises(ValueError, lambda: EccKey(curve="P-256", d=0)) + self.assertRaises(ValueError, lambda: EccKey(curve="P-256", d=_curves['p256'].order)) + + def test_equality(self): + + private_key = ECC.construct(d=3, curve="P-256") + private_key2 = ECC.construct(d=3, curve="P-256") + private_key3 = ECC.construct(d=4, curve="P-256") + + public_key = private_key.public_key() + public_key2 = private_key2.public_key() + public_key3 = private_key3.public_key() + + self.assertEqual(private_key, private_key2) + self.assertNotEqual(private_key, private_key3) + + self.assertEqual(public_key, public_key2) + self.assertNotEqual(public_key, public_key3) + + self.assertNotEqual(public_key, private_key) + + def test_name_consistency(self): + key = ECC.generate(curve='p256') + self.assertIn("curve='NIST P-256'", repr(key)) + self.assertEqual(key.curve, 'NIST P-256') + self.assertEqual(key.public_key().curve, 'NIST P-256') + + +class TestEccKey_P384(unittest.TestCase): + + def test_private_key(self): + + p384 = _curves['p384'] + + key = EccKey(curve="P-384", d=1) + self.assertEqual(key.d, 1) + self.assertTrue(key.has_private()) + self.assertEqual(key.pointQ.x, p384.Gx) + self.assertEqual(key.pointQ.y, p384.Gy) + + point = EccPoint(p384.Gx, p384.Gy, "p384") + key = EccKey(curve="P-384", d=1, point=point) + self.assertEqual(key.d, 1) + self.assertTrue(key.has_private()) + self.assertEqual(key.pointQ, point) + + # Other names + key = EccKey(curve="p384", d=1) + key = EccKey(curve="secp384r1", d=1) + key = EccKey(curve="prime384v1", d=1) + + def test_public_key(self): + + p384 = _curves['p384'] + point = EccPoint(p384.Gx, p384.Gy, 'p384') + key = EccKey(curve="P-384", point=point) + self.assertFalse(key.has_private()) + self.assertEqual(key.pointQ, point) + + def test_public_key_derived(self): + + priv_key = EccKey(curve="P-384", d=3) + pub_key = priv_key.public_key() + self.assertFalse(pub_key.has_private()) + self.assertEqual(priv_key.pointQ, pub_key.pointQ) + + def test_invalid_curve(self): + self.assertRaises(ValueError, lambda: EccKey(curve="P-385", d=1)) + + def test_invalid_d(self): + self.assertRaises(ValueError, lambda: EccKey(curve="P-384", d=0)) + self.assertRaises(ValueError, lambda: EccKey(curve="P-384", + d=_curves['p384'].order)) + + def test_equality(self): + + private_key = ECC.construct(d=3, curve="P-384") + private_key2 = ECC.construct(d=3, curve="P-384") + private_key3 = ECC.construct(d=4, curve="P-384") + + public_key = private_key.public_key() + public_key2 = private_key2.public_key() + public_key3 = private_key3.public_key() + + self.assertEqual(private_key, private_key2) + self.assertNotEqual(private_key, private_key3) + + self.assertEqual(public_key, public_key2) + self.assertNotEqual(public_key, public_key3) + + self.assertNotEqual(public_key, private_key) + + def test_name_consistency(self): + key = ECC.generate(curve='p384') + self.assertIn("curve='NIST P-384'", repr(key)) + self.assertEqual(key.curve, 'NIST P-384') + self.assertEqual(key.public_key().curve, 'NIST P-384') + + +class TestEccKey_P521(unittest.TestCase): + + def test_private_key(self): + + p521 = _curves['p521'] + + key = EccKey(curve="P-521", d=1) + self.assertEqual(key.d, 1) + self.assertTrue(key.has_private()) + self.assertEqual(key.pointQ.x, p521.Gx) + self.assertEqual(key.pointQ.y, p521.Gy) + + point = EccPoint(p521.Gx, p521.Gy, "p521") + key = EccKey(curve="P-521", d=1, point=point) + self.assertEqual(key.d, 1) + self.assertTrue(key.has_private()) + self.assertEqual(key.pointQ, point) + + # Other names + key = EccKey(curve="p521", d=1) + key = EccKey(curve="secp521r1", d=1) + key = EccKey(curve="prime521v1", d=1) + + def test_public_key(self): + + p521 = _curves['p521'] + point = EccPoint(p521.Gx, p521.Gy, 'p521') + key = EccKey(curve="P-384", point=point) + self.assertFalse(key.has_private()) + self.assertEqual(key.pointQ, point) + + def test_public_key_derived(self): + + priv_key = EccKey(curve="P-521", d=3) + pub_key = priv_key.public_key() + self.assertFalse(pub_key.has_private()) + self.assertEqual(priv_key.pointQ, pub_key.pointQ) + + def test_invalid_curve(self): + self.assertRaises(ValueError, lambda: EccKey(curve="P-522", d=1)) + + def test_invalid_d(self): + self.assertRaises(ValueError, lambda: EccKey(curve="P-521", d=0)) + self.assertRaises(ValueError, lambda: EccKey(curve="P-521", + d=_curves['p521'].order)) + + def test_equality(self): + + private_key = ECC.construct(d=3, curve="P-521") + private_key2 = ECC.construct(d=3, curve="P-521") + private_key3 = ECC.construct(d=4, curve="P-521") + + public_key = private_key.public_key() + public_key2 = private_key2.public_key() + public_key3 = private_key3.public_key() + + self.assertEqual(private_key, private_key2) + self.assertNotEqual(private_key, private_key3) + + self.assertEqual(public_key, public_key2) + self.assertNotEqual(public_key, public_key3) + + self.assertNotEqual(public_key, private_key) + + def test_name_consistency(self): + key = ECC.generate(curve='p521') + self.assertIn("curve='NIST P-521'", repr(key)) + self.assertEqual(key.curve, 'NIST P-521') + self.assertEqual(key.public_key().curve, 'NIST P-521') + + +class TestEccModule_P192(unittest.TestCase): + + def test_generate(self): + + key = ECC.generate(curve="P-192") + self.assertTrue(key.has_private()) + self.assertEqual(key.pointQ, EccPoint(_curves['p192'].Gx, + _curves['p192'].Gy, + "P-192") * key.d, + "p192") + + # Other names + ECC.generate(curve="secp192r1") + ECC.generate(curve="prime192v1") + + def test_construct(self): + + key = ECC.construct(curve="P-192", d=1) + self.assertTrue(key.has_private()) + self.assertEqual(key.pointQ, _curves['p192'].G) + + key = ECC.construct(curve="P-192", point_x=_curves['p192'].Gx, + point_y=_curves['p192'].Gy) + self.assertFalse(key.has_private()) + self.assertEqual(key.pointQ, _curves['p192'].G) + + # Other names + ECC.construct(curve="p192", d=1) + ECC.construct(curve="secp192r1", d=1) + ECC.construct(curve="prime192v1", d=1) + + def test_negative_construct(self): + coord = dict(point_x=10, point_y=4) + coordG = dict(point_x=_curves['p192'].Gx, point_y=_curves['p192'].Gy) + + self.assertRaises(ValueError, ECC.construct, curve="P-192", **coord) + self.assertRaises(ValueError, ECC.construct, curve="P-192", d=2, **coordG) + + +class TestEccModule_P224(unittest.TestCase): + + def test_generate(self): + + key = ECC.generate(curve="P-224") + self.assertTrue(key.has_private()) + self.assertEqual(key.pointQ, EccPoint(_curves['p224'].Gx, + _curves['p224'].Gy, + "P-224") * key.d, + "p224") + + # Other names + ECC.generate(curve="secp224r1") + ECC.generate(curve="prime224v1") + + def test_construct(self): + + key = ECC.construct(curve="P-224", d=1) + self.assertTrue(key.has_private()) + self.assertEqual(key.pointQ, _curves['p224'].G) + + key = ECC.construct(curve="P-224", point_x=_curves['p224'].Gx, + point_y=_curves['p224'].Gy) + self.assertFalse(key.has_private()) + self.assertEqual(key.pointQ, _curves['p224'].G) + + # Other names + ECC.construct(curve="p224", d=1) + ECC.construct(curve="secp224r1", d=1) + ECC.construct(curve="prime224v1", d=1) + + def test_negative_construct(self): + coord = dict(point_x=10, point_y=4) + coordG = dict(point_x=_curves['p224'].Gx, point_y=_curves['p224'].Gy) + + self.assertRaises(ValueError, ECC.construct, curve="P-224", **coord) + self.assertRaises(ValueError, ECC.construct, curve="P-224", d=2, **coordG) + + +class TestEccModule_P256(unittest.TestCase): + + def test_generate(self): + + key = ECC.generate(curve="P-256") + self.assertTrue(key.has_private()) + self.assertEqual(key.pointQ, EccPoint(_curves['p256'].Gx, + _curves['p256'].Gy) * key.d, + "p256") + + # Other names + ECC.generate(curve="secp256r1") + ECC.generate(curve="prime256v1") + + def test_construct(self): + + key = ECC.construct(curve="P-256", d=1) + self.assertTrue(key.has_private()) + self.assertEqual(key.pointQ, _curves['p256'].G) + + key = ECC.construct(curve="P-256", point_x=_curves['p256'].Gx, + point_y=_curves['p256'].Gy) + self.assertFalse(key.has_private()) + self.assertEqual(key.pointQ, _curves['p256'].G) + + # Other names + ECC.construct(curve="p256", d=1) + ECC.construct(curve="secp256r1", d=1) + ECC.construct(curve="prime256v1", d=1) + + def test_negative_construct(self): + coord = dict(point_x=10, point_y=4) + coordG = dict(point_x=_curves['p256'].Gx, point_y=_curves['p256'].Gy) + + self.assertRaises(ValueError, ECC.construct, curve="P-256", **coord) + self.assertRaises(ValueError, ECC.construct, curve="P-256", d=2, **coordG) + + +class TestEccModule_P384(unittest.TestCase): + + def test_generate(self): + + curve = _curves['p384'] + key = ECC.generate(curve="P-384") + self.assertTrue(key.has_private()) + self.assertEqual(key.pointQ, EccPoint(curve.Gx, curve.Gy, "p384") * key.d) + + # Other names + ECC.generate(curve="secp384r1") + ECC.generate(curve="prime384v1") + + def test_construct(self): + + curve = _curves['p384'] + key = ECC.construct(curve="P-384", d=1) + self.assertTrue(key.has_private()) + self.assertEqual(key.pointQ, _curves['p384'].G) + + key = ECC.construct(curve="P-384", point_x=curve.Gx, point_y=curve.Gy) + self.assertFalse(key.has_private()) + self.assertEqual(key.pointQ, curve.G) + + # Other names + ECC.construct(curve="p384", d=1) + ECC.construct(curve="secp384r1", d=1) + ECC.construct(curve="prime384v1", d=1) + + def test_negative_construct(self): + coord = dict(point_x=10, point_y=4) + coordG = dict(point_x=_curves['p384'].Gx, point_y=_curves['p384'].Gy) + + self.assertRaises(ValueError, ECC.construct, curve="P-384", **coord) + self.assertRaises(ValueError, ECC.construct, curve="P-384", d=2, **coordG) + + +class TestEccModule_P521(unittest.TestCase): + + def test_generate(self): + + curve = _curves['p521'] + key = ECC.generate(curve="P-521") + self.assertTrue(key.has_private()) + self.assertEqual(key.pointQ, EccPoint(curve.Gx, curve.Gy, "p521") * key.d) + + # Other names + ECC.generate(curve="secp521r1") + ECC.generate(curve="prime521v1") + + def test_construct(self): + + curve = _curves['p521'] + key = ECC.construct(curve="P-521", d=1) + self.assertTrue(key.has_private()) + self.assertEqual(key.pointQ, _curves['p521'].G) + + key = ECC.construct(curve="P-521", point_x=curve.Gx, point_y=curve.Gy) + self.assertFalse(key.has_private()) + self.assertEqual(key.pointQ, curve.G) + + # Other names + ECC.construct(curve="p521", d=1) + ECC.construct(curve="secp521r1", d=1) + ECC.construct(curve="prime521v1", d=1) + + def test_negative_construct(self): + coord = dict(point_x=10, point_y=4) + coordG = dict(point_x=_curves['p521'].Gx, point_y=_curves['p521'].Gy) + + self.assertRaises(ValueError, ECC.construct, curve="P-521", **coord) + self.assertRaises(ValueError, ECC.construct, curve="P-521", d=2, **coordG) + + +def get_tests(config={}): + tests = [] + tests += list_test_cases(TestEccPoint) + tests += list_test_cases(TestEccPoint_NIST_P192) + tests += list_test_cases(TestEccPoint_NIST_P224) + tests += list_test_cases(TestEccPoint_NIST_P256) + tests += list_test_cases(TestEccPoint_NIST_P384) + tests += list_test_cases(TestEccPoint_NIST_P521) + tests += list_test_cases(TestEccPoint_PAI_P192) + tests += list_test_cases(TestEccPoint_PAI_P224) + tests += list_test_cases(TestEccPoint_PAI_P256) + tests += list_test_cases(TestEccPoint_PAI_P384) + tests += list_test_cases(TestEccPoint_PAI_P521) + tests += list_test_cases(TestEccKey_P192) + tests += list_test_cases(TestEccKey_P224) + tests += list_test_cases(TestEccKey_P256) + tests += list_test_cases(TestEccKey_P384) + tests += list_test_cases(TestEccKey_P521) + tests += list_test_cases(TestEccModule_P192) + tests += list_test_cases(TestEccModule_P224) + tests += list_test_cases(TestEccModule_P256) + tests += list_test_cases(TestEccModule_P384) + tests += list_test_cases(TestEccModule_P521) + return tests + + +if __name__ == '__main__': + suite = lambda: unittest.TestSuite(get_tests()) + unittest.main(defaultTest='suite') diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/PublicKey/test_ElGamal.py b/venv/Lib/site-packages/Cryptodome/SelfTest/PublicKey/test_ElGamal.py new file mode 100644 index 0000000..67d2e0b --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/SelfTest/PublicKey/test_ElGamal.py @@ -0,0 +1,217 @@ +# -*- coding: utf-8 -*- +# +# SelfTest/PublicKey/test_ElGamal.py: Self-test for the ElGamal primitive +# +# =================================================================== +# The contents of this file are dedicated to the public domain. To +# the extent that dedication to the public domain is not available, +# everyone is granted a worldwide, perpetual, royalty-free, +# non-exclusive license to exercise all rights associated with the +# contents of this file for any purpose whatsoever. +# No rights are reserved. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# =================================================================== + +"""Self-test suite for Cryptodome.PublicKey.ElGamal""" + +__revision__ = "$Id$" + +import unittest +from Cryptodome.SelfTest.st_common import list_test_cases, a2b_hex, b2a_hex +from Cryptodome import Random +from Cryptodome.PublicKey import ElGamal +from Cryptodome.Util.number import bytes_to_long +from Cryptodome.Util.py3compat import * + +class ElGamalTest(unittest.TestCase): + + # + # Test vectors + # + # There seem to be no real ElGamal test vectors available in the + # public domain. The following test vectors have been generated + # with libgcrypt 1.5.0. + # + # Encryption + tve=[ + { + # 256 bits + 'p' :'BA4CAEAAED8CBE952AFD2126C63EB3B345D65C2A0A73D2A3AD4138B6D09BD933', + 'g' :'05', + 'y' :'60D063600ECED7C7C55146020E7A31C4476E9793BEAED420FEC9E77604CAE4EF', + 'x' :'1D391BA2EE3C37FE1BA175A69B2C73A11238AD77675932', + 'k' :'F5893C5BAB4131264066F57AB3D8AD89E391A0B68A68A1', + 'pt' :'48656C6C6F207468657265', + 'ct1':'32BFD5F487966CEA9E9356715788C491EC515E4ED48B58F0F00971E93AAA5EC7', + 'ct2':'7BE8FBFF317C93E82FCEF9BD515284BA506603FEA25D01C0CB874A31F315EE68' + }, + + { + # 512 bits + 'p' :'F1B18AE9F7B4E08FDA9A04832F4E919D89462FD31BF12F92791A93519F75076D6CE3942689CDFF2F344CAFF0F82D01864F69F3AECF566C774CBACF728B81A227', + 'g' :'07', + 'y' :'688628C676E4F05D630E1BE39D0066178CA7AA83836B645DE5ADD359B4825A12B02EF4252E4E6FA9BEC1DB0BE90F6D7C8629CABB6E531F472B2664868156E20C', + 'x' :'14E60B1BDFD33436C0DA8A22FDC14A2CCDBBED0627CE68', + 'k' :'38DBF14E1F319BDA9BAB33EEEADCAF6B2EA5250577ACE7', + 'pt' :'48656C6C6F207468657265', + 'ct1':'290F8530C2CC312EC46178724F196F308AD4C523CEABB001FACB0506BFED676083FE0F27AC688B5C749AB3CB8A80CD6F7094DBA421FB19442F5A413E06A9772B', + 'ct2':'1D69AAAD1DC50493FB1B8E8721D621D683F3BF1321BE21BC4A43E11B40C9D4D9C80DE3AAC2AB60D31782B16B61112E68220889D53C4C3136EE6F6CE61F8A23A0' + } + ] + + # Signature + tvs=[ + { + # 256 bits + 'p' :'D2F3C41EA66530838A704A48FFAC9334F4701ECE3A97CEE4C69DD01AE7129DD7', + 'g' :'05', + 'y' :'C3F9417DC0DAFEA6A05C1D2333B7A95E63B3F4F28CC962254B3256984D1012E7', + 'x' :'165E4A39BE44D5A2D8B1332D416BC559616F536BC735BB', + 'k' :'C7F0C794A7EAD726E25A47FF8928013680E73C51DD3D7D99BFDA8F492585928F', + 'h' :'48656C6C6F207468657265', + 'sig1':'35CA98133779E2073EF31165AFCDEB764DD54E96ADE851715495F9C635E1E7C2', + 'sig2':'0135B88B1151279FE5D8078D4FC685EE81177EE9802AB123A73925FC1CB059A7', + }, + { + # 512 bits + 'p' :'E24CF3A4B8A6AF749DCA6D714282FE4AABEEE44A53BB6ED15FBE32B5D3C3EF9CC4124A2ECA331F3C1C1B667ACA3766825217E7B5F9856648D95F05330C6A19CF', + 'g' :'0B', + 'y' :'2AD3A1049CA5D4ED207B2431C79A8719BB4073D4A94E450EA6CEE8A760EB07ADB67C0D52C275EE85D7B52789061EE45F2F37D9B2AE522A51C28329766BFE68AC', + 'x' :'16CBB4F46D9ECCF24FF9F7E63CAA3BD8936341555062AB', + 'k' :'8A3D89A4E429FD2476D7D717251FB79BF900FFE77444E6BB8299DC3F84D0DD57ABAB50732AE158EA52F5B9E7D8813E81FD9F79470AE22F8F1CF9AEC820A78C69', + 'h' :'48656C6C6F207468657265', + 'sig1':'BE001AABAFFF976EC9016198FBFEA14CBEF96B000CCC0063D3324016F9E91FE80D8F9325812ED24DDB2B4D4CF4430B169880B3CE88313B53255BD4EC0378586F', + 'sig2':'5E266F3F837BA204E3BBB6DBECC0611429D96F8C7CE8F4EFDF9D4CB681C2A954468A357BF4242CEC7418B51DFC081BCD21299EF5B5A0DDEF3A139A1817503DDE', + } + ] + + def test_generate_180(self): + self._test_random_key(180) + + def test_encryption(self): + for tv in self.tve: + d = self.convert_tv(tv, True) + key = ElGamal.construct(d['key']) + ct = key._encrypt(d['pt'], d['k']) + self.assertEqual(ct[0], d['ct1']) + self.assertEqual(ct[1], d['ct2']) + + def test_decryption(self): + for tv in self.tve: + d = self.convert_tv(tv, True) + key = ElGamal.construct(d['key']) + pt = key._decrypt((d['ct1'], d['ct2'])) + self.assertEqual(pt, d['pt']) + + def test_signing(self): + for tv in self.tvs: + d = self.convert_tv(tv, True) + key = ElGamal.construct(d['key']) + sig1, sig2 = key._sign(d['h'], d['k']) + self.assertEqual(sig1, d['sig1']) + self.assertEqual(sig2, d['sig2']) + + def test_verification(self): + for tv in self.tvs: + d = self.convert_tv(tv, True) + key = ElGamal.construct(d['key']) + # Positive test + res = key._verify( d['h'], (d['sig1'],d['sig2']) ) + self.assertTrue(res) + # Negative test + res = key._verify( d['h'], (d['sig1']+1,d['sig2']) ) + self.assertFalse(res) + + def test_bad_key3(self): + tup = tup0 = list(self.convert_tv(self.tvs[0], 1)['key'])[:3] + tup[0] += 1 # p += 1 (not prime) + self.assertRaises(ValueError, ElGamal.construct, tup) + + tup = tup0 + tup[1] = 1 # g = 1 + self.assertRaises(ValueError, ElGamal.construct, tup) + + tup = tup0 + tup[2] = tup[0]*2 # y = 2*p + self.assertRaises(ValueError, ElGamal.construct, tup) + + def test_bad_key4(self): + tup = tup0 = list(self.convert_tv(self.tvs[0], 1)['key']) + tup[3] += 1 # x += 1 + self.assertRaises(ValueError, ElGamal.construct, tup) + + def convert_tv(self, tv, as_longs=0): + """Convert a test vector from textual form (hexadecimal ascii + to either integers or byte strings.""" + key_comps = 'p','g','y','x' + tv2 = {} + for c in tv.keys(): + tv2[c] = a2b_hex(tv[c]) + if as_longs or c in key_comps or c in ('sig1','sig2'): + tv2[c] = bytes_to_long(tv2[c]) + tv2['key']=[] + for c in key_comps: + tv2['key'] += [tv2[c]] + del tv2[c] + return tv2 + + def _test_random_key(self, bits): + elgObj = ElGamal.generate(bits, Random.new().read) + self._check_private_key(elgObj) + self._exercise_primitive(elgObj) + pub = elgObj.publickey() + self._check_public_key(pub) + self._exercise_public_primitive(elgObj) + + def _check_private_key(self, elgObj): + + # Check capabilities + self.assertTrue(elgObj.has_private()) + + # Sanity check key data + self.assertTrue(1 +# +# =================================================================== +# The contents of this file are dedicated to the public domain. To +# the extent that dedication to the public domain is not available, +# everyone is granted a worldwide, perpetual, royalty-free, +# non-exclusive license to exercise all rights associated with the +# contents of this file for any purpose whatsoever. +# No rights are reserved. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# =================================================================== + +"""Self-test suite for Cryptodome.PublicKey.RSA""" + +__revision__ = "$Id$" + +import os +import pickle +from pickle import PicklingError +from Cryptodome.Util.py3compat import * + +import unittest +from Cryptodome.SelfTest.st_common import list_test_cases, a2b_hex, b2a_hex + +class RSATest(unittest.TestCase): + # Test vectors from "RSA-OAEP and RSA-PSS test vectors (.zip file)" + # ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1-vec.zip + # See RSADSI's PKCS#1 page at + # http://www.rsa.com/rsalabs/node.asp?id=2125 + + # from oaep-int.txt + + # TODO: PyCryptodome treats the message as starting *after* the leading "00" + # TODO: That behaviour should probably be changed in the future. + plaintext = """ + eb 7a 19 ac e9 e3 00 63 50 e3 29 50 4b 45 e2 + ca 82 31 0b 26 dc d8 7d 5c 68 f1 ee a8 f5 52 67 + c3 1b 2e 8b b4 25 1f 84 d7 e0 b2 c0 46 26 f5 af + f9 3e dc fb 25 c9 c2 b3 ff 8a e1 0e 83 9a 2d db + 4c dc fe 4f f4 77 28 b4 a1 b7 c1 36 2b aa d2 9a + b4 8d 28 69 d5 02 41 21 43 58 11 59 1b e3 92 f9 + 82 fb 3e 87 d0 95 ae b4 04 48 db 97 2f 3a c1 4f + 7b c2 75 19 52 81 ce 32 d2 f1 b7 6d 4d 35 3e 2d + """ + + ciphertext = """ + 12 53 e0 4d c0 a5 39 7b b4 4a 7a b8 7e 9b f2 a0 + 39 a3 3d 1e 99 6f c8 2a 94 cc d3 00 74 c9 5d f7 + 63 72 20 17 06 9e 52 68 da 5d 1c 0b 4f 87 2c f6 + 53 c1 1d f8 23 14 a6 79 68 df ea e2 8d ef 04 bb + 6d 84 b1 c3 1d 65 4a 19 70 e5 78 3b d6 eb 96 a0 + 24 c2 ca 2f 4a 90 fe 9f 2e f5 c9 c1 40 e5 bb 48 + da 95 36 ad 87 00 c8 4f c9 13 0a de a7 4e 55 8d + 51 a7 4d df 85 d8 b5 0d e9 68 38 d6 06 3e 09 55 + """ + + modulus = """ + bb f8 2f 09 06 82 ce 9c 23 38 ac 2b 9d a8 71 f7 + 36 8d 07 ee d4 10 43 a4 40 d6 b6 f0 74 54 f5 1f + b8 df ba af 03 5c 02 ab 61 ea 48 ce eb 6f cd 48 + 76 ed 52 0d 60 e1 ec 46 19 71 9d 8a 5b 8b 80 7f + af b8 e0 a3 df c7 37 72 3e e6 b4 b7 d9 3a 25 84 + ee 6a 64 9d 06 09 53 74 88 34 b2 45 45 98 39 4e + e0 aa b1 2d 7b 61 a5 1f 52 7a 9a 41 f6 c1 68 7f + e2 53 72 98 ca 2a 8f 59 46 f8 e5 fd 09 1d bd cb + """ + + e = 0x11 # public exponent + + prime_factor = """ + c9 7f b1 f0 27 f4 53 f6 34 12 33 ea aa d1 d9 35 + 3f 6c 42 d0 88 66 b1 d0 5a 0f 20 35 02 8b 9d 86 + 98 40 b4 16 66 b4 2e 92 ea 0d a3 b4 32 04 b5 cf + ce 33 52 52 4d 04 16 a5 a4 41 e7 00 af 46 15 03 + """ + + def setUp(self): + global RSA, Random, bytes_to_long + from Cryptodome.PublicKey import RSA + from Cryptodome import Random + from Cryptodome.Util.number import bytes_to_long, inverse + self.n = bytes_to_long(a2b_hex(self.modulus)) + self.p = bytes_to_long(a2b_hex(self.prime_factor)) + + # Compute q, d, and u from n, e, and p + self.q = self.n // self.p + self.d = inverse(self.e, (self.p-1)*(self.q-1)) + self.u = inverse(self.p, self.q) # u = e**-1 (mod q) + + self.rsa = RSA + + def test_generate_1arg(self): + """RSA (default implementation) generated key (1 argument)""" + rsaObj = self.rsa.generate(1024) + self._check_private_key(rsaObj) + self._exercise_primitive(rsaObj) + pub = rsaObj.public_key() + self._check_public_key(pub) + self._exercise_public_primitive(rsaObj) + + def test_generate_2arg(self): + """RSA (default implementation) generated key (2 arguments)""" + rsaObj = self.rsa.generate(1024, Random.new().read) + self._check_private_key(rsaObj) + self._exercise_primitive(rsaObj) + pub = rsaObj.public_key() + self._check_public_key(pub) + self._exercise_public_primitive(rsaObj) + + def test_generate_3args(self): + rsaObj = self.rsa.generate(1024, Random.new().read,e=65537) + self._check_private_key(rsaObj) + self._exercise_primitive(rsaObj) + pub = rsaObj.public_key() + self._check_public_key(pub) + self._exercise_public_primitive(rsaObj) + self.assertEqual(65537,rsaObj.e) + + def test_construct_2tuple(self): + """RSA (default implementation) constructed key (2-tuple)""" + pub = self.rsa.construct((self.n, self.e)) + self._check_public_key(pub) + self._check_encryption(pub) + + def test_construct_3tuple(self): + """RSA (default implementation) constructed key (3-tuple)""" + rsaObj = self.rsa.construct((self.n, self.e, self.d)) + self._check_encryption(rsaObj) + self._check_decryption(rsaObj) + + def test_construct_4tuple(self): + """RSA (default implementation) constructed key (4-tuple)""" + rsaObj = self.rsa.construct((self.n, self.e, self.d, self.p)) + self._check_encryption(rsaObj) + self._check_decryption(rsaObj) + + def test_construct_5tuple(self): + """RSA (default implementation) constructed key (5-tuple)""" + rsaObj = self.rsa.construct((self.n, self.e, self.d, self.p, self.q)) + self._check_private_key(rsaObj) + self._check_encryption(rsaObj) + self._check_decryption(rsaObj) + + def test_construct_6tuple(self): + """RSA (default implementation) constructed key (6-tuple)""" + rsaObj = self.rsa.construct((self.n, self.e, self.d, self.p, self.q, self.u)) + self._check_private_key(rsaObj) + self._check_encryption(rsaObj) + self._check_decryption(rsaObj) + + def test_construct_bad_key2(self): + tup = (self.n, 1) + self.assertRaises(ValueError, self.rsa.construct, tup) + + # An even modulus is wrong + tup = (self.n+1, self.e) + self.assertRaises(ValueError, self.rsa.construct, tup) + + def test_construct_bad_key3(self): + tup = (self.n, self.e, self.d+1) + self.assertRaises(ValueError, self.rsa.construct, tup) + + def test_construct_bad_key5(self): + tup = (self.n, self.e, self.d, self.p, self.p) + self.assertRaises(ValueError, self.rsa.construct, tup) + + tup = (self.p*self.p, self.e, self.p, self.p) + self.assertRaises(ValueError, self.rsa.construct, tup) + + tup = (self.p*self.p, 3, self.p, self.q) + self.assertRaises(ValueError, self.rsa.construct, tup) + + def test_construct_bad_key6(self): + tup = (self.n, self.e, self.d, self.p, self.q, 10) + self.assertRaises(ValueError, self.rsa.construct, tup) + + from Cryptodome.Util.number import inverse + tup = (self.n, self.e, self.d, self.p, self.q, inverse(self.q, self.p)) + self.assertRaises(ValueError, self.rsa.construct, tup) + + def test_factoring(self): + rsaObj = self.rsa.construct([self.n, self.e, self.d]) + self.assertTrue(rsaObj.p==self.p or rsaObj.p==self.q) + self.assertTrue(rsaObj.q==self.p or rsaObj.q==self.q) + self.assertTrue(rsaObj.q*rsaObj.p == self.n) + + self.assertRaises(ValueError, self.rsa.construct, [self.n, self.e, self.n-1]) + + def test_repr(self): + rsaObj = self.rsa.construct((self.n, self.e, self.d, self.p, self.q)) + repr(rsaObj) + + def test_serialization(self): + """RSA keys are unpickable""" + + rsa_key = self.rsa.generate(1024) + self.assertRaises(PicklingError, pickle.dumps, rsa_key) + + def test_raw_rsa_boundary(self): + # The argument of every RSA raw operation (encrypt/decrypt) must be + # non-negative and no larger than the modulus + rsa_obj = self.rsa.generate(1024) + + self.assertRaises(ValueError, rsa_obj._decrypt, rsa_obj.n) + self.assertRaises(ValueError, rsa_obj._decrypt_to_bytes, rsa_obj.n) + self.assertRaises(ValueError, rsa_obj._encrypt, rsa_obj.n) + + self.assertRaises(ValueError, rsa_obj._decrypt, -1) + self.assertRaises(ValueError, rsa_obj._decrypt_to_bytes, -1) + self.assertRaises(ValueError, rsa_obj._encrypt, -1) + + def test_size(self): + pub = self.rsa.construct((self.n, self.e)) + self.assertEqual(pub.size_in_bits(), 1024) + self.assertEqual(pub.size_in_bytes(), 128) + + def _check_private_key(self, rsaObj): + from Cryptodome.Math.Numbers import Integer + + # Check capabilities + self.assertEqual(1, rsaObj.has_private()) + + # Sanity check key data + self.assertEqual(rsaObj.n, rsaObj.p * rsaObj.q) # n = pq + lcm = int(Integer(rsaObj.p-1).lcm(rsaObj.q-1)) + self.assertEqual(1, rsaObj.d * rsaObj.e % lcm) # ed = 1 (mod LCM(p-1, q-1)) + self.assertEqual(1, rsaObj.p * rsaObj.u % rsaObj.q) # pu = 1 (mod q) + self.assertEqual(1, rsaObj.p > 1) # p > 1 + self.assertEqual(1, rsaObj.q > 1) # q > 1 + self.assertEqual(1, rsaObj.e > 1) # e > 1 + self.assertEqual(1, rsaObj.d > 1) # d > 1 + + self.assertEqual(rsaObj.u, rsaObj.invp) + self.assertEqual(1, rsaObj.q * rsaObj.invq % rsaObj.p) + + def _check_public_key(self, rsaObj): + ciphertext = a2b_hex(self.ciphertext) + + # Check capabilities + self.assertEqual(0, rsaObj.has_private()) + + # Check rsaObj.[ne] -> rsaObj.[ne] mapping + self.assertEqual(rsaObj.n, rsaObj.n) + self.assertEqual(rsaObj.e, rsaObj.e) + + # Check that private parameters are all missing + self.assertEqual(0, hasattr(rsaObj, 'd')) + self.assertEqual(0, hasattr(rsaObj, 'p')) + self.assertEqual(0, hasattr(rsaObj, 'q')) + self.assertEqual(0, hasattr(rsaObj, 'u')) + + # Sanity check key data + self.assertEqual(1, rsaObj.e > 1) # e > 1 + + # Public keys should not be able to sign or decrypt + self.assertRaises(TypeError, rsaObj._decrypt, + bytes_to_long(ciphertext)) + self.assertRaises(TypeError, rsaObj._decrypt_to_bytes, + bytes_to_long(ciphertext)) + + # Check __eq__ and __ne__ + self.assertEqual(rsaObj.public_key() == rsaObj.public_key(),True) # assert_ + self.assertEqual(rsaObj.public_key() != rsaObj.public_key(),False) # assertFalse + + self.assertEqual(rsaObj.publickey(), rsaObj.public_key()) + + def _exercise_primitive(self, rsaObj): + # Since we're using a randomly-generated key, we can't check the test + # vector, but we can make sure encryption and decryption are inverse + # operations. + ciphertext = bytes_to_long(a2b_hex(self.ciphertext)) + + # Test decryption + plaintext = rsaObj._decrypt(ciphertext) + + # Test encryption (2 arguments) + new_ciphertext2 = rsaObj._encrypt(plaintext) + self.assertEqual(ciphertext, new_ciphertext2) + + def _exercise_public_primitive(self, rsaObj): + plaintext = a2b_hex(self.plaintext) + + # Test encryption (2 arguments) + new_ciphertext2 = rsaObj._encrypt(bytes_to_long(plaintext)) + + def _check_encryption(self, rsaObj): + plaintext = a2b_hex(self.plaintext) + ciphertext = a2b_hex(self.ciphertext) + + # Test encryption + new_ciphertext2 = rsaObj._encrypt(bytes_to_long(plaintext)) + self.assertEqual(bytes_to_long(ciphertext), new_ciphertext2) + + def _check_decryption(self, rsaObj): + plaintext = bytes_to_long(a2b_hex(self.plaintext)) + ciphertext = bytes_to_long(a2b_hex(self.ciphertext)) + + # Test plain decryption + new_plaintext = rsaObj._decrypt(ciphertext) + self.assertEqual(plaintext, new_plaintext) + + +def get_tests(config={}): + tests = [] + tests += list_test_cases(RSATest) + return tests + +if __name__ == '__main__': + suite = lambda: unittest.TestSuite(get_tests()) + unittest.main(defaultTest='suite') + +# vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/PublicKey/test_import_Curve25519.py b/venv/Lib/site-packages/Cryptodome/SelfTest/PublicKey/test_import_Curve25519.py new file mode 100644 index 0000000..2401eac --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/SelfTest/PublicKey/test_import_Curve25519.py @@ -0,0 +1,385 @@ +# =================================================================== +# +# Copyright (c) 2024, Helder Eijs +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# =================================================================== + +import os +import errno +import warnings +import unittest +from binascii import unhexlify +from unittest import SkipTest + +from Cryptodome.SelfTest.st_common import list_test_cases +from Cryptodome.Util.py3compat import tostr, FileNotFoundError +from Cryptodome.Util.asn1 import DerSequence, DerBitString +from Cryptodome.Hash import SHAKE128 + +from Cryptodome.PublicKey import ECC + +try: + import pycryptodome_test_vectors # type: ignore + test_vectors_available = True +except ImportError: + test_vectors_available = False + + +def load_file(file_name, mode="rb"): + results = None + + try: + if not test_vectors_available: + raise FileNotFoundError(errno.ENOENT, + os.strerror(errno.ENOENT), + file_name) + + dir_comps = ("PublicKey", "ECC") + init_dir = os.path.dirname(pycryptodome_test_vectors.__file__) + full_file_name = os.path.join(os.path.join(init_dir, *dir_comps), file_name) + with open(full_file_name, mode) as file_in: + results = file_in.read() + + except FileNotFoundError: + warnings.warn("Warning: skipping extended tests for ECC", + UserWarning, + stacklevel=2) + + if results is None: + raise SkipTest("Missing %s" % file_name) + + return results + + +def compact(lines): + ext = b"".join(lines) + return unhexlify(tostr(ext).replace(" ", "").replace(":", "")) + + +def create_ref_keys_x25519(): + key_lines = load_file("ecc_x25519.txt").splitlines() + seed = compact(key_lines[5:8]) + key = ECC.construct(curve="Curve25519", seed=seed) + return (key, key.public_key()) + + +def get_fixed_prng(): + return SHAKE128.new().update(b"SEED").read + + +def extract_bitstring_from_spki(data): + seq = DerSequence() + seq.decode(data) + bs = DerBitString() + bs.decode(seq[1]) + return bs.value + + +class TestImport(unittest.TestCase): + + def test_empty(self): + self.assertRaises(ValueError, ECC.import_key, b"") + + def test_mismatch(self): + # Private key with X448 Object ID but X25519 key + mismatch_hex = "302e020100300506032b656f042204207009906b64ec727d5cb5c23007bf0425b3fd79014c6cd62ca3dddfcf0f278f79" + mismatch = unhexlify(mismatch_hex) + self.assertRaises(ValueError, ECC.import_key, mismatch) + + +class TestImport_Curve25519(unittest.TestCase): + + def __init__(self, *args, **kwargs): + super(TestImport_Curve25519, self).__init__(*args, **kwargs) + self.ref_private, self.ref_public = create_ref_keys_x25519() + + def test_import_public_der(self): + key_file = load_file("ecc_x25519_public.der") + + key = ECC._import_subjectPublicKeyInfo(key_file) + self.assertEqual(self.ref_public, key) + + key = ECC._import_der(key_file, None) + self.assertEqual(self.ref_public, key) + + key = ECC.import_key(key_file) + self.assertEqual(self.ref_public, key) + + def test_import_pkcs8_der(self): + key_file = load_file("ecc_x25519_private.der") + + key = ECC._import_der(key_file, None) + self.assertEqual(self.ref_private, key) + + key = ECC.import_key(key_file) + self.assertEqual(self.ref_private, key) + + def test_import_private_pkcs8_encrypted_1(self): + key_file = load_file("ecc_x25519_private_p8.der") + + key = ECC._import_der(key_file, "secret") + self.assertEqual(self.ref_private, key) + + key = ECC.import_key(key_file, "secret") + self.assertEqual(self.ref_private, key) + + def test_import_private_pkcs8_encrypted_2(self): + key_file = load_file("ecc_x25519_private_p8.pem") + + key = ECC.import_key(key_file, "secret") + self.assertEqual(self.ref_private, key) + + def test_import_private_pkcs8_encrypted_3(self): + key_file = load_file("ecc_x25519_private_p8_2.der") + + key = ECC._import_der(key_file, "secret") + self.assertEqual(self.ref_private, key) + + key = ECC.import_key(key_file, "secret") + self.assertEqual(self.ref_private, key) + + def test_import_x509_der(self): + key_file = load_file("ecc_x25519_x509.der") + + key = ECC._import_der(key_file, None) + self.assertEqual(self.ref_public, key) + + key = ECC.import_key(key_file) + self.assertEqual(self.ref_public, key) + + def test_import_public_pem(self): + key_file = load_file("ecc_x25519_public.pem") + + key = ECC.import_key(key_file) + self.assertEqual(self.ref_public, key) + + def test_import_private_pem(self): + key_file = load_file("ecc_x25519_private.pem") + + key = ECC.import_key(key_file) + self.assertEqual(self.ref_private, key) + + def test_import_private_pem_encrypted(self): + for algo in "des3", "aes128", "aes192", "aes256": + key_file = load_file("ecc_x25519_private_enc_%s.pem" % algo) + + key = ECC.import_key(key_file, "secret") + self.assertEqual(self.ref_private, key) + + key = ECC.import_key(tostr(key_file), b"secret") + self.assertEqual(self.ref_private, key) + + def test_import_x509_pem(self): + key_file = load_file("ecc_x25519_x509.pem") + + key = ECC.import_key(key_file) + self.assertEqual(self.ref_public, key) + + +class TestExport_Curve25519(unittest.TestCase): + + def __init__(self, *args, **kwargs): + super(TestExport_Curve25519, self).__init__(*args, **kwargs) + self.ref_private, self.ref_public = create_ref_keys_x25519() + + def test_export_public_der(self): + key_file = load_file("ecc_x25519_public.der") + + encoded = self.ref_public._export_subjectPublicKeyInfo(True) + self.assertEqual(key_file, encoded) + + encoded = self.ref_public.export_key(format="DER") + self.assertEqual(key_file, encoded) + + encoded = self.ref_public.export_key(format="DER", compress=False) + self.assertEqual(key_file, encoded) + + def test_export_private_pkcs8_clear(self): + key_file = load_file("ecc_x25519_private.der") + + encoded = self.ref_private._export_pkcs8() + self.assertEqual(key_file, encoded) + + # --- + + encoded = self.ref_private.export_key(format="DER") + self.assertEqual(key_file, encoded) + + self.assertRaises(ValueError, self.ref_private.export_key, + format="DER", use_pkcs8=False) + + def test_export_private_pkcs8_encrypted(self): + encoded = self.ref_private._export_pkcs8(passphrase="secret", + protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") + + # This should prove that the output is password-protected + self.assertRaises(ValueError, ECC._import_pkcs8, encoded, None) + + decoded = ECC._import_pkcs8(encoded, "secret") + self.assertEqual(self.ref_private, decoded) + + # --- + + encoded = self.ref_private.export_key(format="DER", + passphrase="secret", + protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") + decoded = ECC.import_key(encoded, "secret") + self.assertEqual(self.ref_private, decoded) + + # --- + + encoded = self.ref_private.export_key(format="DER", + passphrase="secret", + protection="PBKDF2WithHMAC-SHA256AndAES128-CBC", + prot_params={'iteration_count': 123}) + decoded = ECC.import_key(encoded, "secret") + self.assertEqual(self.ref_private, decoded) + + def test_export_public_pem(self): + key_file_ref = load_file("ecc_x25519_public.pem", "rt").strip() + key_file = self.ref_public.export_key(format="PEM").strip() + self.assertEqual(key_file_ref, key_file) + + def test_export_private_pem_clear(self): + key_file = load_file("ecc_x25519_private.pem", "rt").strip() + encoded = self.ref_private.export_key(format="PEM").strip() + self.assertEqual(key_file, encoded) + + def test_export_private_pem_encrypted(self): + encoded = self.ref_private.export_key(format="PEM", + passphrase=b"secret", + protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") + + # This should prove that the output is password-protected + self.assertRaises(ValueError, ECC.import_key, encoded) + + assert "ENCRYPTED PRIVATE KEY" in encoded + + decoded = ECC.import_key(encoded, "secret") + self.assertEqual(self.ref_private, decoded) + + def test_export_raw(self): + encoded = self.ref_public.export_key(format='raw') + self.assertEqual(len(encoded), 32) + self.assertEqual(encoded, unhexlify(b'ff7561ef60c9c8a757f6d6372ec14142c9be208d0e719136d8d3c715dfcf7e15')) + + def test_prng(self): + # Test that password-protected containers use the provided PRNG + encoded1 = self.ref_private.export_key(format="PEM", + passphrase="secret", + protection="PBKDF2WithHMAC-SHA1AndAES128-CBC", + randfunc=get_fixed_prng()) + encoded2 = self.ref_private.export_key(format="PEM", + passphrase="secret", + protection="PBKDF2WithHMAC-SHA1AndAES128-CBC", + randfunc=get_fixed_prng()) + self.assertEqual(encoded1, encoded2) + + def test_byte_or_string_passphrase(self): + encoded1 = self.ref_private.export_key(format="PEM", + passphrase="secret", + protection="PBKDF2WithHMAC-SHA1AndAES128-CBC", + randfunc=get_fixed_prng()) + encoded2 = self.ref_private.export_key(format="PEM", + passphrase=b"secret", + protection="PBKDF2WithHMAC-SHA1AndAES128-CBC", + randfunc=get_fixed_prng()) + self.assertEqual(encoded1, encoded2) + + def test_error_params1(self): + # Unknown format + self.assertRaises(ValueError, self.ref_private.export_key, format="XXX") + + # Missing 'protection' parameter when PKCS#8 is used + self.assertRaises(ValueError, + self.ref_private.export_key, + format="PEM", + passphrase="secret") + + # Empty password + self.assertRaises(ValueError, + self.ref_private.export_key, + format="PEM", + passphrase="", + use_pkcs8=False) + self.assertRaises(ValueError, + self.ref_private.export_key, + format="PEM", + passphrase="", + protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") + + # No private keys with OpenSSH + self.assertRaises(ValueError, + self.ref_private.export_key, + format="OpenSSH", + passphrase="secret") + + +class TestImport_Curve25519_Weak(unittest.TestCase): + + def test_weak_pem(self): + + p = 2**255 - 19 + weak_x = (0, + 1, + 325606250916557431795983626356110631294008115727848805560023387167927233504, + 39382357235489614581723060781553021112529911719440698176882885853963445705823, + p - 1, + p, + p + 1, + p + 325606250916557431795983626356110631294008115727848805560023387167927233504, + p + 39382357235489614581723060781553021112529911719440698176882885853963445705823, + p * 2 - 1, + p * 2, + p * 2 + 1) + + for x in weak_x: + low_order_point = ECC.EccXPoint(x, "curve25519") + weak_key = ECC.EccKey(point=low_order_point, curve="curve25519") + encoded = weak_key.export_key(format="PEM") + + self.assertRaises(ValueError, + ECC.import_key, + encoded) + + +def get_tests(config={}): + tests = [] + try: + tests += list_test_cases(TestImport) + tests += list_test_cases(TestImport_Curve25519) + tests += list_test_cases(TestExport_Curve25519) + tests += list_test_cases(TestImport_Curve25519_Weak) + except SkipTest: + pass + return tests + + +if __name__ == '__main__': + def suit(): + return unittest.TestSuite(get_tests()) + unittest.main(defaultTest='suite') diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/PublicKey/test_import_Curve448.py b/venv/Lib/site-packages/Cryptodome/SelfTest/PublicKey/test_import_Curve448.py new file mode 100644 index 0000000..e1b343b --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/SelfTest/PublicKey/test_import_Curve448.py @@ -0,0 +1,351 @@ +# This file is licensed under the BSD 2-Clause License. +# See https://opensource.org/licenses/BSD-2-Clause for details. + +import os +import errno +import warnings +import unittest +from binascii import unhexlify +from unittest import SkipTest + +from Cryptodome.SelfTest.st_common import list_test_cases +from Cryptodome.Util.py3compat import tostr, FileNotFoundError +from Cryptodome.Util.asn1 import DerSequence, DerBitString +from Cryptodome.Hash import SHAKE128 + +from Cryptodome.PublicKey import ECC + +try: + import pycryptodome_test_vectors # type: ignore + test_vectors_available = True +except ImportError: + test_vectors_available = False + + +def load_file(file_name, mode="rb"): + results = None + + try: + if not test_vectors_available: + raise FileNotFoundError(errno.ENOENT, + os.strerror(errno.ENOENT), + file_name) + + dir_comps = ("PublicKey", "ECC") + init_dir = os.path.dirname(pycryptodome_test_vectors.__file__) + full_file_name = os.path.join(os.path.join(init_dir, *dir_comps), file_name) + with open(full_file_name, mode) as file_in: + results = file_in.read() + + except FileNotFoundError: + warnings.warn("Warning: skipping extended tests for ECC", + UserWarning, + stacklevel=2) + + if results is None: + raise SkipTest("Missing %s" % file_name) + + return results + + +def compact(lines): + ext = b"".join(lines) + return unhexlify(tostr(ext).replace(" ", "").replace(":", "")) + + +def create_ref_keys_x448(): + key_lines = load_file("ecc_x448.txt").splitlines() + seed = compact(key_lines[6:10]) + key = ECC.construct(curve="Curve448", seed=seed) + return (key, key.public_key()) + + +def get_fixed_prng(): + return SHAKE128.new().update(b"SEED").read + + +def extract_bitstring_from_spki(data): + seq = DerSequence() + seq.decode(data) + bs = DerBitString() + bs.decode(seq[1]) + return bs.value + + +class TestImport(unittest.TestCase): + + def test_empty(self): + self.assertRaises(ValueError, ECC.import_key, b"") + + def test_mismatch(self): + # Private key with X448 Object ID but X448 key + mismatch_hex = "302e020100300506032b656f042204207009906b64ec727d5cb5c23007bf0425b3fd79014c6cd62ca3dddfcf0f278f79" + mismatch = unhexlify(mismatch_hex) + self.assertRaises(ValueError, ECC.import_key, mismatch) + + +class TestImport_Curve448(unittest.TestCase): + + def __init__(self, *args, **kwargs): + super(TestImport_Curve448, self).__init__(*args, **kwargs) + self.ref_private, self.ref_public = create_ref_keys_x448() + + def test_import_public_der(self): + key_file = load_file("ecc_x448_public.der") + + key = ECC._import_subjectPublicKeyInfo(key_file) + self.assertEqual(self.ref_public, key) + + key = ECC._import_der(key_file, None) + self.assertEqual(self.ref_public, key) + + key = ECC.import_key(key_file) + self.assertEqual(self.ref_public, key) + + def test_import_pkcs8_der(self): + key_file = load_file("ecc_x448_private.der") + + key = ECC._import_der(key_file, None) + self.assertEqual(self.ref_private, key) + + key = ECC.import_key(key_file) + self.assertEqual(self.ref_private, key) + + def test_import_private_pkcs8_encrypted_1(self): + key_file = load_file("ecc_x448_private_p8.der") + + key = ECC._import_der(key_file, "secret") + self.assertEqual(self.ref_private, key) + + key = ECC.import_key(key_file, "secret") + self.assertEqual(self.ref_private, key) + + def test_import_private_pkcs8_encrypted_2(self): + key_file = load_file("ecc_x448_private_p8.pem") + + key = ECC.import_key(key_file, "secret") + self.assertEqual(self.ref_private, key) + + def test_import_private_pkcs8_encrypted_3(self): + key_file = load_file("ecc_x448_private_p8_2.der") + + key = ECC._import_der(key_file, "secret") + self.assertEqual(self.ref_private, key) + + key = ECC.import_key(key_file, "secret") + self.assertEqual(self.ref_private, key) + + def test_import_x509_der(self): + key_file = load_file("ecc_x448_x509.der") + + key = ECC._import_der(key_file, None) + self.assertEqual(self.ref_public, key) + + key = ECC.import_key(key_file) + self.assertEqual(self.ref_public, key) + + def test_import_public_pem(self): + key_file = load_file("ecc_x448_public.pem") + + key = ECC.import_key(key_file) + self.assertEqual(self.ref_public, key) + + def test_import_private_pem(self): + key_file = load_file("ecc_x448_private.pem") + + key = ECC.import_key(key_file) + self.assertEqual(self.ref_private, key) + + def test_import_private_pem_encrypted(self): + for algo in "des3", "aes128", "aes192", "aes256": + key_file = load_file("ecc_x448_private_enc_%s.pem" % algo) + + key = ECC.import_key(key_file, "secret") + self.assertEqual(self.ref_private, key) + + key = ECC.import_key(tostr(key_file), b"secret") + self.assertEqual(self.ref_private, key) + + def test_import_x509_pem(self): + key_file = load_file("ecc_x448_x509.pem") + + key = ECC.import_key(key_file) + self.assertEqual(self.ref_public, key) + + +class TestExport_Curve448(unittest.TestCase): + + def __init__(self, *args, **kwargs): + super(TestExport_Curve448, self).__init__(*args, **kwargs) + self.ref_private, self.ref_public = create_ref_keys_x448() + + def test_export_public_der(self): + key_file = load_file("ecc_x448_public.der") + + encoded = self.ref_public._export_subjectPublicKeyInfo(True) + self.assertEqual(key_file, encoded) + + encoded = self.ref_public.export_key(format="DER") + self.assertEqual(key_file, encoded) + + encoded = self.ref_public.export_key(format="DER", compress=False) + self.assertEqual(key_file, encoded) + + def test_export_private_pkcs8_clear(self): + key_file = load_file("ecc_x448_private.der") + + encoded = self.ref_private._export_pkcs8() + self.assertEqual(key_file, encoded) + + # --- + + encoded = self.ref_private.export_key(format="DER") + self.assertEqual(key_file, encoded) + + self.assertRaises(ValueError, self.ref_private.export_key, + format="DER", use_pkcs8=False) + + def test_export_private_pkcs8_encrypted(self): + encoded = self.ref_private._export_pkcs8(passphrase="secret", + protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") + + # This should prove that the output is password-protected + self.assertRaises(ValueError, ECC._import_pkcs8, encoded, None) + + decoded = ECC._import_pkcs8(encoded, "secret") + self.assertEqual(self.ref_private, decoded) + + # --- + + encoded = self.ref_private.export_key(format="DER", + passphrase="secret", + protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") + decoded = ECC.import_key(encoded, "secret") + self.assertEqual(self.ref_private, decoded) + + # --- + + encoded = self.ref_private.export_key(format="DER", + passphrase="secret", + protection="PBKDF2WithHMAC-SHA256AndAES128-CBC", + prot_params={'iteration_count': 123}) + decoded = ECC.import_key(encoded, "secret") + self.assertEqual(self.ref_private, decoded) + + def test_export_public_pem(self): + key_file_ref = load_file("ecc_x448_public.pem", "rt").strip() + key_file = self.ref_public.export_key(format="PEM").strip() + self.assertEqual(key_file_ref, key_file) + + def test_export_private_pem_clear(self): + key_file = load_file("ecc_x448_private.pem", "rt").strip() + encoded = self.ref_private.export_key(format="PEM").strip() + self.assertEqual(key_file, encoded) + + def test_export_private_pem_encrypted(self): + encoded = self.ref_private.export_key(format="PEM", + passphrase=b"secret", + protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") + + # This should prove that the output is password-protected + self.assertRaises(ValueError, ECC.import_key, encoded) + + assert "ENCRYPTED PRIVATE KEY" in encoded + + decoded = ECC.import_key(encoded, "secret") + self.assertEqual(self.ref_private, decoded) + + def test_export_raw(self): + encoded = self.ref_public.export_key(format='raw') + self.assertEqual(len(encoded), 56) + self.assertEqual(encoded, unhexlify(b'e2abae24ab8f65b01969e61f84fee615b525f413a90e3d727f71d0ffe60fb1d0a1a0285f2a7fd88789206e0aa4f3e9fcb9e4ba5d644e691e')) + + def test_prng(self): + # Test that password-protected containers use the provided PRNG + encoded1 = self.ref_private.export_key(format="PEM", + passphrase="secret", + protection="PBKDF2WithHMAC-SHA1AndAES128-CBC", + randfunc=get_fixed_prng()) + encoded2 = self.ref_private.export_key(format="PEM", + passphrase="secret", + protection="PBKDF2WithHMAC-SHA1AndAES128-CBC", + randfunc=get_fixed_prng()) + self.assertEqual(encoded1, encoded2) + + def test_byte_or_string_passphrase(self): + encoded1 = self.ref_private.export_key(format="PEM", + passphrase="secret", + protection="PBKDF2WithHMAC-SHA1AndAES128-CBC", + randfunc=get_fixed_prng()) + encoded2 = self.ref_private.export_key(format="PEM", + passphrase=b"secret", + protection="PBKDF2WithHMAC-SHA1AndAES128-CBC", + randfunc=get_fixed_prng()) + self.assertEqual(encoded1, encoded2) + + def test_error_params1(self): + # Unknown format + self.assertRaises(ValueError, self.ref_private.export_key, format="XXX") + + # Missing 'protection' parameter when PKCS#8 is used + self.assertRaises(ValueError, + self.ref_private.export_key, + format="PEM", + passphrase="secret") + + # Empty password + self.assertRaises(ValueError, + self.ref_private.export_key, + format="PEM", + passphrase="", + use_pkcs8=False) + self.assertRaises(ValueError, + self.ref_private.export_key, + format="PEM", + passphrase="", + protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") + + # No private keys with OpenSSH + self.assertRaises(ValueError, + self.ref_private.export_key, + format="OpenSSH", + passphrase="secret") + + +class TestImport_Curve448_Weak(unittest.TestCase): + + def test_weak_pem(self): + + p = 2**448 - 2**224 - 1 + weak_x = (0, + 1, + p - 1, + p, + p + 1) + + for x in weak_x: + low_order_point = ECC.EccXPoint(x, "curve448") + weak_key = ECC.EccKey(point=low_order_point, curve="curve448") + encoded = weak_key.export_key(format="PEM") + + self.assertRaises(ValueError, + ECC.import_key, + encoded) + + +def get_tests(config={}): + tests = [] + try: + tests += list_test_cases(TestImport) + tests += list_test_cases(TestImport_Curve448) + tests += list_test_cases(TestExport_Curve448) + tests += list_test_cases(TestImport_Curve448_Weak) + except SkipTest: + pass + return tests + + +if __name__ == '__main__': + def suit(): + return unittest.TestSuite(get_tests()) + unittest.main(defaultTest='suite') diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/PublicKey/test_import_DSA.py b/venv/Lib/site-packages/Cryptodome/SelfTest/PublicKey/test_import_DSA.py new file mode 100644 index 0000000..5ff0113 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/SelfTest/PublicKey/test_import_DSA.py @@ -0,0 +1,554 @@ +# -*- coding: utf-8 -*- +# +# SelfTest/PublicKey/test_import_DSA.py: Self-test for importing DSA keys +# +# =================================================================== +# The contents of this file are dedicated to the public domain. To +# the extent that dedication to the public domain is not available, +# everyone is granted a worldwide, perpetual, royalty-free, +# non-exclusive license to exercise all rights associated with the +# contents of this file for any purpose whatsoever. +# No rights are reserved. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# =================================================================== + +import unittest +import re + +from Cryptodome.PublicKey import DSA +from Cryptodome.SelfTest.st_common import * +from Cryptodome.Util.py3compat import * + +from binascii import unhexlify + +class ImportKeyTests(unittest.TestCase): + + y = 92137165128186062214622779787483327510946462589285775188003362705875131352591574106484271700740858696583623951844732128165434284507709057439633739849986759064015013893156866539696757799934634945787496920169462601722830899660681779448742875054459716726855443681559131362852474817534616736104831095601710736729 + p = 162452170958135306109773853318304545923250830605675936228618290525164105310663722368377131295055868997377338797580997938253236213714988311430600065853662861806894003694743806769284131194035848116051021923956699231855223389086646903420682639786976554552864568460372266462812137447840653688476258666833303658691 + q = 988791743931120302950649732173330531512663554851 + g = 85583152299197514738065570254868711517748965097380456700369348466136657764813442044039878840094809620913085570225318356734366886985903212775602770761953571967834823306046501307810937486758039063386311593890777319935391363872375452381836756832784184928202587843258855704771836753434368484556809100537243908232 + x = 540873410045082450874416847965843801027716145253 + + def setUp(self): + + # It is easier to write test vectors in text form, + # and convert them to byte strigs dynamically here + for mname, mvalue in ImportKeyTests.__dict__.items(): + if mname[:4] in ('der_', 'pem_', 'ssh_'): + if mname[:4] == 'der_': + mvalue = unhexlify(tobytes(mvalue)) + mvalue = tobytes(mvalue) + setattr(self, mname, mvalue) + + # 1. SubjectPublicKeyInfo + der_public=\ + '308201b73082012b06072a8648ce3804013082011e02818100e756ee1717f4b6'+\ + '794c7c214724a19763742c45572b4b3f8ff3b44f3be9f44ce039a2757695ec91'+\ + '5697da74ef914fcd1b05660e2419c761d639f45d2d79b802dbd23e7ab8b81b47'+\ + '9a380e1f30932584ba2a0b955032342ebc83cb5ca906e7b0d7cd6fe656cecb4c'+\ + '8b5a77123a8c6750a481e3b06057aff6aa6eba620b832d60c3021500ad32f48c'+\ + 'd3ae0c45a198a61fa4b5e20320763b2302818079dfdc3d614fe635fceb7eaeae'+\ + '3718dc2efefb45282993ac6749dc83c223d8c1887296316b3b0b54466cf444f3'+\ + '4b82e3554d0b90a778faaf1306f025dae6a3e36c7f93dd5bac4052b92370040a'+\ + 'ca70b8d5820599711900efbc961812c355dd9beffe0981da85c5548074b41c56'+\ + 'ae43fd300d89262e4efd89943f99a651b03888038185000281810083352a69a1'+\ + '32f34843d2a0eb995bff4e2f083a73f0049d2c91ea2f0ce43d144abda48199e4'+\ + 'b003c570a8af83303d45105f606c5c48d925a40ed9c2630c2fa4cdbf838539de'+\ + 'b9a29f919085f2046369f627ca84b2cb1e2c7940564b670f963ab1164d4e2ca2'+\ + 'bf6ffd39f12f548928bf4d2d1b5e6980b4f1be4c92a91986fba559' + + def testImportKey1(self): + key_obj = DSA.importKey(self.der_public) + self.assertFalse(key_obj.has_private()) + self.assertEqual(self.y, key_obj.y) + self.assertEqual(self.p, key_obj.p) + self.assertEqual(self.q, key_obj.q) + self.assertEqual(self.g, key_obj.g) + + def testExportKey1(self): + tup = (self.y, self.g, self.p, self.q) + key = DSA.construct(tup) + encoded = key.export_key('DER') + self.assertEqual(self.der_public, encoded) + + # 2. + pem_public="""\ +-----BEGIN PUBLIC KEY----- +MIIBtzCCASsGByqGSM44BAEwggEeAoGBAOdW7hcX9LZ5THwhRyShl2N0LEVXK0s/ +j/O0Tzvp9EzgOaJ1dpXskVaX2nTvkU/NGwVmDiQZx2HWOfRdLXm4AtvSPnq4uBtH +mjgOHzCTJYS6KguVUDI0LryDy1ypBuew181v5lbOy0yLWncSOoxnUKSB47BgV6/2 +qm66YguDLWDDAhUArTL0jNOuDEWhmKYfpLXiAyB2OyMCgYB539w9YU/mNfzrfq6u +NxjcLv77RSgpk6xnSdyDwiPYwYhyljFrOwtURmz0RPNLguNVTQuQp3j6rxMG8CXa +5qPjbH+T3VusQFK5I3AECspwuNWCBZlxGQDvvJYYEsNV3Zvv/gmB2oXFVIB0tBxW +rkP9MA2JJi5O/YmUP5mmUbA4iAOBhQACgYEAgzUqaaEy80hD0qDrmVv/Ti8IOnPw +BJ0skeovDOQ9FEq9pIGZ5LADxXCor4MwPUUQX2BsXEjZJaQO2cJjDC+kzb+DhTne +uaKfkZCF8gRjafYnyoSyyx4seUBWS2cPljqxFk1OLKK/b/058S9UiSi/TS0bXmmA +tPG+TJKpGYb7pVk= +-----END PUBLIC KEY-----""" + + def testImportKey2(self): + for pem in (self.pem_public, tostr(self.pem_public)): + key_obj = DSA.importKey(pem) + self.assertFalse(key_obj.has_private()) + self.assertEqual(self.y, key_obj.y) + self.assertEqual(self.p, key_obj.p) + self.assertEqual(self.q, key_obj.q) + self.assertEqual(self.g, key_obj.g) + + def testExportKey2(self): + tup = (self.y, self.g, self.p, self.q) + key = DSA.construct(tup) + encoded = key.export_key('PEM') + self.assertEqual(self.pem_public, encoded) + + # 3. OpenSSL/OpenSSH format + der_private=\ + '308201bb02010002818100e756ee1717f4b6794c7c214724a19763742c45572b'+\ + '4b3f8ff3b44f3be9f44ce039a2757695ec915697da74ef914fcd1b05660e2419'+\ + 'c761d639f45d2d79b802dbd23e7ab8b81b479a380e1f30932584ba2a0b955032'+\ + '342ebc83cb5ca906e7b0d7cd6fe656cecb4c8b5a77123a8c6750a481e3b06057'+\ + 'aff6aa6eba620b832d60c3021500ad32f48cd3ae0c45a198a61fa4b5e2032076'+\ + '3b2302818079dfdc3d614fe635fceb7eaeae3718dc2efefb45282993ac6749dc'+\ + '83c223d8c1887296316b3b0b54466cf444f34b82e3554d0b90a778faaf1306f0'+\ + '25dae6a3e36c7f93dd5bac4052b92370040aca70b8d5820599711900efbc9618'+\ + '12c355dd9beffe0981da85c5548074b41c56ae43fd300d89262e4efd89943f99'+\ + 'a651b038880281810083352a69a132f34843d2a0eb995bff4e2f083a73f0049d'+\ + '2c91ea2f0ce43d144abda48199e4b003c570a8af83303d45105f606c5c48d925'+\ + 'a40ed9c2630c2fa4cdbf838539deb9a29f919085f2046369f627ca84b2cb1e2c'+\ + '7940564b670f963ab1164d4e2ca2bf6ffd39f12f548928bf4d2d1b5e6980b4f1'+\ + 'be4c92a91986fba55902145ebd9a3f0b82069d98420986b314215025756065' + + def testImportKey3(self): + key_obj = DSA.importKey(self.der_private) + self.assertTrue(key_obj.has_private()) + self.assertEqual(self.y, key_obj.y) + self.assertEqual(self.p, key_obj.p) + self.assertEqual(self.q, key_obj.q) + self.assertEqual(self.g, key_obj.g) + self.assertEqual(self.x, key_obj.x) + + def testExportKey3(self): + tup = (self.y, self.g, self.p, self.q, self.x) + key = DSA.construct(tup) + encoded = key.export_key('DER', pkcs8=False) + self.assertEqual(self.der_private, encoded) + + # 4. + pem_private="""\ +-----BEGIN DSA PRIVATE KEY----- +MIIBuwIBAAKBgQDnVu4XF/S2eUx8IUckoZdjdCxFVytLP4/ztE876fRM4DmidXaV +7JFWl9p075FPzRsFZg4kGcdh1jn0XS15uALb0j56uLgbR5o4Dh8wkyWEuioLlVAy +NC68g8tcqQbnsNfNb+ZWzstMi1p3EjqMZ1CkgeOwYFev9qpuumILgy1gwwIVAK0y +9IzTrgxFoZimH6S14gMgdjsjAoGAed/cPWFP5jX8636urjcY3C7++0UoKZOsZ0nc +g8Ij2MGIcpYxazsLVEZs9ETzS4LjVU0LkKd4+q8TBvAl2uaj42x/k91brEBSuSNw +BArKcLjVggWZcRkA77yWGBLDVd2b7/4JgdqFxVSAdLQcVq5D/TANiSYuTv2JlD+Z +plGwOIgCgYEAgzUqaaEy80hD0qDrmVv/Ti8IOnPwBJ0skeovDOQ9FEq9pIGZ5LAD +xXCor4MwPUUQX2BsXEjZJaQO2cJjDC+kzb+DhTneuaKfkZCF8gRjafYnyoSyyx4s +eUBWS2cPljqxFk1OLKK/b/058S9UiSi/TS0bXmmAtPG+TJKpGYb7pVkCFF69mj8L +ggadmEIJhrMUIVAldWBl +-----END DSA PRIVATE KEY-----""" + + def testImportKey4(self): + for pem in (self.pem_private, tostr(self.pem_private)): + key_obj = DSA.importKey(pem) + self.assertTrue(key_obj.has_private()) + self.assertEqual(self.y, key_obj.y) + self.assertEqual(self.p, key_obj.p) + self.assertEqual(self.q, key_obj.q) + self.assertEqual(self.g, key_obj.g) + self.assertEqual(self.x, key_obj.x) + + def testExportKey4(self): + tup = (self.y, self.g, self.p, self.q, self.x) + key = DSA.construct(tup) + encoded = key.export_key('PEM', pkcs8=False) + self.assertEqual(self.pem_private, encoded) + + # 5. PKCS8 (unencrypted) + der_pkcs8=\ + '3082014a0201003082012b06072a8648ce3804013082011e02818100e756ee17'+\ + '17f4b6794c7c214724a19763742c45572b4b3f8ff3b44f3be9f44ce039a27576'+\ + '95ec915697da74ef914fcd1b05660e2419c761d639f45d2d79b802dbd23e7ab8'+\ + 'b81b479a380e1f30932584ba2a0b955032342ebc83cb5ca906e7b0d7cd6fe656'+\ + 'cecb4c8b5a77123a8c6750a481e3b06057aff6aa6eba620b832d60c3021500ad'+\ + '32f48cd3ae0c45a198a61fa4b5e20320763b2302818079dfdc3d614fe635fceb'+\ + '7eaeae3718dc2efefb45282993ac6749dc83c223d8c1887296316b3b0b54466c'+\ + 'f444f34b82e3554d0b90a778faaf1306f025dae6a3e36c7f93dd5bac4052b923'+\ + '70040aca70b8d5820599711900efbc961812c355dd9beffe0981da85c5548074'+\ + 'b41c56ae43fd300d89262e4efd89943f99a651b03888041602145ebd9a3f0b82'+\ + '069d98420986b314215025756065' + + def testImportKey5(self): + key_obj = DSA.importKey(self.der_pkcs8) + self.assertTrue(key_obj.has_private()) + self.assertEqual(self.y, key_obj.y) + self.assertEqual(self.p, key_obj.p) + self.assertEqual(self.q, key_obj.q) + self.assertEqual(self.g, key_obj.g) + self.assertEqual(self.x, key_obj.x) + + def testExportKey5(self): + tup = (self.y, self.g, self.p, self.q, self.x) + key = DSA.construct(tup) + encoded = key.export_key('DER') + self.assertEqual(self.der_pkcs8, encoded) + encoded = key.export_key('DER', pkcs8=True) + self.assertEqual(self.der_pkcs8, encoded) + + # 6. + pem_pkcs8="""\ +-----BEGIN PRIVATE KEY----- +MIIBSgIBADCCASsGByqGSM44BAEwggEeAoGBAOdW7hcX9LZ5THwhRyShl2N0LEVX +K0s/j/O0Tzvp9EzgOaJ1dpXskVaX2nTvkU/NGwVmDiQZx2HWOfRdLXm4AtvSPnq4 +uBtHmjgOHzCTJYS6KguVUDI0LryDy1ypBuew181v5lbOy0yLWncSOoxnUKSB47Bg +V6/2qm66YguDLWDDAhUArTL0jNOuDEWhmKYfpLXiAyB2OyMCgYB539w9YU/mNfzr +fq6uNxjcLv77RSgpk6xnSdyDwiPYwYhyljFrOwtURmz0RPNLguNVTQuQp3j6rxMG +8CXa5qPjbH+T3VusQFK5I3AECspwuNWCBZlxGQDvvJYYEsNV3Zvv/gmB2oXFVIB0 +tBxWrkP9MA2JJi5O/YmUP5mmUbA4iAQWAhRevZo/C4IGnZhCCYazFCFQJXVgZQ== +-----END PRIVATE KEY-----""" + + def testImportKey6(self): + for pem in (self.pem_pkcs8, tostr(self.pem_pkcs8)): + key_obj = DSA.importKey(pem) + self.assertTrue(key_obj.has_private()) + self.assertEqual(self.y, key_obj.y) + self.assertEqual(self.p, key_obj.p) + self.assertEqual(self.q, key_obj.q) + self.assertEqual(self.g, key_obj.g) + self.assertEqual(self.x, key_obj.x) + + def testExportKey6(self): + tup = (self.y, self.g, self.p, self.q, self.x) + key = DSA.construct(tup) + encoded = key.export_key('PEM') + self.assertEqual(self.pem_pkcs8, encoded) + encoded = key.export_key('PEM', pkcs8=True) + self.assertEqual(self.pem_pkcs8, encoded) + + # 7. OpenSSH/RFC4253 + ssh_pub="""ssh-dss AAAAB3NzaC1kc3MAAACBAOdW7hcX9LZ5THwhRyShl2N0LEVXK0s/j/O0Tzvp9EzgOaJ1dpXskVaX2nTvkU/NGwVmDiQZx2HWOfRdLXm4AtvSPnq4uBtHmjgOHzCTJYS6KguVUDI0LryDy1ypBuew181v5lbOy0yLWncSOoxnUKSB47BgV6/2qm66YguDLWDDAAAAFQCtMvSM064MRaGYph+kteIDIHY7IwAAAIB539w9YU/mNfzrfq6uNxjcLv77RSgpk6xnSdyDwiPYwYhyljFrOwtURmz0RPNLguNVTQuQp3j6rxMG8CXa5qPjbH+T3VusQFK5I3AECspwuNWCBZlxGQDvvJYYEsNV3Zvv/gmB2oXFVIB0tBxWrkP9MA2JJi5O/YmUP5mmUbA4iAAAAIEAgzUqaaEy80hD0qDrmVv/Ti8IOnPwBJ0skeovDOQ9FEq9pIGZ5LADxXCor4MwPUUQX2BsXEjZJaQO2cJjDC+kzb+DhTneuaKfkZCF8gRjafYnyoSyyx4seUBWS2cPljqxFk1OLKK/b/058S9UiSi/TS0bXmmAtPG+TJKpGYb7pVk=""" + + def testImportKey7(self): + for ssh in (self.ssh_pub, tostr(self.ssh_pub)): + key_obj = DSA.importKey(ssh) + self.assertFalse(key_obj.has_private()) + self.assertEqual(self.y, key_obj.y) + self.assertEqual(self.p, key_obj.p) + self.assertEqual(self.q, key_obj.q) + self.assertEqual(self.g, key_obj.g) + + def testExportKey7(self): + tup = (self.y, self.g, self.p, self.q) + key = DSA.construct(tup) + encoded = key.export_key('OpenSSH') + self.assertEqual(self.ssh_pub, encoded) + + # 8. Encrypted OpenSSL/OpenSSH + pem_private_encrypted="""\ +-----BEGIN DSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: AES-128-CBC,70B6908939D65E9F2EB999E8729788CE + +4V6GHRDpCrdZ8MBjbyp5AlGUrjvr2Pn2e2zVxy5RBt4FBj9/pa0ae0nnyUPMLSUU +kKyOR0topRYTVRLElm4qVrb5uNZ3hRwfbklr+pSrB7O9eHz9V5sfOQxyODS07JxK +k1OdOs70/ouMXLF9EWfAZOmWUccZKHNblUwg1p1UrZIz5jXw4dUE/zqhvXh6d+iC +ADsICaBCjCrRQJKDp50h3+ndQjkYBKVH+pj8TiQ79U7lAvdp3+iMghQN6YXs9mdI +gFpWw/f97oWM4GHZFqHJ+VSMNFjBiFhAvYV587d7Lk4dhD8sCfbxj42PnfRgUItc +nnPqHxmhMQozBWzYM4mQuo3XbF2WlsNFbOzFVyGhw1Bx1s91qvXBVWJh2ozrW0s6 +HYDV7ZkcTml/4kjA/d+mve6LZ8kuuR1qCiZx6rkffhh1gDN/1Xz3HVvIy/dQ+h9s +5zp7PwUoWbhqp3WCOr156P6gR8qo7OlT6wMh33FSXK/mxikHK136fV2shwTKQVII +rJBvXpj8nACUmi7scKuTWGeUoXa+dwTZVVe+b+L2U1ZM7+h/neTJiXn7u99PFUwu +xVJtxaV37m3aXxtCsPnbBg== +-----END DSA PRIVATE KEY-----""" + + def testImportKey8(self): + for pem in (self.pem_private_encrypted, tostr(self.pem_private_encrypted)): + key_obj = DSA.importKey(pem, "PWDTEST") + self.assertTrue(key_obj.has_private()) + self.assertEqual(self.y, key_obj.y) + self.assertEqual(self.p, key_obj.p) + self.assertEqual(self.q, key_obj.q) + self.assertEqual(self.g, key_obj.g) + self.assertEqual(self.x, key_obj.x) + + def testExportKey8(self): + tup = (self.y, self.g, self.p, self.q, self.x) + key = DSA.construct(tup) + encoded = key.export_key('PEM', pkcs8=False, passphrase="PWDTEST") + key = DSA.importKey(encoded, "PWDTEST") + self.assertEqual(self.y, key.y) + self.assertEqual(self.p, key.p) + self.assertEqual(self.q, key.q) + self.assertEqual(self.g, key.g) + self.assertEqual(self.x, key.x) + + # 9. Encrypted PKCS8 + # pbeWithMD5AndDES-CBC + pem_pkcs8_encrypted="""\ +-----BEGIN ENCRYPTED PRIVATE KEY----- +MIIBcTAbBgkqhkiG9w0BBQMwDgQI0GC3BJ/jSw8CAggABIIBUHc1cXZpExIE9tC7 +7ryiW+5ihtF2Ekurq3e408GYSAu5smJjN2bvQXmzRFBz8W38K8eMf1sbWroZ4+zn +kZSbb9nSm5kAa8lR2+oF2k+WRswMR/PTC3f/D9STO2X0QxdrzKgIHEcSGSHp5jTx +aVvbkCDHo9vhBTl6S3ogZ48As/MEro76+9igUwJ1jNhIQZPJ7e20QH5qDpQFFJN4 +CKl2ENSEuwGiqBszItFy4dqH0g63ZGZV/xt9wSO9Rd7SK/EbA/dklOxBa5Y/VItM +gnIhs9XDMoGYyn6F023EicNJm6g/bVQk81BTTma4tm+12TKGdYm+QkeZvCOMZylr +Wv67cKwO3cAXt5C3QXMDgYR64XvuaT5h7C0igMp2afSXJlnbHEbFxQVJlv83T4FM +eZ4k+NQDbEL8GiHmFxzDWQAuPPZKJWEEEV2p/To+WOh+kSDHQw== +-----END ENCRYPTED PRIVATE KEY-----""" + + def testImportKey9(self): + for pem in (self.pem_pkcs8_encrypted, tostr(self.pem_pkcs8_encrypted)): + key_obj = DSA.importKey(pem, "PWDTEST") + self.assertTrue(key_obj.has_private()) + self.assertEqual(self.y, key_obj.y) + self.assertEqual(self.p, key_obj.p) + self.assertEqual(self.q, key_obj.q) + self.assertEqual(self.g, key_obj.g) + self.assertEqual(self.x, key_obj.x) + + # 10. Encrypted PKCS8 + # pkcs5PBES2 / + # pkcs5PBKDF2 (rounds=1000, salt=D725BF1B6B8239F4) / + # des-EDE3-CBC (iv=27A1C66C42AFEECE) + # + der_pkcs8_encrypted=\ + '30820196304006092a864886f70d01050d3033301b06092a864886f70d01050c'+\ + '300e0408d725bf1b6b8239f4020203e8301406082a864886f70d0307040827a1'+\ + 'c66c42afeece048201505cacfde7bf8edabb3e0d387950dc872662ea7e9b1ed4'+\ + '400d2e7e6186284b64668d8d0328c33a9d9397e6f03df7cb68268b0a06b4e22f'+\ + '7d132821449ecf998a8b696dbc6dd2b19e66d7eb2edfeb4153c1771d49702395'+\ + '4f36072868b5fcccf93413a5ac4b2eb47d4b3f681c6bd67ae363ed776f45ae47'+\ + '174a00098a7c930a50f820b227ddf50f9742d8e950d02586ff2dac0e3c372248'+\ + 'e5f9b6a7a02f4004f20c87913e0f7b52bccc209b95d478256a890b31d4c9adec'+\ + '21a4d157a179a93a3dad06f94f3ce486b46dfa7fc15fd852dd7680bbb2f17478'+\ + '7e71bd8dbaf81eca7518d76c1d26256e95424864ba45ca5d47d7c5a421be02fa'+\ + 'b94ab01e18593f66cf9094eb5c94b9ecf3aa08b854a195cf87612fbe5e96c426'+\ + '2b0d573e52dc71ba3f5e468c601e816c49b7d32c698b22175e89aaef0c443770'+\ + '5ef2f88a116d99d8e2869a4fd09a771b84b49e4ccb79aadcb1c9' + + def testImportKey10(self): + key_obj = DSA.importKey(self.der_pkcs8_encrypted, "PWDTEST") + self.assertTrue(key_obj.has_private()) + self.assertEqual(self.y, key_obj.y) + self.assertEqual(self.p, key_obj.p) + self.assertEqual(self.q, key_obj.q) + self.assertEqual(self.g, key_obj.g) + self.assertEqual(self.x, key_obj.x) + + def testExportKey10(self): + tup = (self.y, self.g, self.p, self.q, self.x) + key = DSA.construct(tup) + randfunc = BytesIO(unhexlify(b("27A1C66C42AFEECE") + b("D725BF1B6B8239F4"))).read + encoded = key.export_key('DER', pkcs8=True, passphrase="PWDTEST", randfunc=randfunc) + self.assertEqual(self.der_pkcs8_encrypted, encoded) + + # ---- + + def testImportError1(self): + self.assertRaises(ValueError, DSA.importKey, self.der_pkcs8_encrypted, "wrongpwd") + + def testExportError2(self): + tup = (self.y, self.g, self.p, self.q, self.x) + key = DSA.construct(tup) + self.assertRaises(ValueError, key.export_key, 'DER', pkcs8=False, passphrase="PWDTEST") + + def test_import_key(self): + """Verify importKey is an alias to import_key""" + + key_obj = DSA.import_key(self.der_public) + self.assertFalse(key_obj.has_private()) + self.assertEqual(self.y, key_obj.y) + self.assertEqual(self.p, key_obj.p) + self.assertEqual(self.q, key_obj.q) + self.assertEqual(self.g, key_obj.g) + + def test_exportKey(self): + tup = (self.y, self.g, self.p, self.q, self.x) + key = DSA.construct(tup) + self.assertEqual(key.exportKey(), key.export_key()) + + + def test_import_empty(self): + self.assertRaises(ValueError, DSA.import_key, b'') + + +class ImportKeyFromX509Cert(unittest.TestCase): + + def test_x509v1(self): + + # Sample V1 certificate with a 1024 bit DSA key + x509_v1_cert = """ +-----BEGIN CERTIFICATE----- +MIIDUjCCArsCAQIwDQYJKoZIhvcNAQEFBQAwfjENMAsGA1UEChMEQWNtZTELMAkG +A1UECxMCUkQxHDAaBgkqhkiG9w0BCQEWDXNwYW1AYWNtZS5vcmcxEzARBgNVBAcT +Ck1ldHJvcG9saXMxETAPBgNVBAgTCE5ldyBZb3JrMQswCQYDVQQGEwJVUzENMAsG +A1UEAxMEdGVzdDAeFw0xNDA3MTEyMDM4NDNaFw0xNzA0MDYyMDM4NDNaME0xCzAJ +BgNVBAYTAlVTMREwDwYDVQQIEwhOZXcgWW9yazENMAsGA1UEChMEQWNtZTELMAkG +A1UECxMCUkQxDzANBgNVBAMTBnBvbGFuZDCCAbYwggErBgcqhkjOOAQBMIIBHgKB +gQDOrN4Ox4+t3T6wKeHfhzArhcrNEFMQ4Ss+4PIKyimDy9Bn64WPkL1B/9dvYIga +23GLu6tVJmXo6EdJnVOHEMhr99EeOwuDWWeP7Awq7RSlKEejokr4BEzMTW/tExSD +cO6/GI7xzh0eTH+VTTPDfyrJMYCkh0rJAfCP+5xrmPNetwIVALtXYOV1yoRrzJ2Q +M5uEjidH6GiZAoGAfUqA1SAm5g5U68SILMVX9l5rq0OpB0waBMpJQ31/R/yXNDqo +c3gGWZTOJFU4IzwNpGhrGNADUByz/lc1SAOAdEJIr0JVrhbGewQjB4pWqoLGbBKz +RoavTNDc/zD7SYa12evWDHADwvlXoeQg+lWop1zS8OqaDC7aLGKpWN3/m8kDgYQA +AoGAKoirPAfcp1rbbl4y2FFAIktfW8f4+T7d2iKSg73aiVfujhNOt1Zz1lfC0NI2 +eonLWO3tAM4XGKf1TLjb5UXngGn40okPsaA81YE6ZIKm20ywjlOY3QkAEdMaLVY3 +9PJvM8RGB9m7pLKxyHfGMfF40MVN4222zKeGp7xhM0CNiCUwDQYJKoZIhvcNAQEF +BQADgYEAfbNZfpYa2KlALEM1FZnwvQDvJHntHz8LdeJ4WM7CXDlKi67wY2HKM30w +s2xej75imkVOFd1kF2d0A8sjfriXLVIt1Hwq9ANZomhu4Edx0xpH8tqdh/bDtnM2 +TmduZNY9OWkb07h0CtWD6Zt8fhRllVsSSrlWd/2or7FXNC5weFQ= +-----END CERTIFICATE----- + """.strip() + + # DSA public key as dumped by openssl + y_str = """ +2a:88:ab:3c:07:dc:a7:5a:db:6e:5e:32:d8:51:40: +22:4b:5f:5b:c7:f8:f9:3e:dd:da:22:92:83:bd:da: +89:57:ee:8e:13:4e:b7:56:73:d6:57:c2:d0:d2:36: +7a:89:cb:58:ed:ed:00:ce:17:18:a7:f5:4c:b8:db: +e5:45:e7:80:69:f8:d2:89:0f:b1:a0:3c:d5:81:3a: +64:82:a6:db:4c:b0:8e:53:98:dd:09:00:11:d3:1a: +2d:56:37:f4:f2:6f:33:c4:46:07:d9:bb:a4:b2:b1: +c8:77:c6:31:f1:78:d0:c5:4d:e3:6d:b6:cc:a7:86: +a7:bc:61:33:40:8d:88:25 + """ + p_str = """ +00:ce:ac:de:0e:c7:8f:ad:dd:3e:b0:29:e1:df:87: +30:2b:85:ca:cd:10:53:10:e1:2b:3e:e0:f2:0a:ca: +29:83:cb:d0:67:eb:85:8f:90:bd:41:ff:d7:6f:60: +88:1a:db:71:8b:bb:ab:55:26:65:e8:e8:47:49:9d: +53:87:10:c8:6b:f7:d1:1e:3b:0b:83:59:67:8f:ec: +0c:2a:ed:14:a5:28:47:a3:a2:4a:f8:04:4c:cc:4d: +6f:ed:13:14:83:70:ee:bf:18:8e:f1:ce:1d:1e:4c: +7f:95:4d:33:c3:7f:2a:c9:31:80:a4:87:4a:c9:01: +f0:8f:fb:9c:6b:98:f3:5e:b7 + """ + q_str = """ +00:bb:57:60:e5:75:ca:84:6b:cc:9d:90:33:9b:84: +8e:27:47:e8:68:99 + """ + g_str = """ +7d:4a:80:d5:20:26:e6:0e:54:eb:c4:88:2c:c5:57: +f6:5e:6b:ab:43:a9:07:4c:1a:04:ca:49:43:7d:7f: +47:fc:97:34:3a:a8:73:78:06:59:94:ce:24:55:38: +23:3c:0d:a4:68:6b:18:d0:03:50:1c:b3:fe:57:35: +48:03:80:74:42:48:af:42:55:ae:16:c6:7b:04:23: +07:8a:56:aa:82:c6:6c:12:b3:46:86:af:4c:d0:dc: +ff:30:fb:49:86:b5:d9:eb:d6:0c:70:03:c2:f9:57: +a1:e4:20:fa:55:a8:a7:5c:d2:f0:ea:9a:0c:2e:da: +2c:62:a9:58:dd:ff:9b:c9 + """ + + key = DSA.importKey(x509_v1_cert) + for comp_name in ('y', 'p', 'q', 'g'): + comp_str = locals()[comp_name + "_str"] + comp = int(re.sub("[^0-9a-f]", "", comp_str), 16) + self.assertEqual(getattr(key, comp_name), comp) + self.assertFalse(key.has_private()) + + def test_x509v3(self): + + # Sample V3 certificate with a 1024 bit DSA key + x509_v3_cert = """ +-----BEGIN CERTIFICATE----- +MIIFhjCCA26gAwIBAgIBAzANBgkqhkiG9w0BAQsFADBhMQswCQYDVQQGEwJVUzEL +MAkGA1UECAwCTUQxEjAQBgNVBAcMCUJhbHRpbW9yZTEQMA4GA1UEAwwHVGVzdCBD +QTEfMB0GCSqGSIb3DQEJARYQdGVzdEBleGFtcGxlLmNvbTAeFw0xNDA3MTMyMDUz +MjBaFw0xNzA0MDgyMDUzMjBaMEAxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJNRDES +MBAGA1UEBwwJQmFsdGltb3JlMRAwDgYDVQQDDAdhdXN0cmlhMIIBtjCCASsGByqG +SM44BAEwggEeAoGBALfd8gyEpVPA0ZI69Kp3nyJcu5N0ZZ3K1K9hleQLNqKEcZOh +7a/C2J1TPdmHTLJ0rAwBZ1nWxnARSgRphziGDFspKCYQwYcSMz8KoFgvXbXpuchy +oFACiQ2LqZnc5MakuLQtLcQciSYGYj3zmZdYMoa904F1aDWr+DxQI6DVC3/bAhUA +hqXMCJ6fQK3G2O9S3/CC/yVZXCsCgYBRXROl3R2khX7l10LQjDEgo3B1IzjXU/jP +McMBl6XO+nBJXxr/scbq8Ajiv7LTnGpSjgryHtvfj887kfvo8QbSS3kp3vq5uSqI +ui7E7r3jguWaLj616AG1HWOctXJUjqsiabZwsp2h09gHTzmHEXBOmiARu8xFxKAH +xsuo7onAbwOBhAACgYBylWjWSnKHE8mHx1A5m/0GQx6xnhWIe3+MJAnEhRGxA2J4 +SCsfWU0OwglIQToh1z5uUU9oDi9cYgNPBevOFRnDhc2yaJY6VAYnI+D+6J5IU6Yd +0iaG/iSc4sV4bFr0axcPpse3SN0XaQxiKeSFBfFnoMqL+dd9Gb3QPZSllBcVD6OB +1TCB0jAdBgNVHQ4EFgQUx5wN0Puotv388M9Tp/fsPbZpzAUwHwYDVR0jBBgwFoAU +a0hkif3RMaraiWtsOOZZlLu9wJwwCQYDVR0TBAIwADALBgNVHQ8EBAMCBeAwSgYD +VR0RBEMwQYILZXhhbXBsZS5jb22CD3d3dy5leGFtcGxlLmNvbYIQbWFpbC5leGFt +cGxlLmNvbYIPZnRwLmV4YW1wbGUuY29tMCwGCWCGSAGG+EIBDQQfFh1PcGVuU1NM +IEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTANBgkqhkiG9w0BAQsFAAOCAgEAyWf1TiJI +aNEIA9o/PG8/JiGASTS2/HBVTJbkq03k6NkJVk/GxC1DPziTUJ+CdWlHWcAi1EOW +Ach3QxNDRrVfCOfCMDgElIO1094/reJgdFYG00LRi8QkRJuxANV7YS4tLudhyHJC +kR2lhdMNmEuzWK+s2y+5cLrdm7qdvdENQCcV67uvGPx4sc+EaE7x13SczKjWBtbo +QCs6JTOW+EkPRl4Zo27K4OIZ43/J+GxvwU9QUVH3wPVdbbLNw+QeTFBYMTEcxyc4 +kv50HPBFaithziXBFyvdIs19FjkFzu0Uz/e0zb1+vMzQlJMD94HVOrMnIj5Sb2cL +KKdYXS4uhxFJmdV091Xur5JkYYwEzuaGav7J3zOzYutrIGTgDluLCvA+VQkRcTsy +jZ065SkY/v+38QHp+cmm8WRluupJTs8wYzVp6Fu0iFaaK7ztFmaZmHpiPIfDFjva +aCIgzzT5NweJd/b71A2SyzHXJ14zBXsr1PMylMp2TpHIidhuuNuQL6I0HaollB4M +Z3FsVBMhVDw4Z76qnFPr8mZE2tar33hSlJI/3pS/bBiukuBk8U7VB0X8OqaUnP3C +7b2Z4G8GtqDVcKGMzkvMjT4n9rKd/Le+qHSsQOGO9W/0LB7UDAZSwUsfAPnoBgdS +5t9tIomLCOstByXi+gGZue1TcdCa3Ph4kO0= +-----END CERTIFICATE----- + """.strip() + + # DSA public key as dumped by openssl + y_str = """ +72:95:68:d6:4a:72:87:13:c9:87:c7:50:39:9b:fd: +06:43:1e:b1:9e:15:88:7b:7f:8c:24:09:c4:85:11: +b1:03:62:78:48:2b:1f:59:4d:0e:c2:09:48:41:3a: +21:d7:3e:6e:51:4f:68:0e:2f:5c:62:03:4f:05:eb: +ce:15:19:c3:85:cd:b2:68:96:3a:54:06:27:23:e0: +fe:e8:9e:48:53:a6:1d:d2:26:86:fe:24:9c:e2:c5: +78:6c:5a:f4:6b:17:0f:a6:c7:b7:48:dd:17:69:0c: +62:29:e4:85:05:f1:67:a0:ca:8b:f9:d7:7d:19:bd: +d0:3d:94:a5:94:17:15:0f + """ + p_str = """ +00:b7:dd:f2:0c:84:a5:53:c0:d1:92:3a:f4:aa:77: +9f:22:5c:bb:93:74:65:9d:ca:d4:af:61:95:e4:0b: +36:a2:84:71:93:a1:ed:af:c2:d8:9d:53:3d:d9:87: +4c:b2:74:ac:0c:01:67:59:d6:c6:70:11:4a:04:69: +87:38:86:0c:5b:29:28:26:10:c1:87:12:33:3f:0a: +a0:58:2f:5d:b5:e9:b9:c8:72:a0:50:02:89:0d:8b: +a9:99:dc:e4:c6:a4:b8:b4:2d:2d:c4:1c:89:26:06: +62:3d:f3:99:97:58:32:86:bd:d3:81:75:68:35:ab: +f8:3c:50:23:a0:d5:0b:7f:db + """ + q_str = """ +00:86:a5:cc:08:9e:9f:40:ad:c6:d8:ef:52:df:f0: +82:ff:25:59:5c:2b + """ + g_str = """ +51:5d:13:a5:dd:1d:a4:85:7e:e5:d7:42:d0:8c:31: +20:a3:70:75:23:38:d7:53:f8:cf:31:c3:01:97:a5: +ce:fa:70:49:5f:1a:ff:b1:c6:ea:f0:08:e2:bf:b2: +d3:9c:6a:52:8e:0a:f2:1e:db:df:8f:cf:3b:91:fb: +e8:f1:06:d2:4b:79:29:de:fa:b9:b9:2a:88:ba:2e: +c4:ee:bd:e3:82:e5:9a:2e:3e:b5:e8:01:b5:1d:63: +9c:b5:72:54:8e:ab:22:69:b6:70:b2:9d:a1:d3:d8: +07:4f:39:87:11:70:4e:9a:20:11:bb:cc:45:c4:a0: +07:c6:cb:a8:ee:89:c0:6f + """ + + key = DSA.importKey(x509_v3_cert) + for comp_name in ('y', 'p', 'q', 'g'): + comp_str = locals()[comp_name + "_str"] + comp = int(re.sub("[^0-9a-f]", "", comp_str), 16) + self.assertEqual(getattr(key, comp_name), comp) + self.assertFalse(key.has_private()) + + +if __name__ == '__main__': + unittest.main() + +def get_tests(config={}): + tests = [] + tests += list_test_cases(ImportKeyTests) + tests += list_test_cases(ImportKeyFromX509Cert) + return tests + +if __name__ == '__main__': + suite = lambda: unittest.TestSuite(get_tests()) + unittest.main(defaultTest='suite') + diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/PublicKey/test_import_ECC.py b/venv/Lib/site-packages/Cryptodome/SelfTest/PublicKey/test_import_ECC.py new file mode 100644 index 0000000..ee80000 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/SelfTest/PublicKey/test_import_ECC.py @@ -0,0 +1,2782 @@ +# =================================================================== +# +# Copyright (c) 2015, Legrandin +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# =================================================================== + +import os +import errno +import warnings +import unittest +from binascii import unhexlify + +from Cryptodome.SelfTest.st_common import list_test_cases +from Cryptodome.Util.py3compat import bord, tostr, FileNotFoundError +from Cryptodome.Util.asn1 import DerSequence, DerBitString +from Cryptodome.Util.number import bytes_to_long +from Cryptodome.Hash import SHAKE128 + +from Cryptodome.PublicKey import ECC + +from Cryptodome.PublicKey.ECC import _import_rfc5915_der + +try: + import pycryptodome_test_vectors # type: ignore + test_vectors_available = True +except ImportError: + test_vectors_available = False + + +class MissingTestVectorException(ValueError): + pass + + +def load_file(file_name, mode="rb"): + results = None + + try: + if not test_vectors_available: + raise FileNotFoundError(errno.ENOENT, + os.strerror(errno.ENOENT), + file_name) + + dir_comps = ("PublicKey", "ECC") + init_dir = os.path.dirname(pycryptodome_test_vectors.__file__) + full_file_name = os.path.join(os.path.join(init_dir, *dir_comps), file_name) + with open(full_file_name, mode) as file_in: + results = file_in.read() + + except FileNotFoundError: + warnings.warn("Skipping extended tests for ECC", + UserWarning, + stacklevel=2) + + if results is None: + raise MissingTestVectorException("Missing %s" % file_name) + + return results + + +def compact(lines): + ext = b"".join(lines) + return unhexlify(tostr(ext).replace(" ", "").replace(":", "")) + + +def create_ref_keys_p192(): + key_len = 24 + key_lines = load_file("ecc_p192.txt").splitlines() + private_key_d = bytes_to_long(compact(key_lines[2:4])) + public_key_xy = compact(key_lines[5:9]) + assert bord(public_key_xy[0]) == 4 # Uncompressed + public_key_x = bytes_to_long(public_key_xy[1:key_len+1]) + public_key_y = bytes_to_long(public_key_xy[key_len+1:]) + + return (ECC.construct(curve="P-192", d=private_key_d), + ECC.construct(curve="P-192", point_x=public_key_x, point_y=public_key_y)) + + +def create_ref_keys_p224(): + key_len = 28 + key_lines = load_file("ecc_p224.txt").splitlines() + private_key_d = bytes_to_long(compact(key_lines[2:4])) + public_key_xy = compact(key_lines[5:9]) + assert bord(public_key_xy[0]) == 4 # Uncompressed + public_key_x = bytes_to_long(public_key_xy[1:key_len+1]) + public_key_y = bytes_to_long(public_key_xy[key_len+1:]) + + return (ECC.construct(curve="P-224", d=private_key_d), + ECC.construct(curve="P-224", point_x=public_key_x, point_y=public_key_y)) + + +def create_ref_keys_p256(): + key_len = 32 + key_lines = load_file("ecc_p256.txt").splitlines() + private_key_d = bytes_to_long(compact(key_lines[2:5])) + public_key_xy = compact(key_lines[6:11]) + assert bord(public_key_xy[0]) == 4 # Uncompressed + public_key_x = bytes_to_long(public_key_xy[1:key_len+1]) + public_key_y = bytes_to_long(public_key_xy[key_len+1:]) + + return (ECC.construct(curve="P-256", d=private_key_d), + ECC.construct(curve="P-256", point_x=public_key_x, point_y=public_key_y)) + + +def create_ref_keys_p384(): + key_len = 48 + key_lines = load_file("ecc_p384.txt").splitlines() + private_key_d = bytes_to_long(compact(key_lines[2:6])) + public_key_xy = compact(key_lines[7:14]) + assert bord(public_key_xy[0]) == 4 # Uncompressed + public_key_x = bytes_to_long(public_key_xy[1:key_len+1]) + public_key_y = bytes_to_long(public_key_xy[key_len+1:]) + + return (ECC.construct(curve="P-384", d=private_key_d), + ECC.construct(curve="P-384", point_x=public_key_x, point_y=public_key_y)) + + +def create_ref_keys_p521(): + key_len = 66 + key_lines = load_file("ecc_p521.txt").splitlines() + private_key_d = bytes_to_long(compact(key_lines[2:7])) + public_key_xy = compact(key_lines[8:17]) + assert bord(public_key_xy[0]) == 4 # Uncompressed + public_key_x = bytes_to_long(public_key_xy[1:key_len+1]) + public_key_y = bytes_to_long(public_key_xy[key_len+1:]) + + return (ECC.construct(curve="P-521", d=private_key_d), + ECC.construct(curve="P-521", point_x=public_key_x, point_y=public_key_y)) + + +def create_ref_keys_ed25519(): + key_lines = load_file("ecc_ed25519.txt").splitlines() + seed = compact(key_lines[5:8]) + key = ECC.construct(curve="Ed25519", seed=seed) + return (key, key.public_key()) + + +def create_ref_keys_ed448(): + key_lines = load_file("ecc_ed448.txt").splitlines() + seed = compact(key_lines[6:10]) + key = ECC.construct(curve="Ed448", seed=seed) + return (key, key.public_key()) + + +# Create reference key pair +# ref_private, ref_public = create_ref_keys_p521() + +def get_fixed_prng(): + return SHAKE128.new().update(b"SEED").read + + +def extract_bitstring_from_spki(data): + seq = DerSequence() + seq.decode(data) + bs = DerBitString() + bs.decode(seq[1]) + return bs.value + + +class TestImport(unittest.TestCase): + + def test_empty(self): + self.assertRaises(ValueError, ECC.import_key, b"") + + def test_mismatch(self): + # The private key does not match the public key + mismatch = """-----BEGIN PRIVATE KEY----- +MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJChZANiAAQarFRaqflo +I+d61SRvU8Za2EurxtW20eZzca7dnNYMYf3boIkDuAUU7FfO7l0/4iGzzvfUinng +o4N+LZfQYcTxmdwlkWOrfzCjtHDix6EznPO/LlxTsV+zfTJ/ijTjeXk= +-----END PRIVATE KEY-----""" + self.assertRaises(ValueError, ECC.import_key, mismatch) + + def test_import_private_rfc5915_none(self): + # ECPrivateKey with a P256 private key, without [0] and [1] + data_hex = "302502010104205c4e4320ef260f91ed9fc597aee98c8236b60e0ced692cc7a057d5e45798a052" + key = _import_rfc5915_der(unhexlify(data_hex), None, "1.2.840.10045.3.1.7") + self.assertEqual(key.d, 0x5c4e4320ef260f91ed9fc597aee98c8236b60e0ced692cc7a057d5e45798a052) + + def test_import_private_rfc5915_only_0(self): + # ECPrivateKey with a P256 private key, with [0] only + data_hex = "303102010104205c4e4320ef260f91ed9fc597aee98c8236b60e0ced692cc7a057d5e45798a052a00a06082a8648ce3d030107" + key = _import_rfc5915_der(unhexlify(data_hex), None) + self.assertEqual(key.d, 0x5c4e4320ef260f91ed9fc597aee98c8236b60e0ced692cc7a057d5e45798a052) + + def test_import_private_rfc5915_only_1(self): + # ECPrivateKey with a P256 private key, with [1] only + data_hex = "306b02010104205c4e4320ef260f91ed9fc597aee98c8236b60e0ced692cc7a057d5e45798a052a14403420004a40ad59a2050ebe92479bd5fb16bb2e45b6465eb3cb2b1effe423fabe6cb7424db8219ef0bab80acf26fd70595b61fe4760d33eed80dd03d2fd0dfb27b8ce75c" + key = _import_rfc5915_der(unhexlify(data_hex), None, "1.2.840.10045.3.1.7") + self.assertEqual(key.d, 0x5c4e4320ef260f91ed9fc597aee98c8236b60e0ced692cc7a057d5e45798a052) + +class TestImport_P192(unittest.TestCase): + + def __init__(self, *args, **kwargs): + super(TestImport_P192, self).__init__(*args, **kwargs) + self.ref_private, self.ref_public = create_ref_keys_p192() + + def test_import_public_der(self): + key_file = load_file("ecc_p192_public.der") + + key = ECC._import_subjectPublicKeyInfo(key_file) + self.assertEqual(self.ref_public, key) + + key = ECC._import_der(key_file, None) + self.assertEqual(self.ref_public, key) + + key = ECC.import_key(key_file) + self.assertEqual(self.ref_public, key) + + def test_import_sec1_uncompressed(self): + key_file = load_file("ecc_p192_public.der") + value = extract_bitstring_from_spki(key_file) + key = ECC.import_key(key_file, curve_name='P192') + self.assertEqual(self.ref_public, key) + + def test_import_sec1_compressed(self): + key_file = load_file("ecc_p192_public_compressed.der") + value = extract_bitstring_from_spki(key_file) + key = ECC.import_key(key_file, curve_name='P192') + self.assertEqual(self.ref_public, key) + + def test_import_rfc5915_der(self): + key_file = load_file("ecc_p192_private.der") + + key = ECC._import_rfc5915_der(key_file, None) + self.assertEqual(self.ref_private, key) + + key = ECC._import_der(key_file, None) + self.assertEqual(self.ref_private, key) + + key = ECC.import_key(key_file) + self.assertEqual(self.ref_private, key) + + def test_import_private_pkcs8_clear(self): + key_file = load_file("ecc_p192_private_p8_clear.der") + + key = ECC._import_der(key_file, None) + self.assertEqual(self.ref_private, key) + + key = ECC.import_key(key_file) + self.assertEqual(self.ref_private, key) + + def test_import_private_pkcs8_in_pem_clear(self): + key_file = load_file("ecc_p192_private_p8_clear.pem") + + key = ECC.import_key(key_file) + self.assertEqual(self.ref_private, key) + + def test_import_private_pkcs8_encrypted_1(self): + key_file = load_file("ecc_p192_private_p8.der") + + key = ECC._import_der(key_file, "secret") + self.assertEqual(self.ref_private, key) + + key = ECC.import_key(key_file, "secret") + self.assertEqual(self.ref_private, key) + + def test_import_private_pkcs8_encrypted_2(self): + key_file = load_file("ecc_p192_private_p8.pem") + + key = ECC.import_key(key_file, "secret") + self.assertEqual(self.ref_private, key) + + def test_import_x509_der(self): + key_file = load_file("ecc_p192_x509.der") + + key = ECC._import_der(key_file, None) + self.assertEqual(self.ref_public, key) + + key = ECC.import_key(key_file) + self.assertEqual(self.ref_public, key) + + def test_import_public_pem(self): + key_file = load_file("ecc_p192_public.pem") + + key = ECC.import_key(key_file) + self.assertEqual(self.ref_public, key) + + def test_import_private_pem(self): + key_file = load_file("ecc_p192_private.pem") + + key = ECC.import_key(key_file) + self.assertEqual(self.ref_private, key) + + def test_import_private_pem_encrypted(self): + for algo in "des3", "aes128", "aes192", "aes256", "aes256_gcm": + key_file = load_file("ecc_p192_private_enc_%s.pem" % algo) + + key = ECC.import_key(key_file, "secret") + self.assertEqual(self.ref_private, key) + + key = ECC.import_key(tostr(key_file), b"secret") + self.assertEqual(self.ref_private, key) + + def test_import_x509_pem(self): + key_file = load_file("ecc_p192_x509.pem") + + key = ECC.import_key(key_file) + self.assertEqual(self.ref_public, key) + + +class TestImport_P224(unittest.TestCase): + + def __init__(self, *args, **kwargs): + super(TestImport_P224, self).__init__(*args, **kwargs) + self.ref_private, self.ref_public = create_ref_keys_p224() + + def test_import_public_der(self): + key_file = load_file("ecc_p224_public.der") + + key = ECC._import_subjectPublicKeyInfo(key_file) + self.assertEqual(self.ref_public, key) + + key = ECC._import_der(key_file, None) + self.assertEqual(self.ref_public, key) + + key = ECC.import_key(key_file) + self.assertEqual(self.ref_public, key) + + def test_import_sec1_uncompressed(self): + key_file = load_file("ecc_p224_public.der") + value = extract_bitstring_from_spki(key_file) + key = ECC.import_key(key_file, curve_name='P224') + self.assertEqual(self.ref_public, key) + + def test_import_sec1_compressed(self): + key_file = load_file("ecc_p224_public_compressed.der") + value = extract_bitstring_from_spki(key_file) + key = ECC.import_key(key_file, curve_name='P224') + self.assertEqual(self.ref_public, key) + + def test_import_rfc5915_der(self): + key_file = load_file("ecc_p224_private.der") + + key = ECC._import_rfc5915_der(key_file, None) + self.assertEqual(self.ref_private, key) + + key = ECC._import_der(key_file, None) + self.assertEqual(self.ref_private, key) + + key = ECC.import_key(key_file) + self.assertEqual(self.ref_private, key) + + def test_import_private_pkcs8_clear(self): + key_file = load_file("ecc_p224_private_p8_clear.der") + + key = ECC._import_der(key_file, None) + self.assertEqual(self.ref_private, key) + + key = ECC.import_key(key_file) + self.assertEqual(self.ref_private, key) + + def test_import_private_pkcs8_in_pem_clear(self): + key_file = load_file("ecc_p224_private_p8_clear.pem") + + key = ECC.import_key(key_file) + self.assertEqual(self.ref_private, key) + + def test_import_private_pkcs8_encrypted_1(self): + key_file = load_file("ecc_p224_private_p8.der") + + key = ECC._import_der(key_file, "secret") + self.assertEqual(self.ref_private, key) + + key = ECC.import_key(key_file, "secret") + self.assertEqual(self.ref_private, key) + + def test_import_private_pkcs8_encrypted_2(self): + key_file = load_file("ecc_p224_private_p8.pem") + + key = ECC.import_key(key_file, "secret") + self.assertEqual(self.ref_private, key) + + def test_import_private_pkcs8_encrypted_3(self): + key_file = load_file("ecc_p224_private_p8_2.der") + + key = ECC._import_der(key_file, "secret") + self.assertEqual(self.ref_private, key) + + key = ECC.import_key(key_file, "secret") + self.assertEqual(self.ref_private, key) + + def test_import_x509_der(self): + key_file = load_file("ecc_p224_x509.der") + + key = ECC._import_der(key_file, None) + self.assertEqual(self.ref_public, key) + + key = ECC.import_key(key_file) + self.assertEqual(self.ref_public, key) + + def test_import_public_pem(self): + key_file = load_file("ecc_p224_public.pem") + + key = ECC.import_key(key_file) + self.assertEqual(self.ref_public, key) + + def test_import_private_pem(self): + key_file = load_file("ecc_p224_private.pem") + + key = ECC.import_key(key_file) + self.assertEqual(self.ref_private, key) + + def test_import_private_pem_encrypted(self): + for algo in "des3", "aes128", "aes192", "aes256", "aes256_gcm": + key_file = load_file("ecc_p224_private_enc_%s.pem" % algo) + + key = ECC.import_key(key_file, "secret") + self.assertEqual(self.ref_private, key) + + key = ECC.import_key(tostr(key_file), b"secret") + self.assertEqual(self.ref_private, key) + + def test_import_x509_pem(self): + key_file = load_file("ecc_p224_x509.pem") + + key = ECC.import_key(key_file) + self.assertEqual(self.ref_public, key) + + +class TestImport_P256(unittest.TestCase): + + def __init__(self, *args, **kwargs): + super(TestImport_P256, self).__init__(*args, **kwargs) + self.ref_private, self.ref_public = create_ref_keys_p256() + + def test_import_public_der(self): + key_file = load_file("ecc_p256_public.der") + + key = ECC._import_subjectPublicKeyInfo(key_file) + self.assertEqual(self.ref_public, key) + + key = ECC._import_der(key_file, None) + self.assertEqual(self.ref_public, key) + + key = ECC.import_key(key_file) + self.assertEqual(self.ref_public, key) + + def test_import_sec1_uncompressed(self): + key_file = load_file("ecc_p256_public.der") + value = extract_bitstring_from_spki(key_file) + key = ECC.import_key(key_file, curve_name='P256') + self.assertEqual(self.ref_public, key) + + def test_import_sec1_compressed(self): + key_file = load_file("ecc_p256_public_compressed.der") + value = extract_bitstring_from_spki(key_file) + key = ECC.import_key(key_file, curve_name='P256') + self.assertEqual(self.ref_public, key) + + def test_import_rfc5915_der(self): + key_file = load_file("ecc_p256_private.der") + + key = ECC._import_rfc5915_der(key_file, None) + self.assertEqual(self.ref_private, key) + + key = ECC._import_der(key_file, None) + self.assertEqual(self.ref_private, key) + + key = ECC.import_key(key_file) + self.assertEqual(self.ref_private, key) + + def test_import_private_pkcs8_clear(self): + key_file = load_file("ecc_p256_private_p8_clear.der") + + key = ECC._import_der(key_file, None) + self.assertEqual(self.ref_private, key) + + key = ECC.import_key(key_file) + self.assertEqual(self.ref_private, key) + + def test_import_private_pkcs8_in_pem_clear(self): + key_file = load_file("ecc_p256_private_p8_clear.pem") + + key = ECC.import_key(key_file) + self.assertEqual(self.ref_private, key) + + def test_import_private_pkcs8_encrypted_1(self): + key_file = load_file("ecc_p256_private_p8.der") + + key = ECC._import_der(key_file, "secret") + self.assertEqual(self.ref_private, key) + + key = ECC.import_key(key_file, "secret") + self.assertEqual(self.ref_private, key) + + def test_import_private_pkcs8_encrypted_2(self): + key_file = load_file("ecc_p256_private_p8.pem") + + key = ECC.import_key(key_file, "secret") + self.assertEqual(self.ref_private, key) + + def test_import_private_pkcs8_encrypted_3(self): + key_file = load_file("ecc_p256_private_p8_2.der") + + key = ECC._import_der(key_file, "secret") + self.assertEqual(self.ref_private, key) + + key = ECC.import_key(key_file, "secret") + self.assertEqual(self.ref_private, key) + + def test_import_x509_der(self): + key_file = load_file("ecc_p256_x509.der") + + key = ECC._import_der(key_file, None) + self.assertEqual(self.ref_public, key) + + key = ECC.import_key(key_file) + self.assertEqual(self.ref_public, key) + + def test_import_public_pem(self): + key_file = load_file("ecc_p256_public.pem") + + key = ECC.import_key(key_file) + self.assertEqual(self.ref_public, key) + + def test_import_private_pem(self): + key_file = load_file("ecc_p256_private.pem") + + key = ECC.import_key(key_file) + self.assertEqual(self.ref_private, key) + + def test_import_private_pem_with_ecparams(self): + key_file = load_file("ecc_p256_private_ecparams.pem") + key = ECC.import_key(key_file) + # We just check if the import succeeds + + def test_import_private_pem_encrypted(self): + for algo in "des3", "aes128", "aes192", "aes256", "aes256_gcm": + key_file = load_file("ecc_p256_private_enc_%s.pem" % algo) + + key = ECC.import_key(key_file, "secret") + self.assertEqual(self.ref_private, key) + + key = ECC.import_key(tostr(key_file), b"secret") + self.assertEqual(self.ref_private, key) + + def test_import_x509_pem(self): + key_file = load_file("ecc_p256_x509.pem") + + key = ECC.import_key(key_file) + self.assertEqual(self.ref_public, key) + + def test_import_openssh_public(self): + key_file = load_file("ecc_p256_public_openssh.txt") + + key = ECC._import_openssh_public(key_file) + self.assertEqual(self.ref_public, key) + + key = ECC.import_key(key_file) + self.assertEqual(self.ref_public, key) + + def test_import_openssh_private_clear(self): + key_file = load_file("ecc_p256_private_openssh.pem") + key_file_old = load_file("ecc_p256_private_openssh_old.pem") + + key = ECC.import_key(key_file) + key_old = ECC.import_key(key_file_old) + self.assertEqual(key, key_old) + + def test_import_openssh_private_password(self): + key_file = load_file("ecc_p256_private_openssh_pwd.pem") + key_file_old = load_file("ecc_p256_private_openssh_pwd_old.pem") + + key = ECC.import_key(key_file, b"password") + key_old = ECC.import_key(key_file_old) + self.assertEqual(key, key_old) + + +class TestImport_P384(unittest.TestCase): + + def __init__(self, *args, **kwargs): + super(TestImport_P384, self).__init__(*args, **kwargs) + self.ref_private, self.ref_public = create_ref_keys_p384() + + def test_import_public_der(self): + key_file = load_file("ecc_p384_public.der") + + key = ECC._import_subjectPublicKeyInfo(key_file) + self.assertEqual(self.ref_public, key) + + key = ECC._import_der(key_file, None) + self.assertEqual(self.ref_public, key) + + key = ECC.import_key(key_file) + self.assertEqual(self.ref_public, key) + + def test_import_sec1_uncompressed(self): + key_file = load_file("ecc_p384_public.der") + value = extract_bitstring_from_spki(key_file) + key = ECC.import_key(key_file, curve_name='P384') + self.assertEqual(self.ref_public, key) + + def test_import_sec1_compressed(self): + key_file = load_file("ecc_p384_public_compressed.der") + value = extract_bitstring_from_spki(key_file) + key = ECC.import_key(key_file, curve_name='P384') + self.assertEqual(self.ref_public, key) + + def test_import_rfc5915_der(self): + key_file = load_file("ecc_p384_private.der") + + key = ECC._import_rfc5915_der(key_file, None) + self.assertEqual(self.ref_private, key) + + key = ECC._import_der(key_file, None) + self.assertEqual(self.ref_private, key) + + key = ECC.import_key(key_file) + self.assertEqual(self.ref_private, key) + + def test_import_private_pkcs8_clear(self): + key_file = load_file("ecc_p384_private_p8_clear.der") + + key = ECC._import_der(key_file, None) + self.assertEqual(self.ref_private, key) + + key = ECC.import_key(key_file) + self.assertEqual(self.ref_private, key) + + def test_import_private_pkcs8_in_pem_clear(self): + key_file = load_file("ecc_p384_private_p8_clear.pem") + + key = ECC.import_key(key_file) + self.assertEqual(self.ref_private, key) + + def test_import_private_pkcs8_encrypted_1(self): + key_file = load_file("ecc_p384_private_p8.der") + + key = ECC._import_der(key_file, "secret") + self.assertEqual(self.ref_private, key) + + key = ECC.import_key(key_file, "secret") + self.assertEqual(self.ref_private, key) + + def test_import_private_pkcs8_encrypted_2(self): + key_file = load_file("ecc_p384_private_p8.pem") + + key = ECC.import_key(key_file, "secret") + self.assertEqual(self.ref_private, key) + + def test_import_private_pkcs8_encrypted_3(self): + key_file = load_file("ecc_p384_private_p8_2.der") + + key = ECC._import_der(key_file, "secret") + self.assertEqual(self.ref_private, key) + + key = ECC.import_key(key_file, "secret") + self.assertEqual(self.ref_private, key) + + def test_import_x509_der(self): + key_file = load_file("ecc_p384_x509.der") + + key = ECC._import_der(key_file, None) + self.assertEqual(self.ref_public, key) + + key = ECC.import_key(key_file) + self.assertEqual(self.ref_public, key) + + def test_import_public_pem(self): + key_file = load_file("ecc_p384_public.pem") + + key = ECC.import_key(key_file) + self.assertEqual(self.ref_public, key) + + def test_import_private_pem(self): + key_file = load_file("ecc_p384_private.pem") + + key = ECC.import_key(key_file) + self.assertEqual(self.ref_private, key) + + def test_import_private_pem_encrypted(self): + for algo in "des3", "aes128", "aes192", "aes256", "aes256_gcm": + key_file = load_file("ecc_p384_private_enc_%s.pem" % algo) + + key = ECC.import_key(key_file, "secret") + self.assertEqual(self.ref_private, key) + + key = ECC.import_key(tostr(key_file), b"secret") + self.assertEqual(self.ref_private, key) + + def test_import_x509_pem(self): + key_file = load_file("ecc_p384_x509.pem") + + key = ECC.import_key(key_file) + self.assertEqual(self.ref_public, key) + + def test_import_openssh_public(self): + key_file = load_file("ecc_p384_public_openssh.txt") + + key = ECC._import_openssh_public(key_file) + self.assertEqual(self.ref_public, key) + + key = ECC.import_key(key_file) + self.assertEqual(self.ref_public, key) + + def test_import_openssh_private_clear(self): + key_file = load_file("ecc_p384_private_openssh.pem") + key_file_old = load_file("ecc_p384_private_openssh_old.pem") + + key = ECC.import_key(key_file) + key_old = ECC.import_key(key_file_old) + self.assertEqual(key, key_old) + + def test_import_openssh_private_password(self): + key_file = load_file("ecc_p384_private_openssh_pwd.pem") + key_file_old = load_file("ecc_p384_private_openssh_pwd_old.pem") + + key = ECC.import_key(key_file, b"password") + key_old = ECC.import_key(key_file_old) + self.assertEqual(key, key_old) + + +class TestImport_P521(unittest.TestCase): + + def __init__(self, *args, **kwargs): + super(TestImport_P521, self).__init__(*args, **kwargs) + self.ref_private, self.ref_public = create_ref_keys_p521() + + def test_import_public_der(self): + key_file = load_file("ecc_p521_public.der") + + key = ECC._import_subjectPublicKeyInfo(key_file) + self.assertEqual(self.ref_public, key) + + key = ECC._import_der(key_file, None) + self.assertEqual(self.ref_public, key) + + key = ECC.import_key(key_file) + self.assertEqual(self.ref_public, key) + + def test_import_sec1_uncompressed(self): + key_file = load_file("ecc_p521_public.der") + value = extract_bitstring_from_spki(key_file) + key = ECC.import_key(key_file, curve_name='P521') + self.assertEqual(self.ref_public, key) + + def test_import_sec1_compressed(self): + key_file = load_file("ecc_p521_public_compressed.der") + value = extract_bitstring_from_spki(key_file) + key = ECC.import_key(key_file, curve_name='P521') + self.assertEqual(self.ref_public, key) + + def test_import_rfc5915_der(self): + key_file = load_file("ecc_p521_private.der") + + key = ECC._import_rfc5915_der(key_file, None) + self.assertEqual(self.ref_private, key) + + key = ECC._import_der(key_file, None) + self.assertEqual(self.ref_private, key) + + key = ECC.import_key(key_file) + self.assertEqual(self.ref_private, key) + + def test_import_private_pkcs8_clear(self): + key_file = load_file("ecc_p521_private_p8_clear.der") + + key = ECC._import_der(key_file, None) + self.assertEqual(self.ref_private, key) + + key = ECC.import_key(key_file) + self.assertEqual(self.ref_private, key) + + def test_import_private_pkcs8_in_pem_clear(self): + key_file = load_file("ecc_p521_private_p8_clear.pem") + + key = ECC.import_key(key_file) + self.assertEqual(self.ref_private, key) + + def test_import_private_pkcs8_encrypted_1(self): + key_file = load_file("ecc_p521_private_p8.der") + + key = ECC._import_der(key_file, "secret") + self.assertEqual(self.ref_private, key) + + key = ECC.import_key(key_file, "secret") + self.assertEqual(self.ref_private, key) + + def test_import_private_pkcs8_encrypted_2(self): + key_file = load_file("ecc_p521_private_p8.pem") + + key = ECC.import_key(key_file, "secret") + self.assertEqual(self.ref_private, key) + + def test_import_private_pkcs8_encrypted_3(self): + key_file = load_file("ecc_p521_private_p8_2.der") + + key = ECC._import_der(key_file, "secret") + self.assertEqual(self.ref_private, key) + + key = ECC.import_key(key_file, "secret") + self.assertEqual(self.ref_private, key) + + def test_import_x509_der(self): + key_file = load_file("ecc_p521_x509.der") + + key = ECC._import_der(key_file, None) + self.assertEqual(self.ref_public, key) + + key = ECC.import_key(key_file) + self.assertEqual(self.ref_public, key) + + def test_import_public_pem(self): + key_file = load_file("ecc_p521_public.pem") + + key = ECC.import_key(key_file) + self.assertEqual(self.ref_public, key) + + def test_import_private_pem(self): + key_file = load_file("ecc_p521_private.pem") + + key = ECC.import_key(key_file) + self.assertEqual(self.ref_private, key) + + def test_import_private_pem_encrypted(self): + for algo in "des3", "aes128", "aes192", "aes256", "aes256_gcm": + key_file = load_file("ecc_p521_private_enc_%s.pem" % algo) + + key = ECC.import_key(key_file, "secret") + self.assertEqual(self.ref_private, key) + + key = ECC.import_key(tostr(key_file), b"secret") + self.assertEqual(self.ref_private, key) + + def test_import_x509_pem(self): + key_file = load_file("ecc_p521_x509.pem") + + key = ECC.import_key(key_file) + self.assertEqual(self.ref_public, key) + + def test_import_openssh_public(self): + key_file = load_file("ecc_p521_public_openssh.txt") + + key = ECC._import_openssh_public(key_file) + self.assertEqual(self.ref_public, key) + + key = ECC.import_key(key_file) + self.assertEqual(self.ref_public, key) + + def test_import_openssh_private_clear(self): + key_file = load_file("ecc_p521_private_openssh.pem") + key_file_old = load_file("ecc_p521_private_openssh_old.pem") + + key = ECC.import_key(key_file) + key_old = ECC.import_key(key_file_old) + self.assertEqual(key, key_old) + + def test_import_openssh_private_password(self): + key_file = load_file("ecc_p521_private_openssh_pwd.pem") + key_file_old = load_file("ecc_p521_private_openssh_pwd_old.pem") + + key = ECC.import_key(key_file, b"password") + key_old = ECC.import_key(key_file_old) + self.assertEqual(key, key_old) + + +class TestExport_P192(unittest.TestCase): + + def __init__(self, *args, **kwargs): + super(TestExport_P192, self).__init__(*args, **kwargs) + self.ref_private, self.ref_public = create_ref_keys_p192() + + def test_export_public_der_uncompressed(self): + key_file = load_file("ecc_p192_public.der") + + encoded = self.ref_public._export_subjectPublicKeyInfo(False) + self.assertEqual(key_file, encoded) + + encoded = self.ref_public.export_key(format="DER") + self.assertEqual(key_file, encoded) + + encoded = self.ref_public.export_key(format="DER", compress=False) + self.assertEqual(key_file, encoded) + + def test_export_public_der_compressed(self): + key_file = load_file("ecc_p192_public.der") + pub_key = ECC.import_key(key_file) + key_file_compressed = pub_key.export_key(format="DER", compress=True) + + key_file_compressed_ref = load_file("ecc_p192_public_compressed.der") + self.assertEqual(key_file_compressed, key_file_compressed_ref) + + def test_export_public_sec1_uncompressed(self): + key_file = load_file("ecc_p192_public.der") + value = extract_bitstring_from_spki(key_file) + + encoded = self.ref_public.export_key(format="SEC1") + self.assertEqual(value, encoded) + + def test_export_public_sec1_compressed(self): + key_file = load_file("ecc_p192_public.der") + encoded = self.ref_public.export_key(format="SEC1", compress=True) + + key_file_compressed_ref = load_file("ecc_p192_public_compressed.der") + value = extract_bitstring_from_spki(key_file_compressed_ref) + self.assertEqual(value, encoded) + + def test_export_rfc5915_private_der(self): + key_file = load_file("ecc_p192_private.der") + + encoded = self.ref_private._export_rfc5915_private_der() + self.assertEqual(key_file, encoded) + + # --- + + encoded = self.ref_private.export_key(format="DER", use_pkcs8=False) + self.assertEqual(key_file, encoded) + + def test_export_private_pkcs8_clear(self): + key_file = load_file("ecc_p192_private_p8_clear.der") + + encoded = self.ref_private._export_pkcs8() + self.assertEqual(key_file, encoded) + + # --- + + encoded = self.ref_private.export_key(format="DER") + self.assertEqual(key_file, encoded) + + def test_export_private_pkcs8_encrypted(self): + encoded = self.ref_private._export_pkcs8(passphrase="secret", + protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") + + # This should prove that the output is password-protected + self.assertRaises(ValueError, ECC._import_pkcs8, encoded, None) + + decoded = ECC._import_pkcs8(encoded, "secret") + self.assertEqual(self.ref_private, decoded) + + # --- + + encoded = self.ref_private.export_key(format="DER", + passphrase="secret", + protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") + decoded = ECC.import_key(encoded, "secret") + self.assertEqual(self.ref_private, decoded) + + # --- + + encoded = self.ref_private.export_key(format="DER", + passphrase="secret", + protection="PBKDF2WithHMAC-SHA224AndAES192-CBC", + prot_params={'iteration_count':123}) + decoded = ECC.import_key(encoded, "secret") + self.assertEqual(self.ref_private, decoded) + + def test_export_public_pem_uncompressed(self): + key_file = load_file("ecc_p192_public.pem", "rt").strip() + + encoded = self.ref_private._export_public_pem(False) + self.assertEqual(key_file, encoded) + + # --- + + encoded = self.ref_public.export_key(format="PEM") + self.assertEqual(key_file, encoded) + + encoded = self.ref_public.export_key(format="PEM", compress=False) + self.assertEqual(key_file, encoded) + + def test_export_public_pem_compressed(self): + key_file = load_file("ecc_p192_public.pem", "rt").strip() + pub_key = ECC.import_key(key_file) + + key_file_compressed = pub_key.export_key(format="PEM", compress=True) + key_file_compressed_ref = load_file("ecc_p192_public_compressed.pem", "rt").strip() + + self.assertEqual(key_file_compressed, key_file_compressed_ref) + + def test_export_private_pem_clear(self): + key_file = load_file("ecc_p192_private.pem", "rt").strip() + + encoded = self.ref_private._export_private_pem(None) + self.assertEqual(key_file, encoded) + + # --- + + encoded = self.ref_private.export_key(format="PEM", use_pkcs8=False) + self.assertEqual(key_file, encoded) + + def test_export_private_pem_encrypted(self): + encoded = self.ref_private._export_private_pem(passphrase=b"secret") + + # This should prove that the output is password-protected + self.assertRaises(ValueError, ECC.import_key, encoded) + + assert "EC PRIVATE KEY" in encoded + + decoded = ECC.import_key(encoded, "secret") + self.assertEqual(self.ref_private, decoded) + + # --- + + encoded = self.ref_private.export_key(format="PEM", + passphrase="secret", + use_pkcs8=False) + decoded = ECC.import_key(encoded, "secret") + self.assertEqual(self.ref_private, decoded) + + def test_export_private_pkcs8_and_pem_1(self): + # PKCS8 inside PEM with both unencrypted + key_file = load_file("ecc_p192_private_p8_clear.pem", "rt").strip() + + encoded = self.ref_private._export_private_clear_pkcs8_in_clear_pem() + self.assertEqual(key_file, encoded) + + # --- + + encoded = self.ref_private.export_key(format="PEM") + self.assertEqual(key_file, encoded) + + def test_export_private_pkcs8_and_pem_2(self): + # PKCS8 inside PEM with PKCS8 encryption + encoded = self.ref_private._export_private_encrypted_pkcs8_in_clear_pem("secret", + protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") + + # This should prove that the output is password-protected + self.assertRaises(ValueError, ECC.import_key, encoded) + + assert "ENCRYPTED PRIVATE KEY" in encoded + + decoded = ECC.import_key(encoded, "secret") + self.assertEqual(self.ref_private, decoded) + + # --- + + encoded = self.ref_private.export_key(format="PEM", + passphrase="secret", + protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") + decoded = ECC.import_key(encoded, "secret") + self.assertEqual(self.ref_private, decoded) + + def test_prng(self): + # Test that password-protected containers use the provided PRNG + encoded1 = self.ref_private.export_key(format="PEM", + passphrase="secret", + protection="PBKDF2WithHMAC-SHA1AndAES128-CBC", + randfunc=get_fixed_prng()) + encoded2 = self.ref_private.export_key(format="PEM", + passphrase="secret", + protection="PBKDF2WithHMAC-SHA1AndAES128-CBC", + randfunc=get_fixed_prng()) + self.assertEqual(encoded1, encoded2) + + # --- + + encoded1 = self.ref_private.export_key(format="PEM", + use_pkcs8=False, + passphrase="secret", + randfunc=get_fixed_prng()) + encoded2 = self.ref_private.export_key(format="PEM", + use_pkcs8=False, + passphrase="secret", + randfunc=get_fixed_prng()) + self.assertEqual(encoded1, encoded2) + + def test_byte_or_string_passphrase(self): + encoded1 = self.ref_private.export_key(format="PEM", + use_pkcs8=False, + passphrase="secret", + randfunc=get_fixed_prng()) + encoded2 = self.ref_private.export_key(format="PEM", + use_pkcs8=False, + passphrase=b"secret", + randfunc=get_fixed_prng()) + self.assertEqual(encoded1, encoded2) + + def test_error_params1(self): + # Unknown format + self.assertRaises(ValueError, self.ref_private.export_key, format="XXX") + + # Missing 'protection' parameter when PKCS#8 is used + self.ref_private.export_key(format="PEM", passphrase="secret", + use_pkcs8=False) + self.assertRaises(ValueError, self.ref_private.export_key, format="PEM", + passphrase="secret") + + # DER format but no PKCS#8 + self.assertRaises(ValueError, self.ref_private.export_key, format="DER", + passphrase="secret", + use_pkcs8=False, + protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") + + # Incorrect parameters for public keys + self.assertRaises(ValueError, self.ref_public.export_key, format="DER", + use_pkcs8=False) + + # Empty password + self.assertRaises(ValueError, self.ref_private.export_key, format="PEM", + passphrase="", use_pkcs8=False) + self.assertRaises(ValueError, self.ref_private.export_key, format="PEM", + passphrase="", + protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") + + def test_compressed_curve(self): + + # Compressed P-192 curve (Y-point is even) + pem1 = """-----BEGIN EC PRIVATE KEY----- + MF8CAQEEGHvhXmIW95JxZYfd4AUPu9BwknjuvS36aqAKBggqhkjOPQMBAaE0AzIA + BLJZCyTu35DQIlqvMlBynn3k1Ig+dWfg/brRhHecxptrbloqFSP8ITw0CwbGF+2X + 5g== + -----END EC PRIVATE KEY-----""" + + # Compressed P-192 curve (Y-point is odd) + pem2 = """-----BEGIN EC PRIVATE KEY----- + MF8CAQEEGA3rAotUaWl7d47eX6tz9JmLzOMJwl13XaAKBggqhkjOPQMBAaE0AzIA + BG4tHlTBBBGokcWmGm2xubVB0NvPC/Ou5AYwivs+3iCxmEjsymVAj6iiuX2Lxr6g + /Q== + -----END EC PRIVATE KEY-----""" + + key1 = ECC.import_key(pem1) + low16 = int(key1.pointQ.y % 65536) + self.assertEqual(low16, 0x97E6) + + key2 = ECC.import_key(pem2) + low16 = int(key2.pointQ.y % 65536) + self.assertEqual(low16, 0xA0FD) + + +class TestExport_P224(unittest.TestCase): + + def __init__(self, *args, **kwargs): + super(TestExport_P224, self).__init__(*args, **kwargs) + self.ref_private, self.ref_public = create_ref_keys_p224() + + def test_export_public_der_uncompressed(self): + key_file = load_file("ecc_p224_public.der") + + encoded = self.ref_public._export_subjectPublicKeyInfo(False) + self.assertEqual(key_file, encoded) + + encoded = self.ref_public.export_key(format="DER") + self.assertEqual(key_file, encoded) + + encoded = self.ref_public.export_key(format="DER", compress=False) + self.assertEqual(key_file, encoded) + + def test_export_public_der_compressed(self): + key_file = load_file("ecc_p224_public.der") + pub_key = ECC.import_key(key_file) + key_file_compressed = pub_key.export_key(format="DER", compress=True) + + key_file_compressed_ref = load_file("ecc_p224_public_compressed.der") + self.assertEqual(key_file_compressed, key_file_compressed_ref) + + def test_export_public_sec1_uncompressed(self): + key_file = load_file("ecc_p224_public.der") + value = extract_bitstring_from_spki(key_file) + + encoded = self.ref_public.export_key(format="SEC1") + self.assertEqual(value, encoded) + + def test_export_public_sec1_compressed(self): + key_file = load_file("ecc_p224_public.der") + encoded = self.ref_public.export_key(format="SEC1", compress=True) + + key_file_compressed_ref = load_file("ecc_p224_public_compressed.der") + value = extract_bitstring_from_spki(key_file_compressed_ref) + self.assertEqual(value, encoded) + + def test_export_rfc5915_private_der(self): + key_file = load_file("ecc_p224_private.der") + + encoded = self.ref_private._export_rfc5915_private_der() + self.assertEqual(key_file, encoded) + + # --- + + encoded = self.ref_private.export_key(format="DER", use_pkcs8=False) + self.assertEqual(key_file, encoded) + + def test_export_private_pkcs8_clear(self): + key_file = load_file("ecc_p224_private_p8_clear.der") + + encoded = self.ref_private._export_pkcs8() + self.assertEqual(key_file, encoded) + + # --- + + encoded = self.ref_private.export_key(format="DER") + self.assertEqual(key_file, encoded) + + def test_export_private_pkcs8_encrypted(self): + encoded = self.ref_private._export_pkcs8(passphrase="secret", + protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") + + # This should prove that the output is password-protected + self.assertRaises(ValueError, ECC._import_pkcs8, encoded, None) + + decoded = ECC._import_pkcs8(encoded, "secret") + self.assertEqual(self.ref_private, decoded) + + # --- + + encoded = self.ref_private.export_key(format="DER", + passphrase="secret", + protection="PBKDF2WithHMAC-SHA512-224AndAES128-CBC", + prot_params={'iteration_count':123}) + decoded = ECC.import_key(encoded, "secret") + self.assertEqual(self.ref_private, decoded) + + def test_export_public_pem_uncompressed(self): + key_file = load_file("ecc_p224_public.pem", "rt").strip() + + encoded = self.ref_private._export_public_pem(False) + self.assertEqual(key_file, encoded) + + # --- + + encoded = self.ref_public.export_key(format="PEM") + self.assertEqual(key_file, encoded) + + encoded = self.ref_public.export_key(format="PEM", compress=False) + self.assertEqual(key_file, encoded) + + def test_export_public_pem_compressed(self): + key_file = load_file("ecc_p224_public.pem", "rt").strip() + pub_key = ECC.import_key(key_file) + + key_file_compressed = pub_key.export_key(format="PEM", compress=True) + key_file_compressed_ref = load_file("ecc_p224_public_compressed.pem", "rt").strip() + + self.assertEqual(key_file_compressed, key_file_compressed_ref) + + def test_export_private_pem_clear(self): + key_file = load_file("ecc_p224_private.pem", "rt").strip() + + encoded = self.ref_private._export_private_pem(None) + self.assertEqual(key_file, encoded) + + # --- + + encoded = self.ref_private.export_key(format="PEM", use_pkcs8=False) + self.assertEqual(key_file, encoded) + + def test_export_private_pem_encrypted(self): + encoded = self.ref_private._export_private_pem(passphrase=b"secret") + + # This should prove that the output is password-protected + self.assertRaises(ValueError, ECC.import_key, encoded) + + assert "EC PRIVATE KEY" in encoded + + decoded = ECC.import_key(encoded, "secret") + self.assertEqual(self.ref_private, decoded) + + # --- + + encoded = self.ref_private.export_key(format="PEM", + passphrase="secret", + use_pkcs8=False) + decoded = ECC.import_key(encoded, "secret") + self.assertEqual(self.ref_private, decoded) + + def test_export_private_pkcs8_and_pem_1(self): + # PKCS8 inside PEM with both unencrypted + key_file = load_file("ecc_p224_private_p8_clear.pem", "rt").strip() + + encoded = self.ref_private._export_private_clear_pkcs8_in_clear_pem() + self.assertEqual(key_file, encoded) + + # --- + + encoded = self.ref_private.export_key(format="PEM") + self.assertEqual(key_file, encoded) + + def test_export_private_pkcs8_and_pem_2(self): + # PKCS8 inside PEM with PKCS8 encryption + encoded = self.ref_private._export_private_encrypted_pkcs8_in_clear_pem("secret", + protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") + + # This should prove that the output is password-protected + self.assertRaises(ValueError, ECC.import_key, encoded) + + assert "ENCRYPTED PRIVATE KEY" in encoded + + decoded = ECC.import_key(encoded, "secret") + self.assertEqual(self.ref_private, decoded) + + # --- + + encoded = self.ref_private.export_key(format="PEM", + passphrase="secret", + protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") + decoded = ECC.import_key(encoded, "secret") + self.assertEqual(self.ref_private, decoded) + + def test_prng(self): + # Test that password-protected containers use the provided PRNG + encoded1 = self.ref_private.export_key(format="PEM", + passphrase="secret", + protection="PBKDF2WithHMAC-SHA1AndAES128-CBC", + randfunc=get_fixed_prng()) + encoded2 = self.ref_private.export_key(format="PEM", + passphrase="secret", + protection="PBKDF2WithHMAC-SHA1AndAES128-CBC", + randfunc=get_fixed_prng()) + self.assertEqual(encoded1, encoded2) + + # --- + + encoded1 = self.ref_private.export_key(format="PEM", + use_pkcs8=False, + passphrase="secret", + randfunc=get_fixed_prng()) + encoded2 = self.ref_private.export_key(format="PEM", + use_pkcs8=False, + passphrase="secret", + randfunc=get_fixed_prng()) + self.assertEqual(encoded1, encoded2) + + def test_byte_or_string_passphrase(self): + encoded1 = self.ref_private.export_key(format="PEM", + use_pkcs8=False, + passphrase="secret", + randfunc=get_fixed_prng()) + encoded2 = self.ref_private.export_key(format="PEM", + use_pkcs8=False, + passphrase=b"secret", + randfunc=get_fixed_prng()) + self.assertEqual(encoded1, encoded2) + + def test_error_params1(self): + # Unknown format + self.assertRaises(ValueError, self.ref_private.export_key, format="XXX") + + # Missing 'protection' parameter when PKCS#8 is used + self.ref_private.export_key(format="PEM", passphrase="secret", + use_pkcs8=False) + self.assertRaises(ValueError, self.ref_private.export_key, format="PEM", + passphrase="secret") + + # DER format but no PKCS#8 + self.assertRaises(ValueError, self.ref_private.export_key, format="DER", + passphrase="secret", + use_pkcs8=False, + protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") + + # Incorrect parameters for public keys + self.assertRaises(ValueError, self.ref_public.export_key, format="DER", + use_pkcs8=False) + + # Empty password + self.assertRaises(ValueError, self.ref_private.export_key, format="PEM", + passphrase="", use_pkcs8=False) + self.assertRaises(ValueError, self.ref_private.export_key, format="PEM", + passphrase="", + protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") + + def test_compressed_curve(self): + + # Compressed P-224 curve (Y-point is even) + pem1 = """-----BEGIN EC PRIVATE KEY----- + MGgCAQEEHPYicBNI9nd6wDKAX2l+f3A0Q+KWUQeMqSt5GoOgBwYFK4EEACGhPAM6 + AATCL6rUIDT14zXKoS5GQUMDP/tpc+1iI/FyEZikt2roKDkhU5q08srmqaysbfJN + eUr7Xf1lnCVGag== + -----END EC PRIVATE KEY-----""" + + # Compressed P-224 curve (Y-point is odd) + pem2 = """-----BEGIN EC PRIVATE KEY----- + MGgCAQEEHEFjbaVPLJ3ngZyCibCvT0RLUqSlHjC5Z3e0FtugBwYFK4EEACGhPAM6 + AAT5IvL2V6m48y1JLMGr6ZbnOqNKP9hMf9mxyVkk6/SaRoBoJVkXrNIpYL0P7DS7 + QF8E/OGeZRwvow== + -----END EC PRIVATE KEY-----""" + + key1 = ECC.import_key(pem1) + low16 = int(key1.pointQ.y % 65536) + self.assertEqual(low16, 0x466A) + + key2 = ECC.import_key(pem2) + low16 = int(key2.pointQ.y % 65536) + self.assertEqual(low16, 0x2FA3) + + +class TestExport_P256(unittest.TestCase): + + def __init__(self, *args, **kwargs): + super(TestExport_P256, self).__init__(*args, **kwargs) + self.ref_private, self.ref_public = create_ref_keys_p256() + + def test_export_public_der_uncompressed(self): + key_file = load_file("ecc_p256_public.der") + + encoded = self.ref_public._export_subjectPublicKeyInfo(False) + self.assertEqual(key_file, encoded) + + encoded = self.ref_public.export_key(format="DER") + self.assertEqual(key_file, encoded) + + encoded = self.ref_public.export_key(format="DER", compress=False) + self.assertEqual(key_file, encoded) + + def test_export_public_der_compressed(self): + key_file = load_file("ecc_p256_public.der") + pub_key = ECC.import_key(key_file) + key_file_compressed = pub_key.export_key(format="DER", compress=True) + + key_file_compressed_ref = load_file("ecc_p256_public_compressed.der") + self.assertEqual(key_file_compressed, key_file_compressed_ref) + + def test_export_public_sec1_uncompressed(self): + key_file = load_file("ecc_p256_public.der") + value = extract_bitstring_from_spki(key_file) + + encoded = self.ref_public.export_key(format="SEC1") + self.assertEqual(value, encoded) + + def test_export_public_sec1_compressed(self): + key_file = load_file("ecc_p256_public.der") + encoded = self.ref_public.export_key(format="SEC1", compress=True) + + key_file_compressed_ref = load_file("ecc_p256_public_compressed.der") + value = extract_bitstring_from_spki(key_file_compressed_ref) + self.assertEqual(value, encoded) + + def test_export_rfc5915_private_der(self): + key_file = load_file("ecc_p256_private.der") + + encoded = self.ref_private._export_rfc5915_private_der() + self.assertEqual(key_file, encoded) + + # --- + + encoded = self.ref_private.export_key(format="DER", use_pkcs8=False) + self.assertEqual(key_file, encoded) + + def test_export_private_pkcs8_clear(self): + key_file = load_file("ecc_p256_private_p8_clear.der") + + encoded = self.ref_private._export_pkcs8() + self.assertEqual(key_file, encoded) + + # --- + + encoded = self.ref_private.export_key(format="DER") + self.assertEqual(key_file, encoded) + + def test_export_private_pkcs8_encrypted(self): + encoded = self.ref_private._export_pkcs8(passphrase="secret", + protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") + + # This should prove that the output is password-protected + self.assertRaises(ValueError, ECC._import_pkcs8, encoded, None) + + decoded = ECC._import_pkcs8(encoded, "secret") + self.assertEqual(self.ref_private, decoded) + + # --- + + encoded = self.ref_private.export_key(format="DER", + passphrase="secret", + protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") + decoded = ECC.import_key(encoded, "secret") + self.assertEqual(self.ref_private, decoded) + + # --- + + encoded = self.ref_private.export_key(format="DER", + passphrase="secret", + protection="PBKDF2WithHMAC-SHA512-256AndAES128-CBC", + prot_params={'iteration_count':123}) + decoded = ECC.import_key(encoded, "secret") + self.assertEqual(self.ref_private, decoded) + + def test_export_public_pem_uncompressed(self): + key_file = load_file("ecc_p256_public.pem", "rt").strip() + + encoded = self.ref_private._export_public_pem(False) + self.assertEqual(key_file, encoded) + + # --- + + encoded = self.ref_public.export_key(format="PEM") + self.assertEqual(key_file, encoded) + + encoded = self.ref_public.export_key(format="PEM", compress=False) + self.assertEqual(key_file, encoded) + + def test_export_public_pem_compressed(self): + key_file = load_file("ecc_p256_public.pem", "rt").strip() + pub_key = ECC.import_key(key_file) + + key_file_compressed = pub_key.export_key(format="PEM", compress=True) + key_file_compressed_ref = load_file("ecc_p256_public_compressed.pem", "rt").strip() + + self.assertEqual(key_file_compressed, key_file_compressed_ref) + + def test_export_private_pem_clear(self): + key_file = load_file("ecc_p256_private.pem", "rt").strip() + + encoded = self.ref_private._export_private_pem(None) + self.assertEqual(key_file, encoded) + + # --- + + encoded = self.ref_private.export_key(format="PEM", use_pkcs8=False) + self.assertEqual(key_file, encoded) + + def test_export_private_pem_encrypted(self): + encoded = self.ref_private._export_private_pem(passphrase=b"secret") + + # This should prove that the output is password-protected + self.assertRaises(ValueError, ECC.import_key, encoded) + + assert "EC PRIVATE KEY" in encoded + + decoded = ECC.import_key(encoded, "secret") + self.assertEqual(self.ref_private, decoded) + + # --- + + encoded = self.ref_private.export_key(format="PEM", + passphrase="secret", + use_pkcs8=False) + decoded = ECC.import_key(encoded, "secret") + self.assertEqual(self.ref_private, decoded) + + def test_export_private_pkcs8_and_pem_1(self): + # PKCS8 inside PEM with both unencrypted + key_file = load_file("ecc_p256_private_p8_clear.pem", "rt").strip() + + encoded = self.ref_private._export_private_clear_pkcs8_in_clear_pem() + self.assertEqual(key_file, encoded) + + # --- + + encoded = self.ref_private.export_key(format="PEM") + self.assertEqual(key_file, encoded) + + def test_export_private_pkcs8_and_pem_2(self): + # PKCS8 inside PEM with PKCS8 encryption + encoded = self.ref_private._export_private_encrypted_pkcs8_in_clear_pem("secret", + protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") + + # This should prove that the output is password-protected + self.assertRaises(ValueError, ECC.import_key, encoded) + + assert "ENCRYPTED PRIVATE KEY" in encoded + + decoded = ECC.import_key(encoded, "secret") + self.assertEqual(self.ref_private, decoded) + + # --- + + encoded = self.ref_private.export_key(format="PEM", + passphrase="secret", + protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") + decoded = ECC.import_key(encoded, "secret") + self.assertEqual(self.ref_private, decoded) + + def test_export_openssh_uncompressed(self): + key_file = load_file("ecc_p256_public_openssh.txt", "rt") + + encoded = self.ref_public._export_openssh(False) + self.assertEqual(key_file, encoded) + + # --- + + encoded = self.ref_public.export_key(format="OpenSSH") + self.assertEqual(key_file, encoded) + + encoded = self.ref_public.export_key(format="OpenSSH", compress=False) + self.assertEqual(key_file, encoded) + + def test_export_openssh_compressed(self): + key_file = load_file("ecc_p256_public_openssh.txt", "rt") + pub_key = ECC.import_key(key_file) + + key_file_compressed = pub_key.export_key(format="OpenSSH", compress=True) + assert len(key_file) > len(key_file_compressed) + self.assertEqual(pub_key, ECC.import_key(key_file_compressed)) + + def test_prng(self): + # Test that password-protected containers use the provided PRNG + encoded1 = self.ref_private.export_key(format="PEM", + passphrase="secret", + protection="PBKDF2WithHMAC-SHA1AndAES128-CBC", + randfunc=get_fixed_prng()) + encoded2 = self.ref_private.export_key(format="PEM", + passphrase="secret", + protection="PBKDF2WithHMAC-SHA1AndAES128-CBC", + randfunc=get_fixed_prng()) + self.assertEqual(encoded1, encoded2) + + # --- + + encoded1 = self.ref_private.export_key(format="PEM", + use_pkcs8=False, + passphrase="secret", + randfunc=get_fixed_prng()) + encoded2 = self.ref_private.export_key(format="PEM", + use_pkcs8=False, + passphrase="secret", + randfunc=get_fixed_prng()) + self.assertEqual(encoded1, encoded2) + + def test_byte_or_string_passphrase(self): + encoded1 = self.ref_private.export_key(format="PEM", + use_pkcs8=False, + passphrase="secret", + randfunc=get_fixed_prng()) + encoded2 = self.ref_private.export_key(format="PEM", + use_pkcs8=False, + passphrase=b"secret", + randfunc=get_fixed_prng()) + self.assertEqual(encoded1, encoded2) + + def test_error_params1(self): + # Unknown format + self.assertRaises(ValueError, self.ref_private.export_key, format="XXX") + + # Missing 'protection' parameter when PKCS#8 is used + self.ref_private.export_key(format="PEM", passphrase="secret", + use_pkcs8=False) + self.assertRaises(ValueError, self.ref_private.export_key, format="PEM", + passphrase="secret") + + # DER format but no PKCS#8 + self.assertRaises(ValueError, self.ref_private.export_key, format="DER", + passphrase="secret", + use_pkcs8=False, + protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") + + # Incorrect parameters for public keys + self.assertRaises(ValueError, self.ref_public.export_key, format="DER", + use_pkcs8=False) + + # Empty password + self.assertRaises(ValueError, self.ref_private.export_key, format="PEM", + passphrase="", use_pkcs8=False) + self.assertRaises(ValueError, self.ref_private.export_key, format="PEM", + passphrase="", + protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") + + # No private keys with OpenSSH + self.assertRaises(ValueError, self.ref_private.export_key, format="OpenSSH", + passphrase="secret") + + + def test_compressed_curve(self): + + # Compressed P-256 curve (Y-point is even) + pem1 = """-----BEGIN EC PRIVATE KEY----- + MFcCAQEEIHTuc09jC51xXomV6MVCDN+DpAAvSmaJWZPTEHM6D5H1oAoGCCqGSM49 + AwEHoSQDIgACWFuGbHe8yJ43rir7PMTE9w8vHz0BSpXHq90Xi7/s+a0= + -----END EC PRIVATE KEY-----""" + + # Compressed P-256 curve (Y-point is odd) + pem2 = """-----BEGIN EC PRIVATE KEY----- + MFcCAQEEIFggiPN9SQP+FAPTCPp08fRUz7rHp2qNBRcBJ1DXhb3ZoAoGCCqGSM49 + AwEHoSQDIgADLpph1trTIlVfa8NJvlMUPyWvL+wP+pW3BJITUL/wj9A= + -----END EC PRIVATE KEY-----""" + + key1 = ECC.import_key(pem1) + low16 = int(key1.pointQ.y % 65536) + self.assertEqual(low16, 0xA6FC) + + key2 = ECC.import_key(pem2) + low16 = int(key2.pointQ.y % 65536) + self.assertEqual(low16, 0x6E57) + + +class TestExport_P384(unittest.TestCase): + + def __init__(self, *args, **kwargs): + super(TestExport_P384, self).__init__(*args, **kwargs) + self.ref_private, self.ref_public = create_ref_keys_p384() + + def test_export_public_der_uncompressed(self): + key_file = load_file("ecc_p384_public.der") + + encoded = self.ref_public._export_subjectPublicKeyInfo(False) + self.assertEqual(key_file, encoded) + + encoded = self.ref_public.export_key(format="DER") + self.assertEqual(key_file, encoded) + + encoded = self.ref_public.export_key(format="DER", compress=False) + self.assertEqual(key_file, encoded) + + def test_export_public_der_compressed(self): + key_file = load_file("ecc_p384_public.der") + pub_key = ECC.import_key(key_file) + key_file_compressed = pub_key.export_key(format="DER", compress=True) + + key_file_compressed_ref = load_file("ecc_p384_public_compressed.der") + self.assertEqual(key_file_compressed, key_file_compressed_ref) + + def test_export_public_sec1_uncompressed(self): + key_file = load_file("ecc_p384_public.der") + value = extract_bitstring_from_spki(key_file) + + encoded = self.ref_public.export_key(format="SEC1") + self.assertEqual(value, encoded) + + def test_export_public_sec1_compressed(self): + key_file = load_file("ecc_p384_public.der") + encoded = self.ref_public.export_key(format="SEC1", compress=True) + + key_file_compressed_ref = load_file("ecc_p384_public_compressed.der") + value = extract_bitstring_from_spki(key_file_compressed_ref) + self.assertEqual(value, encoded) + + def test_export_rfc5915_private_der(self): + key_file = load_file("ecc_p384_private.der") + + encoded = self.ref_private._export_rfc5915_private_der() + self.assertEqual(key_file, encoded) + + # --- + + encoded = self.ref_private.export_key(format="DER", use_pkcs8=False) + self.assertEqual(key_file, encoded) + + def test_export_private_pkcs8_clear(self): + key_file = load_file("ecc_p384_private_p8_clear.der") + + encoded = self.ref_private._export_pkcs8() + self.assertEqual(key_file, encoded) + + # --- + + encoded = self.ref_private.export_key(format="DER") + self.assertEqual(key_file, encoded) + + def test_export_private_pkcs8_encrypted(self): + encoded = self.ref_private._export_pkcs8(passphrase="secret", + protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") + + # This should prove that the output is password-protected + self.assertRaises(ValueError, ECC._import_pkcs8, encoded, None) + + decoded = ECC._import_pkcs8(encoded, "secret") + self.assertEqual(self.ref_private, decoded) + + # --- + + encoded = self.ref_private.export_key(format="DER", + passphrase="secret", + protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") + decoded = ECC.import_key(encoded, "secret") + self.assertEqual(self.ref_private, decoded) + + # --- + + encoded = self.ref_private.export_key(format="DER", + passphrase="secret", + protection="PBKDF2WithHMAC-SHA384AndAES128-CBC", + prot_params={'iteration_count':123}) + decoded = ECC.import_key(encoded, "secret") + self.assertEqual(self.ref_private, decoded) + + def test_export_public_pem_uncompressed(self): + key_file = load_file("ecc_p384_public.pem", "rt").strip() + + encoded = self.ref_private._export_public_pem(False) + self.assertEqual(key_file, encoded) + + # --- + + encoded = self.ref_public.export_key(format="PEM") + self.assertEqual(key_file, encoded) + + encoded = self.ref_public.export_key(format="PEM", compress=False) + self.assertEqual(key_file, encoded) + + def test_export_public_pem_compressed(self): + key_file = load_file("ecc_p384_public.pem", "rt").strip() + pub_key = ECC.import_key(key_file) + + key_file_compressed = pub_key.export_key(format="PEM", compress=True) + key_file_compressed_ref = load_file("ecc_p384_public_compressed.pem", "rt").strip() + + self.assertEqual(key_file_compressed, key_file_compressed_ref) + + def test_export_private_pem_clear(self): + key_file = load_file("ecc_p384_private.pem", "rt").strip() + + encoded = self.ref_private._export_private_pem(None) + self.assertEqual(key_file, encoded) + + # --- + + encoded = self.ref_private.export_key(format="PEM", use_pkcs8=False) + self.assertEqual(key_file, encoded) + + def test_export_private_pem_encrypted(self): + encoded = self.ref_private._export_private_pem(passphrase=b"secret") + + # This should prove that the output is password-protected + self.assertRaises(ValueError, ECC.import_key, encoded) + + assert "EC PRIVATE KEY" in encoded + + decoded = ECC.import_key(encoded, "secret") + self.assertEqual(self.ref_private, decoded) + + # --- + + encoded = self.ref_private.export_key(format="PEM", + passphrase="secret", + use_pkcs8=False) + decoded = ECC.import_key(encoded, "secret") + self.assertEqual(self.ref_private, decoded) + + def test_export_private_pkcs8_and_pem_1(self): + # PKCS8 inside PEM with both unencrypted + key_file = load_file("ecc_p384_private_p8_clear.pem", "rt").strip() + + encoded = self.ref_private._export_private_clear_pkcs8_in_clear_pem() + self.assertEqual(key_file, encoded) + + # --- + + encoded = self.ref_private.export_key(format="PEM") + self.assertEqual(key_file, encoded) + + def test_export_private_pkcs8_and_pem_2(self): + # PKCS8 inside PEM with PKCS8 encryption + encoded = self.ref_private._export_private_encrypted_pkcs8_in_clear_pem("secret", + protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") + + # This should prove that the output is password-protected + self.assertRaises(ValueError, ECC.import_key, encoded) + + assert "ENCRYPTED PRIVATE KEY" in encoded + + decoded = ECC.import_key(encoded, "secret") + self.assertEqual(self.ref_private, decoded) + + # --- + + encoded = self.ref_private.export_key(format="PEM", + passphrase="secret", + protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") + decoded = ECC.import_key(encoded, "secret") + self.assertEqual(self.ref_private, decoded) + + def test_export_openssh_uncompressed(self): + key_file = load_file("ecc_p384_public_openssh.txt", "rt") + + encoded = self.ref_public._export_openssh(False) + self.assertEqual(key_file, encoded) + + # --- + + encoded = self.ref_public.export_key(format="OpenSSH") + self.assertEqual(key_file, encoded) + + encoded = self.ref_public.export_key(format="OpenSSH", compress=False) + self.assertEqual(key_file, encoded) + + def test_export_openssh_compressed(self): + key_file = load_file("ecc_p384_public_openssh.txt", "rt") + pub_key = ECC.import_key(key_file) + + key_file_compressed = pub_key.export_key(format="OpenSSH", compress=True) + assert len(key_file) > len(key_file_compressed) + self.assertEqual(pub_key, ECC.import_key(key_file_compressed)) + + def test_prng(self): + # Test that password-protected containers use the provided PRNG + encoded1 = self.ref_private.export_key(format="PEM", + passphrase="secret", + protection="PBKDF2WithHMAC-SHA1AndAES128-CBC", + randfunc=get_fixed_prng()) + encoded2 = self.ref_private.export_key(format="PEM", + passphrase="secret", + protection="PBKDF2WithHMAC-SHA1AndAES128-CBC", + randfunc=get_fixed_prng()) + self.assertEqual(encoded1, encoded2) + + # --- + + encoded1 = self.ref_private.export_key(format="PEM", + use_pkcs8=False, + passphrase="secret", + randfunc=get_fixed_prng()) + encoded2 = self.ref_private.export_key(format="PEM", + use_pkcs8=False, + passphrase="secret", + randfunc=get_fixed_prng()) + self.assertEqual(encoded1, encoded2) + + def test_byte_or_string_passphrase(self): + encoded1 = self.ref_private.export_key(format="PEM", + use_pkcs8=False, + passphrase="secret", + randfunc=get_fixed_prng()) + encoded2 = self.ref_private.export_key(format="PEM", + use_pkcs8=False, + passphrase=b"secret", + randfunc=get_fixed_prng()) + self.assertEqual(encoded1, encoded2) + + def test_error_params1(self): + # Unknown format + self.assertRaises(ValueError, self.ref_private.export_key, format="XXX") + + # Missing 'protection' parameter when PKCS#8 is used + self.ref_private.export_key(format="PEM", passphrase="secret", + use_pkcs8=False) + self.assertRaises(ValueError, self.ref_private.export_key, format="PEM", + passphrase="secret") + + # DER format but no PKCS#8 + self.assertRaises(ValueError, self.ref_private.export_key, format="DER", + passphrase="secret", + use_pkcs8=False, + protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") + + # Incorrect parameters for public keys + self.assertRaises(ValueError, self.ref_public.export_key, format="DER", + use_pkcs8=False) + + # Empty password + self.assertRaises(ValueError, self.ref_private.export_key, format="PEM", + passphrase="", use_pkcs8=False) + self.assertRaises(ValueError, self.ref_private.export_key, format="PEM", + passphrase="", + protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") + + # No private keys with OpenSSH + self.assertRaises(ValueError, self.ref_private.export_key, format="OpenSSH", + passphrase="secret") + + def test_compressed_curve(self): + + # Compressed P-384 curve (Y-point is even) + # openssl ecparam -name secp384p1 -genkey -noout -conv_form compressed -out /tmp/a.pem + # openssl ec -in /tmp/a.pem -text -noout + pem1 = """-----BEGIN EC PRIVATE KEY----- +MIGkAgEBBDAM0lEIhvXuekK2SWtdbgOcZtBaxa9TxfpO/GcDFZLCJ3JVXaTgwken +QT+C+XLtD6WgBwYFK4EEACKhZANiAATs0kZMhFDu8DoBC21jrSDPyAUn4aXZ/DM4 +ylhDfWmb4LEbeszXceIzfhIUaaGs5y1xXaqf5KXTiAAYx2pKUzAAM9lcGUHCGKJG +k4AgUmVJON29XoUilcFrzjDmuye3B6Q= +-----END EC PRIVATE KEY-----""" + + # Compressed P-384 curve (Y-point is odd) + pem2 = """-----BEGIN EC PRIVATE KEY----- +MIGkAgEBBDDHPFTslYLltE16fHdSDTtE/2HTmd3M8mqy5MttAm4wZ833KXiGS9oe +kFdx9sNV0KygBwYFK4EEACKhZANiAASLIE5RqVMtNhtBH/u/p/ifqOAlKnK/+RrQ +YC46ZRsnKNayw3wATdPjgja7L/DSII3nZK0G6KOOVwJBznT/e+zudUJYhZKaBLRx +/bgXyxUtYClOXxb1Y/5N7txLstYRyP0= +-----END EC PRIVATE KEY-----""" + + key1 = ECC.import_key(pem1) + low16 = int(key1.pointQ.y % 65536) + self.assertEqual(low16, 0x07a4) + + key2 = ECC.import_key(pem2) + low16 = int(key2.pointQ.y % 65536) + self.assertEqual(low16, 0xc8fd) + + +class TestExport_P521(unittest.TestCase): + + def __init__(self, *args, **kwargs): + super(TestExport_P521, self).__init__(*args, **kwargs) + self.ref_private, self.ref_public = create_ref_keys_p521() + + def test_export_public_der_uncompressed(self): + key_file = load_file("ecc_p521_public.der") + + encoded = self.ref_public._export_subjectPublicKeyInfo(False) + self.assertEqual(key_file, encoded) + + encoded = self.ref_public.export_key(format="DER") + self.assertEqual(key_file, encoded) + + encoded = self.ref_public.export_key(format="DER", compress=False) + self.assertEqual(key_file, encoded) + + def test_export_public_der_compressed(self): + key_file = load_file("ecc_p521_public.der") + pub_key = ECC.import_key(key_file) + key_file_compressed = pub_key.export_key(format="DER", compress=True) + + key_file_compressed_ref = load_file("ecc_p521_public_compressed.der") + self.assertEqual(key_file_compressed, key_file_compressed_ref) + + def test_export_public_sec1_uncompressed(self): + key_file = load_file("ecc_p521_public.der") + value = extract_bitstring_from_spki(key_file) + + encoded = self.ref_public.export_key(format="SEC1") + self.assertEqual(value, encoded) + + encoded = self.ref_public.export_key(format="raw") + self.assertEqual(value, encoded) + + def test_export_public_sec1_compressed(self): + key_file = load_file("ecc_p521_public.der") + encoded = self.ref_public.export_key(format="SEC1", compress=True) + + key_file_compressed_ref = load_file("ecc_p521_public_compressed.der") + value = extract_bitstring_from_spki(key_file_compressed_ref) + self.assertEqual(value, encoded) + + encoded = self.ref_public.export_key(format="raw", compress=True) + self.assertEqual(value, encoded) + + def test_export_rfc5915_private_der(self): + key_file = load_file("ecc_p521_private.der") + + encoded = self.ref_private._export_rfc5915_private_der() + self.assertEqual(key_file, encoded) + + # --- + + encoded = self.ref_private.export_key(format="DER", use_pkcs8=False) + self.assertEqual(key_file, encoded) + + def test_export_private_pkcs8_clear(self): + key_file = load_file("ecc_p521_private_p8_clear.der") + + encoded = self.ref_private._export_pkcs8() + self.assertEqual(key_file, encoded) + + # --- + + encoded = self.ref_private.export_key(format="DER") + self.assertEqual(key_file, encoded) + + def test_export_private_pkcs8_encrypted(self): + encoded = self.ref_private._export_pkcs8(passphrase="secret", + protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") + + # This should prove that the output is password-protected + self.assertRaises(ValueError, ECC._import_pkcs8, encoded, None) + + decoded = ECC._import_pkcs8(encoded, "secret") + self.assertEqual(self.ref_private, decoded) + + # --- + + encoded = self.ref_private.export_key(format="DER", + passphrase="secret", + protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") + decoded = ECC.import_key(encoded, "secret") + self.assertEqual(self.ref_private, decoded) + + # --- + + encoded = self.ref_private.export_key(format="DER", + passphrase="secret", + protection="PBKDF2WithHMAC-SHA1AndAES128-CBC", + prot_params={'iteration_count':123}) + decoded = ECC.import_key(encoded, "secret") + self.assertEqual(self.ref_private, decoded) + + def test_export_public_pem_uncompressed(self): + key_file = load_file("ecc_p521_public.pem", "rt").strip() + + encoded = self.ref_private._export_public_pem(False) + self.assertEqual(key_file, encoded) + + # --- + + encoded = self.ref_public.export_key(format="PEM") + self.assertEqual(key_file, encoded) + + encoded = self.ref_public.export_key(format="PEM", compress=False) + self.assertEqual(key_file, encoded) + + def test_export_public_pem_compressed(self): + key_file = load_file("ecc_p521_public.pem", "rt").strip() + pub_key = ECC.import_key(key_file) + + key_file_compressed = pub_key.export_key(format="PEM", compress=True) + key_file_compressed_ref = load_file("ecc_p521_public_compressed.pem", "rt").strip() + + self.assertEqual(key_file_compressed, key_file_compressed_ref) + + def test_export_private_pem_clear(self): + key_file = load_file("ecc_p521_private.pem", "rt").strip() + + encoded = self.ref_private._export_private_pem(None) + self.assertEqual(key_file, encoded) + + # --- + + encoded = self.ref_private.export_key(format="PEM", use_pkcs8=False) + self.assertEqual(key_file, encoded) + + def test_export_private_pem_encrypted(self): + encoded = self.ref_private._export_private_pem(passphrase=b"secret") + + # This should prove that the output is password-protected + self.assertRaises(ValueError, ECC.import_key, encoded) + + assert "EC PRIVATE KEY" in encoded + + decoded = ECC.import_key(encoded, "secret") + self.assertEqual(self.ref_private, decoded) + + # --- + + encoded = self.ref_private.export_key(format="PEM", + passphrase="secret", + use_pkcs8=False) + decoded = ECC.import_key(encoded, "secret") + self.assertEqual(self.ref_private, decoded) + + def test_export_private_pkcs8_and_pem_1(self): + # PKCS8 inside PEM with both unencrypted + key_file = load_file("ecc_p521_private_p8_clear.pem", "rt").strip() + + encoded = self.ref_private._export_private_clear_pkcs8_in_clear_pem() + self.assertEqual(key_file, encoded) + + # --- + + encoded = self.ref_private.export_key(format="PEM") + self.assertEqual(key_file, encoded) + + def test_export_private_pkcs8_and_pem_2(self): + # PKCS8 inside PEM with PKCS8 encryption + encoded = self.ref_private._export_private_encrypted_pkcs8_in_clear_pem("secret", + protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") + + # This should prove that the output is password-protected + self.assertRaises(ValueError, ECC.import_key, encoded) + + assert "ENCRYPTED PRIVATE KEY" in encoded + + decoded = ECC.import_key(encoded, "secret") + self.assertEqual(self.ref_private, decoded) + + # --- + + encoded = self.ref_private.export_key(format="PEM", + passphrase="secret", + protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") + decoded = ECC.import_key(encoded, "secret") + self.assertEqual(self.ref_private, decoded) + + def test_export_openssh_uncompressed(self): + key_file = load_file("ecc_p521_public_openssh.txt", "rt") + + encoded = self.ref_public._export_openssh(False) + self.assertEqual(key_file, encoded) + + # --- + + encoded = self.ref_public.export_key(format="OpenSSH") + self.assertEqual(key_file, encoded) + + encoded = self.ref_public.export_key(format="OpenSSH", compress=False) + self.assertEqual(key_file, encoded) + + def test_export_openssh_compressed(self): + key_file = load_file("ecc_p521_public_openssh.txt", "rt") + pub_key = ECC.import_key(key_file) + + key_file_compressed = pub_key.export_key(format="OpenSSH", compress=True) + assert len(key_file) > len(key_file_compressed) + self.assertEqual(pub_key, ECC.import_key(key_file_compressed)) + + def test_prng(self): + # Test that password-protected containers use the provided PRNG + encoded1 = self.ref_private.export_key(format="PEM", + passphrase="secret", + protection="PBKDF2WithHMAC-SHA1AndAES128-CBC", + randfunc=get_fixed_prng()) + encoded2 = self.ref_private.export_key(format="PEM", + passphrase="secret", + protection="PBKDF2WithHMAC-SHA1AndAES128-CBC", + randfunc=get_fixed_prng()) + self.assertEqual(encoded1, encoded2) + + # --- + + encoded1 = self.ref_private.export_key(format="PEM", + use_pkcs8=False, + passphrase="secret", + randfunc=get_fixed_prng()) + encoded2 = self.ref_private.export_key(format="PEM", + use_pkcs8=False, + passphrase="secret", + randfunc=get_fixed_prng()) + self.assertEqual(encoded1, encoded2) + + def test_byte_or_string_passphrase(self): + encoded1 = self.ref_private.export_key(format="PEM", + use_pkcs8=False, + passphrase="secret", + randfunc=get_fixed_prng()) + encoded2 = self.ref_private.export_key(format="PEM", + use_pkcs8=False, + passphrase=b"secret", + randfunc=get_fixed_prng()) + self.assertEqual(encoded1, encoded2) + + def test_error_params1(self): + # Unknown format + self.assertRaises(ValueError, self.ref_private.export_key, format="XXX") + + # Missing 'protection' parameter when PKCS#8 is used + self.ref_private.export_key(format="PEM", passphrase="secret", + use_pkcs8=False) + self.assertRaises(ValueError, self.ref_private.export_key, format="PEM", + passphrase="secret") + + # DER format but no PKCS#8 + self.assertRaises(ValueError, self.ref_private.export_key, format="DER", + passphrase="secret", + use_pkcs8=False, + protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") + + # Incorrect parameters for public keys + self.assertRaises(ValueError, self.ref_public.export_key, format="DER", + use_pkcs8=False) + + # Empty password + self.assertRaises(ValueError, self.ref_private.export_key, format="PEM", + passphrase="", use_pkcs8=False) + self.assertRaises(ValueError, self.ref_private.export_key, format="PEM", + passphrase="", + protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") + + # No private keys with OpenSSH + self.assertRaises(ValueError, self.ref_private.export_key, format="OpenSSH", + passphrase="secret") + + def test_compressed_curve(self): + + # Compressed P-521 curve (Y-point is even) + # openssl ecparam -name secp521r1 -genkey -noout -conv_form compressed -out /tmp/a.pem + # openssl ec -in /tmp/a.pem -text -noout + pem1 = """-----BEGIN EC PRIVATE KEY----- +MIHcAgEBBEIAnm1CEjVjvNfXEN730p+D6su5l+mOztdc5XmTEoti+s2R4GQ4mAv3 +0zYLvyklvOHw0+yy8d0cyGEJGb8T3ZVKmg2gBwYFK4EEACOhgYkDgYYABAHzjTI1 +ckxQ3Togi0LAxiG0PucdBBBs5oIy3df95xv6SInp70z+4qQ2EltEmdNMssH8eOrl +M5CYdZ6nbcHMVaJUvQEzTrYxvFjOgJiOd+E9eBWbLkbMNqsh1UKVO6HbMbW0ohCI +uGxO8tM6r3w89/qzpG2SvFM/fvv3mIR30wSZDD84qA== +-----END EC PRIVATE KEY-----""" + + # Compressed P-521 curve (Y-point is odd) + pem2 = """-----BEGIN EC PRIVATE KEY----- +MIHcAgEBBEIB84OfhJluLBRLn3+cC/RQ37C2SfQVP/t0gQK2tCsTf5avRcWYRrOJ +PmX9lNnkC0Hobd75QFRmdxrB0Wd1/M4jZOWgBwYFK4EEACOhgYkDgYYABAAMZcdJ +1YLCGHt3bHCEzdidVy6+brlJIbv1aQ9fPQLF7WKNv4c8w3H8d5a2+SDZilBOsk5c +6cNJDMz2ExWQvxl4CwDJtJGt1+LHVKFGy73NANqVxMbRu+2F8lOxkNp/ziFTbVyV +vv6oYkMIIi7r5oQWAiQDrR2mlrrFDL9V7GH/r8SWQw== +-----END EC PRIVATE KEY-----""" + + key1 = ECC.import_key(pem1) + low16 = int(key1.pointQ.y % 65536) + self.assertEqual(low16, 0x38a8) + + key2 = ECC.import_key(pem2) + low16 = int(key2.pointQ.y % 65536) + self.assertEqual(low16, 0x9643) + + +class TestImport_Ed25519(unittest.TestCase): + + def __init__(self, *args, **kwargs): + super(TestImport_Ed25519, self).__init__(*args, **kwargs) + self.ref_private, self.ref_public = create_ref_keys_ed25519() + + def test_import_public_der(self): + key_file = load_file("ecc_ed25519_public.der") + + key = ECC._import_subjectPublicKeyInfo(key_file) + self.assertEqual(self.ref_public, key) + + key = ECC._import_der(key_file, None) + self.assertEqual(self.ref_public, key) + + key = ECC.import_key(key_file) + self.assertEqual(self.ref_public, key) + + def test_import_pkcs8_der(self): + key_file = load_file("ecc_ed25519_private.der") + + key = ECC._import_der(key_file, None) + self.assertEqual(self.ref_private, key) + + key = ECC.import_key(key_file) + self.assertEqual(self.ref_private, key) + + def test_import_private_pkcs8_encrypted_1(self): + key_file = load_file("ecc_ed25519_private_p8.der") + + key = ECC._import_der(key_file, "secret") + self.assertEqual(self.ref_private, key) + + key = ECC.import_key(key_file, "secret") + self.assertEqual(self.ref_private, key) + + def test_import_private_pkcs8_encrypted_2(self): + key_file = load_file("ecc_ed25519_private_p8.pem") + + key = ECC.import_key(key_file, "secret") + self.assertEqual(self.ref_private, key) + + def test_import_private_pkcs8_encrypted_3(self): + key_file = load_file("ecc_ed25519_private_p8_2.der") + + key = ECC._import_der(key_file, "secret") + self.assertEqual(self.ref_private, key) + + key = ECC.import_key(key_file, "secret") + self.assertEqual(self.ref_private, key) + + def test_import_x509_der(self): + key_file = load_file("ecc_ed25519_x509.der") + + key = ECC._import_der(key_file, None) + self.assertEqual(self.ref_public, key) + + key = ECC.import_key(key_file) + self.assertEqual(self.ref_public, key) + + def test_import_public_pem(self): + key_file = load_file("ecc_ed25519_public.pem") + + key = ECC.import_key(key_file) + self.assertEqual(self.ref_public, key) + + def test_import_private_pem(self): + key_file = load_file("ecc_ed25519_private.pem") + + key = ECC.import_key(key_file) + self.assertEqual(self.ref_private, key) + + def test_import_private_pem_encrypted(self): + for algo in "des3", "aes128", "aes192", "aes256": + key_file = load_file("ecc_ed25519_private_enc_%s.pem" % algo) + + key = ECC.import_key(key_file, "secret") + self.assertEqual(self.ref_private, key) + + key = ECC.import_key(tostr(key_file), b"secret") + self.assertEqual(self.ref_private, key) + + def test_import_x509_pem(self): + key_file = load_file("ecc_ed25519_x509.pem") + + key = ECC.import_key(key_file) + self.assertEqual(self.ref_public, key) + + def test_import_openssh_public(self): + key_file = load_file("ecc_ed25519_public_openssh.txt") + key = ECC._import_openssh_public(key_file) + self.assertFalse(key.has_private()) + key = ECC.import_key(key_file) + self.assertFalse(key.has_private()) + + def test_import_openssh_private_clear(self): + key_file = load_file("ecc_ed25519_private_openssh.pem") + key = ECC.import_key(key_file) + + def test_import_openssh_private_password(self): + key_file = load_file("ecc_ed25519_private_openssh_pwd.pem") + key = ECC.import_key(key_file, b"password") + + +class TestExport_Ed25519(unittest.TestCase): + + def __init__(self, *args, **kwargs): + super(TestExport_Ed25519, self).__init__(*args, **kwargs) + self.ref_private, self.ref_public = create_ref_keys_ed25519() + + def test_export_public_der(self): + key_file = load_file("ecc_ed25519_public.der") + + encoded = self.ref_public._export_subjectPublicKeyInfo(True) + self.assertEqual(key_file, encoded) + + encoded = self.ref_public.export_key(format="DER") + self.assertEqual(key_file, encoded) + + encoded = self.ref_public.export_key(format="DER", compress=False) + self.assertEqual(key_file, encoded) + + def test_export_public_sec1(self): + self.assertRaises(ValueError, self.ref_public.export_key, format="SEC1") + + def test_export_private_pkcs8_clear(self): + key_file = load_file("ecc_ed25519_private.der") + + encoded = self.ref_private._export_pkcs8() + self.assertEqual(key_file, encoded) + + # --- + + encoded = self.ref_private.export_key(format="DER") + self.assertEqual(key_file, encoded) + + self.assertRaises(ValueError, self.ref_private.export_key, + format="DER", use_pkcs8=False) + + def test_export_private_pkcs8_encrypted(self): + encoded = self.ref_private._export_pkcs8(passphrase="secret", + protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") + + # This should prove that the output is password-protected + self.assertRaises(ValueError, ECC._import_pkcs8, encoded, None) + + decoded = ECC._import_pkcs8(encoded, "secret") + self.assertEqual(self.ref_private, decoded) + + # --- + + encoded = self.ref_private.export_key(format="DER", + passphrase="secret", + protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") + decoded = ECC.import_key(encoded, "secret") + self.assertEqual(self.ref_private, decoded) + + # --- + + encoded = self.ref_private.export_key(format="DER", + passphrase="secret", + protection="PBKDF2WithHMAC-SHA256AndAES128-CBC", + prot_params={'iteration_count':123}) + decoded = ECC.import_key(encoded, "secret") + self.assertEqual(self.ref_private, decoded) + + def test_export_public_pem(self): + key_file_ref = load_file("ecc_ed25519_public.pem", "rt").strip() + key_file = self.ref_public.export_key(format="PEM").strip() + self.assertEqual(key_file_ref, key_file) + + def test_export_private_pem_clear(self): + key_file = load_file("ecc_ed25519_private.pem", "rt").strip() + encoded = self.ref_private.export_key(format="PEM").strip() + self.assertEqual(key_file, encoded) + + def test_export_private_pem_encrypted(self): + encoded = self.ref_private.export_key(format="PEM", + passphrase=b"secret", + protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") + + # This should prove that the output is password-protected + self.assertRaises(ValueError, ECC.import_key, encoded) + + assert "ENCRYPTED PRIVATE KEY" in encoded + + decoded = ECC.import_key(encoded, "secret") + self.assertEqual(self.ref_private, decoded) + + def test_export_openssh(self): + key_file = load_file("ecc_ed25519_public_openssh.txt", "rt") + public_key = ECC.import_key(key_file) + key_file = " ".join(key_file.split(' ')[:2]) # remove comment + + encoded = public_key._export_openssh(False) + self.assertEqual(key_file, encoded.strip()) + + encoded = public_key.export_key(format="OpenSSH") + self.assertEqual(key_file, encoded.strip()) + + def test_export_raw(self): + encoded = self.ref_public.export_key(format='raw') + self.assertEqual(encoded, unhexlify(b'bc85b8cf585d20a4de47e84d1cb6183f63d9ba96223fcbc886e363ffdea20cff')) + + def test_prng(self): + # Test that password-protected containers use the provided PRNG + encoded1 = self.ref_private.export_key(format="PEM", + passphrase="secret", + protection="PBKDF2WithHMAC-SHA1AndAES128-CBC", + randfunc=get_fixed_prng()) + encoded2 = self.ref_private.export_key(format="PEM", + passphrase="secret", + protection="PBKDF2WithHMAC-SHA1AndAES128-CBC", + randfunc=get_fixed_prng()) + self.assertEqual(encoded1, encoded2) + + def test_byte_or_string_passphrase(self): + encoded1 = self.ref_private.export_key(format="PEM", + passphrase="secret", + protection="PBKDF2WithHMAC-SHA1AndAES128-CBC", + randfunc=get_fixed_prng()) + encoded2 = self.ref_private.export_key(format="PEM", + passphrase=b"secret", + protection="PBKDF2WithHMAC-SHA1AndAES128-CBC", + randfunc=get_fixed_prng()) + self.assertEqual(encoded1, encoded2) + + def test_error_params1(self): + # Unknown format + self.assertRaises(ValueError, self.ref_private.export_key, format="XXX") + + # Missing 'protection' parameter when PKCS#8 is used + self.assertRaises(ValueError, self.ref_private.export_key, format="PEM", + passphrase="secret") + + # Empty password + self.assertRaises(ValueError, self.ref_private.export_key, format="PEM", + passphrase="", use_pkcs8=False) + self.assertRaises(ValueError, self.ref_private.export_key, format="PEM", + passphrase="", + protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") + + # No private keys with OpenSSH + self.assertRaises(ValueError, self.ref_private.export_key, format="OpenSSH", + passphrase="secret") + + +class TestImport_Ed448(unittest.TestCase): + + def __init__(self, *args, **kwargs): + super(TestImport_Ed448, self).__init__(*args, **kwargs) + self.ref_private, self.ref_public = create_ref_keys_ed448() + + def test_import_public_der(self): + key_file = load_file("ecc_ed448_public.der") + + key = ECC._import_subjectPublicKeyInfo(key_file) + self.assertEqual(self.ref_public, key) + + key = ECC._import_der(key_file, None) + self.assertEqual(self.ref_public, key) + + key = ECC.import_key(key_file) + self.assertEqual(self.ref_public, key) + + def test_import_pkcs8_der(self): + key_file = load_file("ecc_ed448_private.der") + + key = ECC._import_der(key_file, None) + self.assertEqual(self.ref_private, key) + + key = ECC.import_key(key_file) + self.assertEqual(self.ref_private, key) + + def test_import_private_pkcs8_encrypted_1(self): + key_file = load_file("ecc_ed448_private_p8.der") + + key = ECC._import_der(key_file, "secret") + self.assertEqual(self.ref_private, key) + + key = ECC.import_key(key_file, "secret") + self.assertEqual(self.ref_private, key) + + def test_import_private_pkcs8_encrypted_2(self): + key_file = load_file("ecc_ed448_private_p8.pem") + + key = ECC.import_key(key_file, "secret") + self.assertEqual(self.ref_private, key) + + def test_import_private_pkcs8_encrypted_3(self): + key_file = load_file("ecc_ed448_private_p8_2.der") + + key = ECC._import_der(key_file, "secret") + self.assertEqual(self.ref_private, key) + + key = ECC.import_key(key_file, "secret") + self.assertEqual(self.ref_private, key) + + def test_import_x509_der(self): + key_file = load_file("ecc_ed448_x509.der") + + key = ECC._import_der(key_file, None) + self.assertEqual(self.ref_public, key) + + key = ECC.import_key(key_file) + self.assertEqual(self.ref_public, key) + + def test_import_public_pem(self): + key_file = load_file("ecc_ed448_public.pem") + + key = ECC.import_key(key_file) + self.assertEqual(self.ref_public, key) + + def test_import_private_pem(self): + key_file = load_file("ecc_ed448_private.pem") + + key = ECC.import_key(key_file) + self.assertEqual(self.ref_private, key) + + def test_import_private_pem_encrypted(self): + for algo in "des3", "aes128", "aes192", "aes256": + key_file = load_file("ecc_ed448_private_enc_%s.pem" % algo) + + key = ECC.import_key(key_file, "secret") + self.assertEqual(self.ref_private, key) + + key = ECC.import_key(tostr(key_file), b"secret") + self.assertEqual(self.ref_private, key) + + def test_import_x509_pem(self): + key_file = load_file("ecc_ed448_x509.pem") + + key = ECC.import_key(key_file) + self.assertEqual(self.ref_public, key) + + +class TestExport_Ed448(unittest.TestCase): + + def __init__(self, *args, **kwargs): + super(TestExport_Ed448, self).__init__(*args, **kwargs) + self.ref_private, self.ref_public = create_ref_keys_ed448() + + def test_export_public_der(self): + key_file = load_file("ecc_ed448_public.der") + + encoded = self.ref_public._export_subjectPublicKeyInfo(True) + self.assertEqual(key_file, encoded) + + encoded = self.ref_public.export_key(format="DER") + self.assertEqual(key_file, encoded) + + encoded = self.ref_public.export_key(format="DER", compress=False) + self.assertEqual(key_file, encoded) + + def test_export_public_sec1(self): + self.assertRaises(ValueError, self.ref_public.export_key, format="SEC1") + + def test_export_private_pkcs8_clear(self): + key_file = load_file("ecc_ed448_private.der") + + encoded = self.ref_private._export_pkcs8() + self.assertEqual(key_file, encoded) + + # --- + + encoded = self.ref_private.export_key(format="DER") + self.assertEqual(key_file, encoded) + + self.assertRaises(ValueError, self.ref_private.export_key, + format="DER", use_pkcs8=False) + + def test_export_private_pkcs8_encrypted(self): + encoded = self.ref_private._export_pkcs8(passphrase="secret", + protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") + + # This should prove that the output is password-protected + self.assertRaises(ValueError, ECC._import_pkcs8, encoded, None) + + decoded = ECC._import_pkcs8(encoded, "secret") + self.assertEqual(self.ref_private, decoded) + + # --- + + encoded = self.ref_private.export_key(format="DER", + passphrase="secret", + protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") + decoded = ECC.import_key(encoded, "secret") + self.assertEqual(self.ref_private, decoded) + + # --- + + encoded = self.ref_private.export_key(format="DER", + passphrase="secret", + protection="PBKDF2WithHMAC-SHA384AndAES128-CBC", + prot_params={'iteration_count':123}) + decoded = ECC.import_key(encoded, "secret") + self.assertEqual(self.ref_private, decoded) + + + def test_export_public_pem(self): + key_file_ref = load_file("ecc_ed448_public.pem", "rt").strip() + key_file = self.ref_public.export_key(format="PEM").strip() + self.assertEqual(key_file_ref, key_file) + + def test_export_private_pem_clear(self): + key_file = load_file("ecc_ed448_private.pem", "rt").strip() + encoded = self.ref_private.export_key(format="PEM").strip() + self.assertEqual(key_file, encoded) + + def test_export_private_pem_encrypted(self): + encoded = self.ref_private.export_key(format="PEM", + passphrase=b"secret", + protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") + + # This should prove that the output is password-protected + self.assertRaises(ValueError, ECC.import_key, encoded) + + assert "ENCRYPTED PRIVATE KEY" in encoded + + decoded = ECC.import_key(encoded, "secret") + self.assertEqual(self.ref_private, decoded) + + def test_export_openssh(self): + # Not supported + self.assertRaises(ValueError, self.ref_public.export_key, format="OpenSSH") + + def test_export_raw(self): + encoded = self.ref_public.export_key(format='raw') + self.assertEqual(encoded, unhexlify(b'899014ddc0a0e1260cfc1085afdf952019e9fd63372e3e366e26dad32b176624884330a14617237e3081febd9d1a15069e7499433d2f55dd80')) + + def test_prng(self): + # Test that password-protected containers use the provided PRNG + encoded1 = self.ref_private.export_key(format="PEM", + passphrase="secret", + protection="PBKDF2WithHMAC-SHA1AndAES128-CBC", + randfunc=get_fixed_prng()) + encoded2 = self.ref_private.export_key(format="PEM", + passphrase="secret", + protection="PBKDF2WithHMAC-SHA1AndAES128-CBC", + randfunc=get_fixed_prng()) + self.assertEqual(encoded1, encoded2) + + def test_byte_or_string_passphrase(self): + encoded1 = self.ref_private.export_key(format="PEM", + passphrase="secret", + protection="PBKDF2WithHMAC-SHA1AndAES128-CBC", + randfunc=get_fixed_prng()) + encoded2 = self.ref_private.export_key(format="PEM", + passphrase=b"secret", + protection="PBKDF2WithHMAC-SHA1AndAES128-CBC", + randfunc=get_fixed_prng()) + self.assertEqual(encoded1, encoded2) + + def test_error_params1(self): + # Unknown format + self.assertRaises(ValueError, self.ref_private.export_key, format="XXX") + + # Missing 'protection' parameter when PKCS#8 is used + self.assertRaises(ValueError, self.ref_private.export_key, format="PEM", + passphrase="secret") + + # Empty password + self.assertRaises(ValueError, self.ref_private.export_key, format="PEM", + passphrase="", use_pkcs8=False) + self.assertRaises(ValueError, self.ref_private.export_key, format="PEM", + passphrase="", + protection="PBKDF2WithHMAC-SHA1AndAES128-CBC") + + # No private keys with OpenSSH + self.assertRaises(ValueError, self.ref_private.export_key, format="OpenSSH", + passphrase="secret") + + +def get_tests(config={}): + tests = [] + tests += list_test_cases(TestImport) + try: + tests += list_test_cases(TestImport_P192) + tests += list_test_cases(TestImport_P224) + tests += list_test_cases(TestImport_P256) + tests += list_test_cases(TestImport_P384) + tests += list_test_cases(TestImport_P521) + tests += list_test_cases(TestImport_Ed25519) + tests += list_test_cases(TestImport_Ed448) + + tests += list_test_cases(TestExport_P192) + tests += list_test_cases(TestExport_P224) + tests += list_test_cases(TestExport_P256) + tests += list_test_cases(TestExport_P384) + tests += list_test_cases(TestExport_P521) + tests += list_test_cases(TestExport_Ed25519) + tests += list_test_cases(TestExport_Ed448) + + except MissingTestVectorException: + pass + return tests + + +if __name__ == '__main__': + suite = lambda: unittest.TestSuite(get_tests()) + unittest.main(defaultTest='suite') diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/PublicKey/test_import_RSA.py b/venv/Lib/site-packages/Cryptodome/SelfTest/PublicKey/test_import_RSA.py new file mode 100644 index 0000000..b57676d --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/SelfTest/PublicKey/test_import_RSA.py @@ -0,0 +1,636 @@ +# -*- coding: utf-8 -*- +# +# SelfTest/PublicKey/test_importKey.py: Self-test for importing RSA keys +# +# =================================================================== +# The contents of this file are dedicated to the public domain. To +# the extent that dedication to the public domain is not available, +# everyone is granted a worldwide, perpetual, royalty-free, +# non-exclusive license to exercise all rights associated with the +# contents of this file for any purpose whatsoever. +# No rights are reserved. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# =================================================================== + +import os +import re +import errno +import warnings +import unittest +from unittest import SkipTest + +from Cryptodome.PublicKey import RSA +from Cryptodome.SelfTest.st_common import a2b_hex, list_test_cases +from Cryptodome.IO import PEM +from Cryptodome.Util.py3compat import b, tostr, FileNotFoundError +from Cryptodome.Util.number import inverse +from Cryptodome.Util import asn1 + +try: + import pycryptodome_test_vectors # type: ignore + test_vectors_available = True +except ImportError: + test_vectors_available = False + + +def load_file(file_name, mode="rb"): + results = None + + try: + if not test_vectors_available: + raise FileNotFoundError(errno.ENOENT, + os.strerror(errno.ENOENT), + file_name) + + dir_comps = ("PublicKey", "RSA") + init_dir = os.path.dirname(pycryptodome_test_vectors.__file__) + full_file_name = os.path.join(os.path.join(init_dir, *dir_comps), file_name) + with open(full_file_name, mode) as file_in: + results = file_in.read() + + except FileNotFoundError: + warnings.warn("Skipping tests for RSA based on %s" % file_name, + UserWarning, + stacklevel=2) + + if results is None: + raise SkipTest("Missing %s" % file_name) + + return results + + +def der2pem(der, text='PUBLIC'): + import binascii + chunks = [binascii.b2a_base64(der[i:i+48]) for i in range(0, len(der), 48)] + pem = b('-----BEGIN %s KEY-----\n' % text) + pem += b('').join(chunks) + pem += b('-----END %s KEY-----' % text) + return pem + + +class ImportKeyTests(unittest.TestCase): + # 512-bit RSA key generated with openssl + rsaKeyPEM = u'''-----BEGIN RSA PRIVATE KEY----- +MIIBOwIBAAJBAL8eJ5AKoIsjURpcEoGubZMxLD7+kT+TLr7UkvEtFrRhDDKMtuII +q19FrL4pUIMymPMSLBn3hJLe30Dw48GQM4UCAwEAAQJACUSDEp8RTe32ftq8IwG8 +Wojl5mAd1wFiIOrZ/Uv8b963WJOJiuQcVN29vxU5+My9GPZ7RA3hrDBEAoHUDPrI +OQIhAPIPLz4dphiD9imAkivY31Rc5AfHJiQRA7XixTcjEkojAiEAyh/pJHks/Mlr ++rdPNEpotBjfV4M4BkgGAA/ipcmaAjcCIQCHvhwwKVBLzzTscT2HeUdEeBMoiXXK +JACAr3sJQJGxIQIgarRp+m1WSKV1MciwMaTOnbU7wxFs9DP1pva76lYBzgUCIQC9 +n0CnZCJ6IZYqSt0H5N7+Q+2Ro64nuwV/OSQfM6sBwQ== +-----END RSA PRIVATE KEY-----''' + + # As above, but this is actually an unencrypted PKCS#8 key + rsaKeyPEM8 = u'''-----BEGIN PRIVATE KEY----- +MIIBVQIBADANBgkqhkiG9w0BAQEFAASCAT8wggE7AgEAAkEAvx4nkAqgiyNRGlwS +ga5tkzEsPv6RP5MuvtSS8S0WtGEMMoy24girX0WsvilQgzKY8xIsGfeEkt7fQPDj +wZAzhQIDAQABAkAJRIMSnxFN7fZ+2rwjAbxaiOXmYB3XAWIg6tn9S/xv3rdYk4mK +5BxU3b2/FTn4zL0Y9ntEDeGsMEQCgdQM+sg5AiEA8g8vPh2mGIP2KYCSK9jfVFzk +B8cmJBEDteLFNyMSSiMCIQDKH+kkeSz8yWv6t080Smi0GN9XgzgGSAYAD+KlyZoC +NwIhAIe+HDApUEvPNOxxPYd5R0R4EyiJdcokAICvewlAkbEhAiBqtGn6bVZIpXUx +yLAxpM6dtTvDEWz0M/Wm9rvqVgHOBQIhAL2fQKdkInohlipK3Qfk3v5D7ZGjrie7 +BX85JB8zqwHB +-----END PRIVATE KEY-----''' + + # The same RSA private key as in rsaKeyPEM, but now encrypted + rsaKeyEncryptedPEM = ( + + # PEM encryption + # With DES and passphrase 'test' + ('test', u'''-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: DES-CBC,AF8F9A40BD2FA2FC + +Ckl9ex1kaVEWhYC2QBmfaF+YPiR4NFkRXA7nj3dcnuFEzBnY5XULupqQpQI3qbfA +u8GYS7+b3toWWiHZivHbAAUBPDIZG9hKDyB9Sq2VMARGsX1yW1zhNvZLIiVJzUHs +C6NxQ1IJWOXzTew/xM2I26kPwHIvadq+/VaT8gLQdjdH0jOiVNaevjWnLgrn1mLP +BCNRMdcexozWtAFNNqSzfW58MJL2OdMi21ED184EFytIc1BlB+FZiGZduwKGuaKy +9bMbdb/1PSvsSzPsqW7KSSrTw6MgJAFJg6lzIYvR5F4poTVBxwBX3+EyEmShiaNY +IRX3TgQI0IjrVuLmvlZKbGWP18FXj7I7k9tSsNOOzllTTdq3ny5vgM3A+ynfAaxp +dysKznQ6P+IoqML1WxAID4aGRMWka+uArOJ148Rbj9s= +-----END RSA PRIVATE KEY-----'''), + + # PKCS8 encryption + ('winter', u'''-----BEGIN ENCRYPTED PRIVATE KEY----- +MIIBpjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQIeZIsbW3O+JcCAggA +MBQGCCqGSIb3DQMHBAgSM2p0D8FilgSCAWBhFyP2tiGKVpGj3mO8qIBzinU60ApR +3unvP+N6j7LVgnV2lFGaXbJ6a1PbQXe+2D6DUyBLo8EMXrKKVLqOMGkFMHc0UaV6 +R6MmrsRDrbOqdpTuVRW+NVd5J9kQQh4xnfU/QrcPPt7vpJvSf4GzG0n666Ki50OV +M/feuVlIiyGXY6UWdVDpcOV72cq02eNUs/1JWdh2uEBvA9fCL0c07RnMrdT+CbJQ +NjJ7f8ULtp7xvR9O3Al/yJ4Wv3i4VxF1f3MCXzhlUD4I0ONlr0kJWgeQ80q/cWhw +ntvgJwnCn2XR1h6LA8Wp+0ghDTsL2NhJpWd78zClGhyU4r3hqu1XDjoXa7YCXCix +jCV15+ViDJzlNCwg+W6lRg18sSLkCT7alviIE0U5tHc6UPbbHwT5QqAxAABaP+nZ +CGqJGyiwBzrKebjgSm/KRd4C91XqcsysyH2kKPfT51MLAoD4xelOURBP +-----END ENCRYPTED PRIVATE KEY-----''' + ), + ) + + rsaPublicKeyPEM = u'''-----BEGIN PUBLIC KEY----- +MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAL8eJ5AKoIsjURpcEoGubZMxLD7+kT+T +Lr7UkvEtFrRhDDKMtuIIq19FrL4pUIMymPMSLBn3hJLe30Dw48GQM4UCAwEAAQ== +-----END PUBLIC KEY-----''' + + # Obtained using 'ssh-keygen -i -m PKCS8 -f rsaPublicKeyPEM' + rsaPublicKeyOpenSSH = b('''ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAQQC/HieQCqCLI1EaXBKBrm2TMSw+/pE/ky6+1JLxLRa0YQwyjLbiCKtfRay+KVCDMpjzEiwZ94SS3t9A8OPBkDOF comment\n''') + + # The private key, in PKCS#1 format encoded with DER + rsaKeyDER = a2b_hex( + '''3082013b020100024100bf1e27900aa08b23511a5c1281ae6d93312c3efe + 913f932ebed492f12d16b4610c328cb6e208ab5f45acbe2950833298f312 + 2c19f78492dedf40f0e3c190338502030100010240094483129f114dedf6 + 7edabc2301bc5a88e5e6601dd7016220ead9fd4bfc6fdeb75893898ae41c + 54ddbdbf1539f8ccbd18f67b440de1ac30440281d40cfac839022100f20f + 2f3e1da61883f62980922bd8df545ce407c726241103b5e2c53723124a23 + 022100ca1fe924792cfcc96bfab74f344a68b418df578338064806000fe2 + a5c99a023702210087be1c3029504bcf34ec713d877947447813288975ca + 240080af7b094091b12102206ab469fa6d5648a57531c8b031a4ce9db53b + c3116cf433f5a6f6bbea5601ce05022100bd9f40a764227a21962a4add07 + e4defe43ed91a3ae27bb057f39241f33ab01c1 + '''.replace(" ","")) + + # The private key, in unencrypted PKCS#8 format encoded with DER + rsaKeyDER8 = a2b_hex( + '''30820155020100300d06092a864886f70d01010105000482013f3082013 + b020100024100bf1e27900aa08b23511a5c1281ae6d93312c3efe913f932 + ebed492f12d16b4610c328cb6e208ab5f45acbe2950833298f3122c19f78 + 492dedf40f0e3c190338502030100010240094483129f114dedf67edabc2 + 301bc5a88e5e6601dd7016220ead9fd4bfc6fdeb75893898ae41c54ddbdb + f1539f8ccbd18f67b440de1ac30440281d40cfac839022100f20f2f3e1da + 61883f62980922bd8df545ce407c726241103b5e2c53723124a23022100c + a1fe924792cfcc96bfab74f344a68b418df578338064806000fe2a5c99a0 + 23702210087be1c3029504bcf34ec713d877947447813288975ca240080a + f7b094091b12102206ab469fa6d5648a57531c8b031a4ce9db53bc3116cf + 433f5a6f6bbea5601ce05022100bd9f40a764227a21962a4add07e4defe4 + 3ed91a3ae27bb057f39241f33ab01c1 + '''.replace(" ","")) + + rsaPublicKeyDER = a2b_hex( + '''305c300d06092a864886f70d0101010500034b003048024100bf1e27900a + a08b23511a5c1281ae6d93312c3efe913f932ebed492f12d16b4610c328c + b6e208ab5f45acbe2950833298f3122c19f78492dedf40f0e3c190338502 + 03010001 + '''.replace(" ","")) + + n = int('BF 1E 27 90 0A A0 8B 23 51 1A 5C 12 81 AE 6D 93 31 2C 3E FE 91 3F 93 2E BE D4 92 F1 2D 16 B4 61 0C 32 8C B6 E2 08 AB 5F 45 AC BE 29 50 83 32 98 F3 12 2C 19 F7 84 92 DE DF 40 F0 E3 C1 90 33 85'.replace(" ",""),16) + e = 65537 + d = int('09 44 83 12 9F 11 4D ED F6 7E DA BC 23 01 BC 5A 88 E5 E6 60 1D D7 01 62 20 EA D9 FD 4B FC 6F DE B7 58 93 89 8A E4 1C 54 DD BD BF 15 39 F8 CC BD 18 F6 7B 44 0D E1 AC 30 44 02 81 D4 0C FA C8 39'.replace(" ",""),16) + p = int('00 F2 0F 2F 3E 1D A6 18 83 F6 29 80 92 2B D8 DF 54 5C E4 07 C7 26 24 11 03 B5 E2 C5 37 23 12 4A 23'.replace(" ",""),16) + q = int('00 CA 1F E9 24 79 2C FC C9 6B FA B7 4F 34 4A 68 B4 18 DF 57 83 38 06 48 06 00 0F E2 A5 C9 9A 02 37'.replace(" ",""),16) + + # This is q^{-1} mod p). fastmath and slowmath use pInv (p^{-1} + # mod q) instead! + qInv = int('00 BD 9F 40 A7 64 22 7A 21 96 2A 4A DD 07 E4 DE FE 43 ED 91 A3 AE 27 BB 05 7F 39 24 1F 33 AB 01 C1'.replace(" ",""),16) + pInv = inverse(p,q) + + def testImportKey1(self): + """Verify import of RSAPrivateKey DER SEQUENCE""" + key = RSA.importKey(self.rsaKeyDER) + self.assertTrue(key.has_private()) + self.assertEqual(key.n, self.n) + self.assertEqual(key.e, self.e) + self.assertEqual(key.d, self.d) + self.assertEqual(key.p, self.p) + self.assertEqual(key.q, self.q) + + def testImportKey2(self): + """Verify import of SubjectPublicKeyInfo DER SEQUENCE""" + key = RSA.importKey(self.rsaPublicKeyDER) + self.assertFalse(key.has_private()) + self.assertEqual(key.n, self.n) + self.assertEqual(key.e, self.e) + + def testImportKey3unicode(self): + """Verify import of RSAPrivateKey DER SEQUENCE, encoded with PEM as unicode""" + key = RSA.importKey(self.rsaKeyPEM) + self.assertEqual(key.has_private(),True) # assert_ + self.assertEqual(key.n, self.n) + self.assertEqual(key.e, self.e) + self.assertEqual(key.d, self.d) + self.assertEqual(key.p, self.p) + self.assertEqual(key.q, self.q) + + def testImportKey3bytes(self): + """Verify import of RSAPrivateKey DER SEQUENCE, encoded with PEM as byte string""" + key = RSA.importKey(b(self.rsaKeyPEM)) + self.assertEqual(key.has_private(),True) # assert_ + self.assertEqual(key.n, self.n) + self.assertEqual(key.e, self.e) + self.assertEqual(key.d, self.d) + self.assertEqual(key.p, self.p) + self.assertEqual(key.q, self.q) + + def testImportKey4unicode(self): + """Verify import of RSAPrivateKey DER SEQUENCE, encoded with PEM as unicode""" + key = RSA.importKey(self.rsaPublicKeyPEM) + self.assertEqual(key.has_private(),False) # assertFalse + self.assertEqual(key.n, self.n) + self.assertEqual(key.e, self.e) + + def testImportKey4bytes(self): + """Verify import of SubjectPublicKeyInfo DER SEQUENCE, encoded with PEM as byte string""" + key = RSA.importKey(b(self.rsaPublicKeyPEM)) + self.assertEqual(key.has_private(),False) # assertFalse + self.assertEqual(key.n, self.n) + self.assertEqual(key.e, self.e) + + def testImportKey5(self): + """Verifies that the imported key is still a valid RSA pair""" + key = RSA.importKey(self.rsaKeyPEM) + idem = key._encrypt(key._decrypt(89)) + self.assertEqual(idem, 89) + + def testImportKey6(self): + """Verifies that the imported key is still a valid RSA pair""" + key = RSA.importKey(self.rsaKeyDER) + idem = key._encrypt(key._decrypt(65)) + self.assertEqual(idem, 65) + + def testImportKey7(self): + """Verify import of OpenSSH public key""" + key = RSA.importKey(self.rsaPublicKeyOpenSSH) + self.assertEqual(key.n, self.n) + self.assertEqual(key.e, self.e) + + def testImportKey8(self): + """Verify import of encrypted PrivateKeyInfo DER SEQUENCE""" + for t in self.rsaKeyEncryptedPEM: + key = RSA.importKey(t[1], t[0]) + self.assertTrue(key.has_private()) + self.assertEqual(key.n, self.n) + self.assertEqual(key.e, self.e) + self.assertEqual(key.d, self.d) + self.assertEqual(key.p, self.p) + self.assertEqual(key.q, self.q) + + def testImportKey9(self): + """Verify import of unencrypted PrivateKeyInfo DER SEQUENCE""" + key = RSA.importKey(self.rsaKeyDER8) + self.assertTrue(key.has_private()) + self.assertEqual(key.n, self.n) + self.assertEqual(key.e, self.e) + self.assertEqual(key.d, self.d) + self.assertEqual(key.p, self.p) + self.assertEqual(key.q, self.q) + + def testImportKey10(self): + """Verify import of unencrypted PrivateKeyInfo DER SEQUENCE, encoded with PEM""" + key = RSA.importKey(self.rsaKeyPEM8) + self.assertTrue(key.has_private()) + self.assertEqual(key.n, self.n) + self.assertEqual(key.e, self.e) + self.assertEqual(key.d, self.d) + self.assertEqual(key.p, self.p) + self.assertEqual(key.q, self.q) + + def testImportKey11(self): + """Verify import of RSAPublicKey DER SEQUENCE""" + der = asn1.DerSequence([17, 3]).encode() + key = RSA.importKey(der) + self.assertEqual(key.n, 17) + self.assertEqual(key.e, 3) + + def testImportKey12(self): + """Verify import of RSAPublicKey DER SEQUENCE, encoded with PEM""" + der = asn1.DerSequence([17, 3]).encode() + pem = der2pem(der) + key = RSA.importKey(pem) + self.assertEqual(key.n, 17) + self.assertEqual(key.e, 3) + + def test_import_key_windows_cr_lf(self): + pem_cr_lf = "\r\n".join(self.rsaKeyPEM.splitlines()) + key = RSA.importKey(pem_cr_lf) + self.assertEqual(key.n, self.n) + self.assertEqual(key.e, self.e) + self.assertEqual(key.d, self.d) + self.assertEqual(key.p, self.p) + self.assertEqual(key.q, self.q) + + def test_import_empty(self): + self.assertRaises(ValueError, RSA.import_key, b"") + + ### + def testExportKey1(self): + key = RSA.construct([self.n, self.e, self.d, self.p, self.q, self.pInv]) + derKey = key.export_key("DER") + self.assertEqual(derKey, self.rsaKeyDER) + + def testExportKey2(self): + key = RSA.construct([self.n, self.e]) + derKey = key.export_key("DER") + self.assertEqual(derKey, self.rsaPublicKeyDER) + + def testExportKey3(self): + key = RSA.construct([self.n, self.e, self.d, self.p, self.q, self.pInv]) + pemKey = key.export_key("PEM") + self.assertEqual(pemKey, b(self.rsaKeyPEM)) + + def testExportKey4(self): + key = RSA.construct([self.n, self.e]) + pemKey = key.export_key("PEM") + self.assertEqual(pemKey, b(self.rsaPublicKeyPEM)) + + def testExportKey5(self): + key = RSA.construct([self.n, self.e]) + openssh_1 = key.export_key("OpenSSH").split() + openssh_2 = self.rsaPublicKeyOpenSSH.split() + self.assertEqual(openssh_1[0], openssh_2[0]) + self.assertEqual(openssh_1[1], openssh_2[1]) + + def testExportKey7(self): + key = RSA.construct([self.n, self.e, self.d, self.p, self.q, self.pInv]) + derKey = key.export_key("DER", pkcs=8) + self.assertEqual(derKey, self.rsaKeyDER8) + + def testExportKey8(self): + key = RSA.construct([self.n, self.e, self.d, self.p, self.q, self.pInv]) + pemKey = key.export_key("PEM", pkcs=8) + self.assertEqual(pemKey, b(self.rsaKeyPEM8)) + + def testExportKey9(self): + key = RSA.construct([self.n, self.e, self.d, self.p, self.q, self.pInv]) + self.assertRaises(ValueError, key.export_key, "invalid-format") + + def testExportKey10(self): + # Export and re-import the encrypted key. It must match. + # PEM envelope, PKCS#1, old PEM encryption + key = RSA.construct([self.n, self.e, self.d, self.p, self.q, self.pInv]) + outkey = key.export_key('PEM', 'test') + self.assertTrue(tostr(outkey).find('4,ENCRYPTED')!=-1) + self.assertTrue(tostr(outkey).find('BEGIN RSA PRIVATE KEY')!=-1) + inkey = RSA.importKey(outkey, 'test') + self.assertEqual(key.n, inkey.n) + self.assertEqual(key.e, inkey.e) + self.assertEqual(key.d, inkey.d) + + def testExportKey11(self): + # Export and re-import the encrypted key. It must match. + # PEM envelope, PKCS#1, old PEM encryption + key = RSA.construct([self.n, self.e, self.d, self.p, self.q, self.pInv]) + outkey = key.export_key('PEM', 'test', pkcs=1) + self.assertTrue(tostr(outkey).find('4,ENCRYPTED')!=-1) + self.assertTrue(tostr(outkey).find('BEGIN RSA PRIVATE KEY')!=-1) + inkey = RSA.importKey(outkey, 'test') + self.assertEqual(key.n, inkey.n) + self.assertEqual(key.e, inkey.e) + self.assertEqual(key.d, inkey.d) + + def testExportKey12(self): + # Export and re-import the encrypted key. It must match. + # PEM envelope, PKCS#8, old PEM encryption + key = RSA.construct([self.n, self.e, self.d, self.p, self.q, self.pInv]) + outkey = key.export_key('PEM', 'test', pkcs=8) + self.assertTrue(tostr(outkey).find('4,ENCRYPTED')!=-1) + self.assertTrue(tostr(outkey).find('BEGIN PRIVATE KEY')!=-1) + inkey = RSA.importKey(outkey, 'test') + self.assertEqual(key.n, inkey.n) + self.assertEqual(key.e, inkey.e) + self.assertEqual(key.d, inkey.d) + + def testExportKey13(self): + # Export and re-import the encrypted key. It must match. + # PEM envelope, PKCS#8, PKCS#8 encryption + key = RSA.construct([self.n, self.e, self.d, self.p, self.q, self.pInv]) + outkey = key.export_key('PEM', 'test', pkcs=8, + protection='PBKDF2WithHMAC-SHA1AndDES-EDE3-CBC') + self.assertTrue(tostr(outkey).find('4,ENCRYPTED')==-1) + self.assertTrue(tostr(outkey).find('BEGIN ENCRYPTED PRIVATE KEY')!=-1) + inkey = RSA.importKey(outkey, 'test') + self.assertEqual(key.n, inkey.n) + self.assertEqual(key.e, inkey.e) + self.assertEqual(key.d, inkey.d) + + def testExportKey14(self): + # Export and re-import the encrypted key. It must match. + # DER envelope, PKCS#8, PKCS#8 encryption + key = RSA.construct([self.n, self.e, self.d, self.p, self.q, self.pInv]) + outkey = key.export_key('DER', 'test', pkcs=8) + inkey = RSA.importKey(outkey, 'test') + self.assertEqual(key.n, inkey.n) + self.assertEqual(key.e, inkey.e) + self.assertEqual(key.d, inkey.d) + + def testExportKey15(self): + # Verify that that error an condition is detected when trying to + # use a password with DER encoding and PKCS#1. + key = RSA.construct([self.n, self.e, self.d, self.p, self.q, self.pInv]) + self.assertRaises(ValueError, key.export_key, 'DER', 'test', 1) + + def testExportKey16(self): + # Export and re-import the encrypted key. It must match. + # PEM envelope, PKCS#8, PKCS#8 encryption with parameters + key = RSA.construct([self.n, self.e, self.d, self.p, self.q, self.pInv]) + outkey = key.export_key('PEM', 'test', pkcs=8, + protection='PBKDF2WithHMAC-SHA512AndAES256-CBC', + prot_params={'iteration_count':123} + ) + self.assertTrue(tostr(outkey).find('4,ENCRYPTED')==-1) + self.assertTrue(tostr(outkey).find('BEGIN ENCRYPTED PRIVATE KEY')!=-1) + + # Verify the iteration count + der = PEM.decode(tostr(outkey))[0] + seq1 = asn1.DerSequence().decode(der) + seq2 = asn1.DerSequence().decode(seq1[0]) + seq3 = asn1.DerSequence().decode(seq2[1]) + seq4 = asn1.DerSequence().decode(seq3[0]) + seq5 = asn1.DerSequence().decode(seq4[1]) + self.assertEqual(seq5[1], 123) + + inkey = RSA.importKey(outkey, 'test') + self.assertEqual(key.n, inkey.n) + self.assertEqual(key.e, inkey.e) + self.assertEqual(key.d, inkey.d) + + def test_import_key(self): + """Verify that import_key is an alias to importKey""" + key = RSA.import_key(self.rsaPublicKeyDER) + self.assertFalse(key.has_private()) + self.assertEqual(key.n, self.n) + self.assertEqual(key.e, self.e) + + def test_import_key_ba_mv(self): + """Verify that import_key can be used on bytearrays and memoryviews""" + key = RSA.import_key(bytearray(self.rsaPublicKeyDER)) + key = RSA.import_key(memoryview(self.rsaPublicKeyDER)) + + def test_exportKey(self): + key = RSA.construct([self.n, self.e, self.d, self.p, self.q, self.pInv]) + self.assertEqual(key.export_key(), key.exportKey()) + + +class ImportKeyFromX509Cert(unittest.TestCase): + + def test_x509v1(self): + + # Sample V1 certificate with a 1024 bit RSA key + x509_v1_cert = """ +-----BEGIN CERTIFICATE----- +MIICOjCCAaMCAQEwDQYJKoZIhvcNAQEEBQAwfjENMAsGA1UEChMEQWNtZTELMAkG +A1UECxMCUkQxHDAaBgkqhkiG9w0BCQEWDXNwYW1AYWNtZS5vcmcxEzARBgNVBAcT +Ck1ldHJvcG9saXMxETAPBgNVBAgTCE5ldyBZb3JrMQswCQYDVQQGEwJVUzENMAsG +A1UEAxMEdGVzdDAeFw0xNDA3MTExOTU3MjRaFw0xNzA0MDYxOTU3MjRaME0xCzAJ +BgNVBAYTAlVTMREwDwYDVQQIEwhOZXcgWW9yazENMAsGA1UEChMEQWNtZTELMAkG +A1UECxMCUkQxDzANBgNVBAMTBmxhdHZpYTCBnzANBgkqhkiG9w0BAQEFAAOBjQAw +gYkCgYEAyG+kytdRj3TFbRmHDYp3TXugVQ81chew0qeOxZWOz80IjtWpgdOaCvKW +NCuc8wUR9BWrEQW+39SaRMLiQfQtyFSQZijc3nsEBu/Lo4uWZ0W/FHDRVSvkJA/V +Ex5NL5ikI+wbUeCV5KajGNDalZ8F1pk32+CBs8h1xNx5DyxuEHUCAwEAATANBgkq +hkiG9w0BAQQFAAOBgQCVQF9Y//Q4Psy+umEM38pIlbZ2hxC5xNz/MbVPwuCkNcGn +KYNpQJP+JyVTsPpO8RLZsAQDzRueMI3S7fbbwTzAflN0z19wvblvu93xkaBytVok +9VBAH28olVhy9b1MMeg2WOt5sUEQaFNPnwwsyiY9+HsRpvpRnPSQF+kyYVsshQ== +-----END CERTIFICATE----- + """.strip() + + # RSA public key as dumped by openssl + exponent = 65537 + modulus_str = """ +00:c8:6f:a4:ca:d7:51:8f:74:c5:6d:19:87:0d:8a: +77:4d:7b:a0:55:0f:35:72:17:b0:d2:a7:8e:c5:95: +8e:cf:cd:08:8e:d5:a9:81:d3:9a:0a:f2:96:34:2b: +9c:f3:05:11:f4:15:ab:11:05:be:df:d4:9a:44:c2: +e2:41:f4:2d:c8:54:90:66:28:dc:de:7b:04:06:ef: +cb:a3:8b:96:67:45:bf:14:70:d1:55:2b:e4:24:0f: +d5:13:1e:4d:2f:98:a4:23:ec:1b:51:e0:95:e4:a6: +a3:18:d0:da:95:9f:05:d6:99:37:db:e0:81:b3:c8: +75:c4:dc:79:0f:2c:6e:10:75 + """ + modulus = int(re.sub("[^0-9a-f]","", modulus_str), 16) + + key = RSA.importKey(x509_v1_cert) + self.assertEqual(key.e, exponent) + self.assertEqual(key.n, modulus) + self.assertFalse(key.has_private()) + + def test_x509v3(self): + + # Sample V3 certificate with a 1024 bit RSA key + x509_v3_cert = """ +-----BEGIN CERTIFICATE----- +MIIEcjCCAlqgAwIBAgIBATANBgkqhkiG9w0BAQsFADBhMQswCQYDVQQGEwJVUzEL +MAkGA1UECAwCTUQxEjAQBgNVBAcMCUJhbHRpbW9yZTEQMA4GA1UEAwwHVGVzdCBD +QTEfMB0GCSqGSIb3DQEJARYQdGVzdEBleGFtcGxlLmNvbTAeFw0xNDA3MTIwOTM1 +MTJaFw0xNzA0MDcwOTM1MTJaMEQxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJNRDES +MBAGA1UEBwwJQmFsdGltb3JlMRQwEgYDVQQDDAtUZXN0IFNlcnZlcjCBnzANBgkq +hkiG9w0BAQEFAAOBjQAwgYkCgYEA/S7GJV2OcFdyNMQ4K75KrYFtMEn3VnEFdPHa +jyS37XlMxSh0oS4GeTGVUCJInl5Cpsv8WQdh03FfeOdvzp5IZ46OcjeOPiWnmjgl +2G5j7e2bDH7RSchGV+OD6Fb1Agvuu2/9iy8fdf3rPQ/7eAddzKUrzwacVbnW+tg2 +QtSXKRcCAwEAAaOB1TCB0jAdBgNVHQ4EFgQU/WwCX7FfWMIPDFfJ+I8a2COG+l8w +HwYDVR0jBBgwFoAUa0hkif3RMaraiWtsOOZZlLu9wJwwCQYDVR0TBAIwADALBgNV +HQ8EBAMCBeAwSgYDVR0RBEMwQYILZXhhbXBsZS5jb22CD3d3dy5leGFtcGxlLmNv +bYIQbWFpbC5leGFtcGxlLmNvbYIPZnRwLmV4YW1wbGUuY29tMCwGCWCGSAGG+EIB +DQQfFh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTANBgkqhkiG9w0BAQsF +AAOCAgEAvO6xfdsGbnoK4My3eJthodTAjMjPwFVY133LH04QLcCv54TxKhtUg1fi +PgdjVe1HpTytPBfXy2bSZbXAN0abZCtw1rYrnn7o1g2pN8iypVq3zVn0iMTzQzxs +zEPO3bpR/UhNSf90PmCsS5rqZpAAnXSaAy1ClwHWk/0eG2pYkhE1m1ABVMN2lsAW +e9WxGk6IFqaI9O37NYQwmEypMs4DC+ECJEvbPFiqi3n0gbXCZJJ6omDA5xJldaYK +Oa7KR3s/qjBsu9UAiWpLBuFoSTHIF2aeRKRFmUdmzwo43eVPep65pY6eQ4AdL2RF +rqEuINbGlzI5oQyYhu71IwB+iPZXaZZPlwjLgOsuad/p2hOgDb5WxUi8FnDPursQ +ujfpIpmrOP/zpvvQWnwePI3lI+5n41kTBSbefXEdv6rXpHk3QRzB90uPxnXPdxSC +16ASA8bQT5an/1AgoE3k9CrcD2K0EmgaX0YI0HUhkyzbkg34EhpWJ6vvRUbRiNRo +9cIbt/ya9Y9u0Ja8GLXv6dwX0l0IdJMkL8KifXUFAVCujp1FBrr/gdmwQn8itANy ++qbnWSxmOvtaY0zcaFAcONuHva0h51/WqXOMO1eb8PhR4HIIYU8p1oBwQp7dSni8 +THDi1F+GG5PsymMDj5cWK42f+QzjVw5PrVmFqqrrEoMlx8DWh5Y= +-----END CERTIFICATE----- +""".strip() + + # RSA public key as dumped by openssl + exponent = 65537 + modulus_str = """ +00:fd:2e:c6:25:5d:8e:70:57:72:34:c4:38:2b:be: +4a:ad:81:6d:30:49:f7:56:71:05:74:f1:da:8f:24: +b7:ed:79:4c:c5:28:74:a1:2e:06:79:31:95:50:22: +48:9e:5e:42:a6:cb:fc:59:07:61:d3:71:5f:78:e7: +6f:ce:9e:48:67:8e:8e:72:37:8e:3e:25:a7:9a:38: +25:d8:6e:63:ed:ed:9b:0c:7e:d1:49:c8:46:57:e3: +83:e8:56:f5:02:0b:ee:bb:6f:fd:8b:2f:1f:75:fd: +eb:3d:0f:fb:78:07:5d:cc:a5:2b:cf:06:9c:55:b9: +d6:fa:d8:36:42:d4:97:29:17 + """ + modulus = int(re.sub("[^0-9a-f]","", modulus_str), 16) + + key = RSA.importKey(x509_v3_cert) + self.assertEqual(key.e, exponent) + self.assertEqual(key.n, modulus) + self.assertFalse(key.has_private()) + + +class TestImport_2048(unittest.TestCase): + + def test_import_pss(self): + pub_key_file = load_file("rsa2048_pss_public.pem") + pub_key = RSA.import_key(pub_key_file) + + priv_key_file = load_file("rsa2048_pss_private.pem") + priv_key = RSA.import_key(priv_key_file) + + self.assertEqual(pub_key.n, priv_key.n) + + def test_import_openssh_public(self): + key_file_ref = load_file("rsa2048_private.pem") + key_file = load_file("rsa2048_public_openssh.txt") + + # Skip test if test vectors are not installed + if None in (key_file_ref, key_file): + return + + key_ref = RSA.import_key(key_file_ref).public_key() + key = RSA.import_key(key_file) + self.assertEqual(key_ref, key) + + def test_import_openssh_private_clear(self): + key_file = load_file("rsa2048_private_openssh.pem") + key_file_old = load_file("rsa2048_private_openssh_old.pem") + + # Skip test if test vectors are not installed + if None in (key_file_old, key_file): + return + + key = RSA.import_key(key_file) + key_old = RSA.import_key(key_file_old) + + self.assertEqual(key, key_old) + + def test_import_openssh_private_password(self): + key_file = load_file("rsa2048_private_openssh_pwd.pem") + key_file_old = load_file("rsa2048_private_openssh_pwd_old.pem") + + # Skip test if test vectors are not installed + if None in (key_file_old, key_file): + return + + key = RSA.import_key(key_file, b"password") + key_old = RSA.import_key(key_file_old) + self.assertEqual(key, key_old) + + def test_import_pkcs8_private(self): + key_file_ref = load_file("rsa2048_private.pem") + key_file = load_file("rsa2048_private_p8.der") + + # Skip test if test vectors are not installed + if None in (key_file_ref, key_file): + return + + key_ref = RSA.import_key(key_file_ref) + key = RSA.import_key(key_file, b'secret') + self.assertEqual(key_ref, key) + + +def get_tests(config={}): + tests = [] + tests += list_test_cases(ImportKeyTests) + tests += list_test_cases(ImportKeyFromX509Cert) + tests += list_test_cases(TestImport_2048) + return tests + + +if __name__ == '__main__': + def suite(): + return unittest.TestSuite(get_tests()) + unittest.main(defaultTest='suite') diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Random/__init__.py b/venv/Lib/site-packages/Cryptodome/SelfTest/Random/__init__.py new file mode 100644 index 0000000..763ee9c --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/SelfTest/Random/__init__.py @@ -0,0 +1,39 @@ +# -*- coding: utf-8 -*- +# +# SelfTest/Random/__init__.py: Self-test for random number generation modules +# +# Written in 2008 by Dwayne C. Litzenberger +# +# =================================================================== +# The contents of this file are dedicated to the public domain. To +# the extent that dedication to the public domain is not available, +# everyone is granted a worldwide, perpetual, royalty-free, +# non-exclusive license to exercise all rights associated with the +# contents of this file for any purpose whatsoever. +# No rights are reserved. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# =================================================================== + +"""Self-test for random number generators""" + +__revision__ = "$Id$" + +def get_tests(config={}): + tests = [] + from Cryptodome.SelfTest.Random import test_random; tests += test_random.get_tests(config=config) + return tests + +if __name__ == '__main__': + import unittest + suite = lambda: unittest.TestSuite(get_tests()) + unittest.main(defaultTest='suite') + +# vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Random/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/SelfTest/Random/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000..cfc8d30 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/SelfTest/Random/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Random/__pycache__/test_random.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/SelfTest/Random/__pycache__/test_random.cpython-312.pyc new file mode 100644 index 0000000..62610d2 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/SelfTest/Random/__pycache__/test_random.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Random/test_random.py b/venv/Lib/site-packages/Cryptodome/SelfTest/Random/test_random.py new file mode 100644 index 0000000..30e9194 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/SelfTest/Random/test_random.py @@ -0,0 +1,167 @@ +# -*- coding: utf-8 -*- +# +# SelfTest/Util/test_generic.py: Self-test for the Cryptodome.Random.new() function +# +# Written in 2008 by Dwayne C. Litzenberger +# +# =================================================================== +# The contents of this file are dedicated to the public domain. To +# the extent that dedication to the public domain is not available, +# everyone is granted a worldwide, perpetual, royalty-free, +# non-exclusive license to exercise all rights associated with the +# contents of this file for any purpose whatsoever. +# No rights are reserved. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# =================================================================== + +"""Self-test suite for Cryptodome.Random.new()""" + +import sys +import unittest +from Cryptodome.Util.py3compat import b + +class SimpleTest(unittest.TestCase): + def runTest(self): + """Cryptodome.Random.new()""" + # Import the Random module and try to use it + from Cryptodome import Random + randobj = Random.new() + x = randobj.read(16) + y = randobj.read(16) + self.assertNotEqual(x, y) + z = Random.get_random_bytes(16) + self.assertNotEqual(x, z) + self.assertNotEqual(y, z) + # Test the Random.random module, which + # implements a subset of Python's random API + # Not implemented: + # seed(), getstate(), setstate(), jumpahead() + # random(), uniform(), triangular(), betavariate() + # expovariate(), gammavariate(), gauss(), + # longnormvariate(), normalvariate(), + # vonmisesvariate(), paretovariate() + # weibullvariate() + # WichmannHill(), whseed(), SystemRandom() + from Cryptodome.Random import random + x = random.getrandbits(16*8) + y = random.getrandbits(16*8) + self.assertNotEqual(x, y) + # Test randrange + if x>y: + start = y + stop = x + else: + start = x + stop = y + for step in range(1,10): + x = random.randrange(start,stop,step) + y = random.randrange(start,stop,step) + self.assertNotEqual(x, y) + self.assertEqual(start <= x < stop, True) + self.assertEqual(start <= y < stop, True) + self.assertEqual((x - start) % step, 0) + self.assertEqual((y - start) % step, 0) + for i in range(10): + self.assertEqual(random.randrange(1,2), 1) + self.assertRaises(ValueError, random.randrange, start, start) + self.assertRaises(ValueError, random.randrange, stop, start, step) + self.assertRaises(TypeError, random.randrange, start, stop, step, step) + self.assertRaises(TypeError, random.randrange, start, stop, "1") + self.assertRaises(TypeError, random.randrange, "1", stop, step) + self.assertRaises(TypeError, random.randrange, 1, "2", step) + self.assertRaises(ValueError, random.randrange, start, stop, 0) + # Test randint + x = random.randint(start,stop) + y = random.randint(start,stop) + self.assertNotEqual(x, y) + self.assertEqual(start <= x <= stop, True) + self.assertEqual(start <= y <= stop, True) + for i in range(10): + self.assertEqual(random.randint(1,1), 1) + self.assertRaises(ValueError, random.randint, stop, start) + self.assertRaises(TypeError, random.randint, start, stop, step) + self.assertRaises(TypeError, random.randint, "1", stop) + self.assertRaises(TypeError, random.randint, 1, "2") + # Test choice + seq = range(10000) + x = random.choice(seq) + y = random.choice(seq) + self.assertNotEqual(x, y) + self.assertEqual(x in seq, True) + self.assertEqual(y in seq, True) + for i in range(10): + self.assertEqual(random.choice((1,2,3)) in (1,2,3), True) + self.assertEqual(random.choice([1,2,3]) in [1,2,3], True) + if sys.version_info[0] == 3: + self.assertEqual(random.choice(bytearray(b('123'))) in bytearray(b('123')), True) + self.assertEqual(1, random.choice([1])) + self.assertRaises(IndexError, random.choice, []) + self.assertRaises(TypeError, random.choice, 1) + # Test shuffle. Lacks random parameter to specify function. + # Make copies of seq + seq = range(500) + x = list(seq) + y = list(seq) + random.shuffle(x) + random.shuffle(y) + self.assertNotEqual(x, y) + self.assertEqual(len(seq), len(x)) + self.assertEqual(len(seq), len(y)) + for i in range(len(seq)): + self.assertEqual(x[i] in seq, True) + self.assertEqual(y[i] in seq, True) + self.assertEqual(seq[i] in x, True) + self.assertEqual(seq[i] in y, True) + z = [1] + random.shuffle(z) + self.assertEqual(z, [1]) + if sys.version_info[0] == 3: + z = bytearray(b('12')) + random.shuffle(z) + self.assertEqual(b('1') in z, True) + self.assertRaises(TypeError, random.shuffle, b('12')) + self.assertRaises(TypeError, random.shuffle, 1) + self.assertRaises(TypeError, random.shuffle, "11") + self.assertRaises(TypeError, random.shuffle, (1,2)) + # 2to3 wraps a list() around it, alas - but I want to shoot + # myself in the foot here! :D + # if sys.version_info[0] == 3: + # self.assertRaises(TypeError, random.shuffle, range(3)) + # Test sample + x = random.sample(seq, 20) + y = random.sample(seq, 20) + self.assertNotEqual(x, y) + for i in range(20): + self.assertEqual(x[i] in seq, True) + self.assertEqual(y[i] in seq, True) + z = random.sample([1], 1) + self.assertEqual(z, [1]) + z = random.sample((1,2,3), 1) + self.assertEqual(z[0] in (1,2,3), True) + z = random.sample("123", 1) + self.assertEqual(z[0] in "123", True) + z = random.sample(range(3), 1) + self.assertEqual(z[0] in range(3), True) + if sys.version_info[0] == 3: + z = random.sample(b("123"), 1) + self.assertEqual(z[0] in b("123"), True) + z = random.sample(bytearray(b("123")), 1) + self.assertEqual(z[0] in bytearray(b("123")), True) + self.assertRaises(TypeError, random.sample, 1) + +def get_tests(config={}): + return [SimpleTest()] + +if __name__ == '__main__': + suite = lambda: unittest.TestSuite(get_tests()) + unittest.main(defaultTest='suite') + +# vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Signature/__init__.py b/venv/Lib/site-packages/Cryptodome/SelfTest/Signature/__init__.py new file mode 100644 index 0000000..83cf0f3 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/SelfTest/Signature/__init__.py @@ -0,0 +1,41 @@ +# -*- coding: utf-8 -*- +# +# SelfTest/Signature/__init__.py: Self-test for signature modules +# +# =================================================================== +# The contents of this file are dedicated to the public domain. To +# the extent that dedication to the public domain is not available, +# everyone is granted a worldwide, perpetual, royalty-free, +# non-exclusive license to exercise all rights associated with the +# contents of this file for any purpose whatsoever. +# No rights are reserved. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# =================================================================== + +"""Self-test for signature modules""" + +import unittest +from . import test_pkcs1_15, test_pss, test_dss, test_eddsa + + +def get_tests(config={}): + tests = [] + tests += test_pkcs1_15.get_tests(config=config) + tests += test_pss.get_tests(config=config) + tests += test_dss.get_tests(config=config) + tests += test_eddsa.get_tests(config=config) + return tests + + +if __name__ == '__main__': + def suite(): + return unittest.TestSuite(get_tests()) + unittest.main(defaultTest='suite') diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Signature/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/SelfTest/Signature/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000..2f95601 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/SelfTest/Signature/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Signature/__pycache__/test_dss.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/SelfTest/Signature/__pycache__/test_dss.cpython-312.pyc new file mode 100644 index 0000000..20c4d39 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/SelfTest/Signature/__pycache__/test_dss.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Signature/__pycache__/test_eddsa.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/SelfTest/Signature/__pycache__/test_eddsa.cpython-312.pyc new file mode 100644 index 0000000..f6e9962 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/SelfTest/Signature/__pycache__/test_eddsa.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Signature/__pycache__/test_pkcs1_15.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/SelfTest/Signature/__pycache__/test_pkcs1_15.cpython-312.pyc new file mode 100644 index 0000000..7b1457c Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/SelfTest/Signature/__pycache__/test_pkcs1_15.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Signature/__pycache__/test_pss.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/SelfTest/Signature/__pycache__/test_pss.cpython-312.pyc new file mode 100644 index 0000000..04ba461 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/SelfTest/Signature/__pycache__/test_pss.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Signature/test_dss.py b/venv/Lib/site-packages/Cryptodome/SelfTest/Signature/test_dss.py new file mode 100644 index 0000000..156ee67 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/SelfTest/Signature/test_dss.py @@ -0,0 +1,1369 @@ +# +# SelfTest/Signature/test_dss.py: Self-test for DSS signatures +# +# =================================================================== +# +# Copyright (c) 2014, Legrandin +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# =================================================================== + +import re +import unittest +from binascii import hexlify, unhexlify + +from Cryptodome.Util.py3compat import tobytes, bord, bchr + +from Cryptodome.Hash import (SHA1, SHA224, SHA256, SHA384, SHA512, + SHA3_224, SHA3_256, SHA3_384, SHA3_512) +from Cryptodome.Signature import DSS +from Cryptodome.PublicKey import DSA, ECC +from Cryptodome.SelfTest.st_common import list_test_cases +from Cryptodome.SelfTest.loader import load_test_vectors, load_test_vectors_wycheproof +from Cryptodome.Util.number import bytes_to_long, long_to_bytes + + +def t2b(hexstring): + ws = hexstring.replace(" ", "").replace("\n", "") + return unhexlify(tobytes(ws)) + + +def t2l(hexstring): + ws = hexstring.replace(" ", "").replace("\n", "") + return int(ws, 16) + + +def load_hash_by_name(hash_name): + return __import__("Cryptodome.Hash." + hash_name, globals(), locals(), ["new"]) + + +class StrRNG: + + def __init__(self, randomness): + length = len(randomness) + self._idx = 0 + # Fix required to get the right K (see how randint() works!) + self._randomness = long_to_bytes(bytes_to_long(randomness) - 1, length) + + def __call__(self, n): + out = self._randomness[self._idx:self._idx + n] + self._idx += n + return out + + +class FIPS_DSA_Tests(unittest.TestCase): + + # 1st 1024 bit key from SigGen.txt + P = 0xa8f9cd201e5e35d892f85f80e4db2599a5676a3b1d4f190330ed3256b26d0e80a0e49a8fffaaad2a24f472d2573241d4d6d6c7480c80b4c67bb4479c15ada7ea8424d2502fa01472e760241713dab025ae1b02e1703a1435f62ddf4ee4c1b664066eb22f2e3bf28bb70a2a76e4fd5ebe2d1229681b5b06439ac9c7e9d8bde283 + Q = 0xf85f0f83ac4df7ea0cdf8f469bfeeaea14156495 + G = 0x2b3152ff6c62f14622b8f48e59f8af46883b38e79b8c74deeae9df131f8b856e3ad6c8455dab87cc0da8ac973417ce4f7878557d6cdf40b35b4a0ca3eb310c6a95d68ce284ad4e25ea28591611ee08b8444bd64b25f3f7c572410ddfb39cc728b9c936f85f419129869929cdb909a6a3a99bbe089216368171bd0ba81de4fe33 + X = 0xc53eae6d45323164c7d07af5715703744a63fc3a + Y = 0x313fd9ebca91574e1c2eebe1517c57e0c21b0209872140c5328761bbb2450b33f1b18b409ce9ab7c4cd8fda3391e8e34868357c199e16a6b2eba06d6749def791d79e95d3a4d09b24c392ad89dbf100995ae19c01062056bb14bce005e8731efde175f95b975089bdcdaea562b32786d96f5a31aedf75364008ad4fffebb970b + + key_pub = DSA.construct((Y, G, P, Q)) + key_priv = DSA.construct((Y, G, P, Q, X)) + + def shortDescription(self): + return "FIPS DSA Tests" + + def test_loopback(self): + hashed_msg = SHA512.new(b"test") + signer = DSS.new(self.key_priv, 'fips-186-3') + signature = signer.sign(hashed_msg) + + verifier = DSS.new(self.key_pub, 'fips-186-3') + verifier.verify(hashed_msg, signature) + + def test_negative_unapproved_hashes(self): + """Verify that unapproved hashes are rejected""" + + from Cryptodome.Hash import RIPEMD160 + + self.description = "Unapproved hash (RIPEMD160) test" + hash_obj = RIPEMD160.new() + signer = DSS.new(self.key_priv, 'fips-186-3') + self.assertRaises(ValueError, signer.sign, hash_obj) + self.assertRaises(ValueError, signer.verify, hash_obj, b"\x00" * 40) + + def test_negative_unknown_modes_encodings(self): + """Verify that unknown modes/encodings are rejected""" + + self.description = "Unknown mode test" + self.assertRaises(ValueError, DSS.new, self.key_priv, 'fips-186-0') + + self.description = "Unknown encoding test" + self.assertRaises(ValueError, DSS.new, self.key_priv, 'fips-186-3', 'xml') + + def test_asn1_encoding(self): + """Verify ASN.1 encoding""" + + self.description = "ASN.1 encoding test" + hash_obj = SHA1.new() + signer = DSS.new(self.key_priv, 'fips-186-3', 'der') + signature = signer.sign(hash_obj) + + # Verify that output looks like a DER SEQUENCE + self.assertEqual(bord(signature[0]), 48) + signer.verify(hash_obj, signature) + + # Verify that ASN.1 parsing fails as expected + signature = bchr(7) + signature[1:] + self.assertRaises(ValueError, signer.verify, hash_obj, signature) + + def test_sign_verify(self): + """Verify public/private method""" + + self.description = "can_sign() test" + signer = DSS.new(self.key_priv, 'fips-186-3') + self.assertTrue(signer.can_sign()) + + signer = DSS.new(self.key_pub, 'fips-186-3') + self.assertFalse(signer.can_sign()) + + try: + signer.sign(SHA256.new(b'xyz')) + except TypeError as e: + msg = str(e) + else: + msg = "" + self.assertTrue("Private key is needed" in msg) + + +class FIPS_DSA_Tests_KAT(unittest.TestCase): + pass + + +test_vectors_verify = load_test_vectors(("Signature", "DSA"), + "FIPS_186_3_SigVer.rsp", + "Signature Verification 186-3", + {'result': lambda x: x}) or [] + +for idx, tv in enumerate(test_vectors_verify): + + if isinstance(tv, str): + res = re.match(r"\[mod = L=([0-9]+), N=([0-9]+), ([a-zA-Z0-9-]+)\]", tv) + assert(res) + hash_name = res.group(3).replace("-", "") + hash_module = load_hash_by_name(hash_name) + continue + + if hasattr(tv, "p"): + modulus = tv.p + generator = tv.g + suborder = tv.q + continue + + hash_obj = hash_module.new(tv.msg) + + comps = [bytes_to_long(x) for x in (tv.y, generator, modulus, suborder)] + key = DSA.construct(comps, False) # type: ignore + verifier = DSS.new(key, 'fips-186-3') + + def positive_test(self, verifier=verifier, hash_obj=hash_obj, signature=tv.r+tv.s): + verifier.verify(hash_obj, signature) + + def negative_test(self, verifier=verifier, hash_obj=hash_obj, signature=tv.r+tv.s): + self.assertRaises(ValueError, verifier.verify, hash_obj, signature) + + if tv.result == 'p': + setattr(FIPS_DSA_Tests_KAT, "test_verify_positive_%d" % idx, positive_test) + else: + setattr(FIPS_DSA_Tests_KAT, "test_verify_negative_%d" % idx, negative_test) + + +test_vectors_sign = load_test_vectors(("Signature", "DSA"), + "FIPS_186_3_SigGen.txt", + "Signature Creation 186-3", + {}) or [] + +for idx, tv in enumerate(test_vectors_sign): + + if isinstance(tv, str): + res = re.match(r"\[mod = L=([0-9]+), N=([0-9]+), ([a-zA-Z0-9-]+)\]", tv) + assert(res) + hash_name = res.group(3).replace("-", "") + hash_module = load_hash_by_name(hash_name) + continue + + if hasattr(tv, "p"): + modulus = tv.p + generator = tv.g + suborder = tv.q + continue + + hash_obj = hash_module.new(tv.msg) + comps_dsa = [bytes_to_long(x) for x in (tv.y, generator, modulus, suborder, tv.x)] + key = DSA.construct(comps_dsa, False) # type: ignore + signer = DSS.new(key, 'fips-186-3', randfunc=StrRNG(tv.k)) + + def new_test(self, signer=signer, hash_obj=hash_obj, signature=tv.r+tv.s): + self.assertEqual(signer.sign(hash_obj), signature) + setattr(FIPS_DSA_Tests_KAT, "test_sign_%d" % idx, new_test) + + +class FIPS_ECDSA_Tests(unittest.TestCase): + + key_priv = ECC.generate(curve="P-256") + key_pub = key_priv.public_key() + + def shortDescription(self): + return "FIPS ECDSA Tests" + + def test_loopback(self): + hashed_msg = SHA512.new(b"test") + signer = DSS.new(self.key_priv, 'fips-186-3') + signature = signer.sign(hashed_msg) + + verifier = DSS.new(self.key_pub, 'fips-186-3') + verifier.verify(hashed_msg, signature) + + def test_negative_unapproved_hashes(self): + """Verify that unapproved hashes are rejected""" + + from Cryptodome.Hash import SHA1 + + self.description = "Unapproved hash (SHA-1) test" + hash_obj = SHA1.new() + signer = DSS.new(self.key_priv, 'fips-186-3') + self.assertRaises(ValueError, signer.sign, hash_obj) + self.assertRaises(ValueError, signer.verify, hash_obj, b"\x00" * 40) + + def test_negative_eddsa_key(self): + key = ECC.generate(curve="ed25519") + self.assertRaises(ValueError, DSS.new, key, 'fips-186-3') + + def test_sign_verify(self): + """Verify public/private method""" + + self.description = "can_sign() test" + signer = DSS.new(self.key_priv, 'fips-186-3') + self.assertTrue(signer.can_sign()) + + signer = DSS.new(self.key_pub, 'fips-186-3') + self.assertFalse(signer.can_sign()) + self.assertRaises(TypeError, signer.sign, SHA256.new(b'xyz')) + + try: + signer.sign(SHA256.new(b'xyz')) + except TypeError as e: + msg = str(e) + else: + msg = "" + self.assertTrue("Private key is needed" in msg) + + def test_negative_unknown_modes_encodings(self): + """Verify that unknown modes/encodings are rejected""" + + self.description = "Unknown mode test" + self.assertRaises(ValueError, DSS.new, self.key_priv, 'fips-186-0') + + self.description = "Unknown encoding test" + self.assertRaises(ValueError, DSS.new, self.key_priv, 'fips-186-3', 'xml') + + def test_asn1_encoding(self): + """Verify ASN.1 encoding""" + + self.description = "ASN.1 encoding test" + hash_obj = SHA256.new() + signer = DSS.new(self.key_priv, 'fips-186-3', 'der') + signature = signer.sign(hash_obj) + + # Verify that output looks like a DER SEQUENCE + self.assertEqual(bord(signature[0]), 48) + signer.verify(hash_obj, signature) + + # Verify that ASN.1 parsing fails as expected + signature = bchr(7) + signature[1:] + self.assertRaises(ValueError, signer.verify, hash_obj, signature) + + +class FIPS_ECDSA_Tests_KAT(unittest.TestCase): + pass + + +test_vectors_verify = load_test_vectors(("Signature", "ECDSA"), + "SigVer.rsp", + "ECDSA Signature Verification 186-3", + {'result': lambda x: x, + 'qx': lambda x: int(x, 16), + 'qy': lambda x: int(x, 16), + }) or [] +test_vectors_verify += load_test_vectors(("Signature", "ECDSA"), + "SigVer_TruncatedSHAs.rsp", + "ECDSA Signature Verification 186-3", + {'result': lambda x: x, + 'qx': lambda x: int(x, 16), + 'qy': lambda x: int(x, 16), + }) or [] + + +for idx, tv in enumerate(test_vectors_verify): + + if isinstance(tv, str): + res = re.match(r"\[(P-[0-9]+),(SHA-[0-9]+)\]", tv) + assert res + curve_name = res.group(1) + hash_name = res.group(2).replace("-", "") + if hash_name in ("SHA512224", "SHA512256"): + truncate = hash_name[-3:] + hash_name = hash_name[:-3] + else: + truncate = None + hash_module = load_hash_by_name(hash_name) + continue + + if truncate is None: + hash_obj = hash_module.new(tv.msg) + else: + hash_obj = hash_module.new(tv.msg, truncate=truncate) + ecc_key = ECC.construct(curve=curve_name, point_x=tv.qx, point_y=tv.qy) + verifier = DSS.new(ecc_key, 'fips-186-3') + + def positive_test(self, verifier=verifier, hash_obj=hash_obj, signature=tv.r+tv.s): + verifier.verify(hash_obj, signature) + + def negative_test(self, verifier=verifier, hash_obj=hash_obj, signature=tv.r+tv.s): + self.assertRaises(ValueError, verifier.verify, hash_obj, signature) + + if tv.result.startswith('p'): + setattr(FIPS_ECDSA_Tests_KAT, "test_verify_positive_%d" % idx, positive_test) + else: + setattr(FIPS_ECDSA_Tests_KAT, "test_verify_negative_%d" % idx, negative_test) + + +test_vectors_sign = load_test_vectors(("Signature", "ECDSA"), + "SigGen.txt", + "ECDSA Signature Verification 186-3", + {'d': lambda x: int(x, 16)}) or [] + +for idx, tv in enumerate(test_vectors_sign): + + if isinstance(tv, str): + res = re.match(r"\[(P-[0-9]+),(SHA-[0-9]+)\]", tv) + assert res + curve_name = res.group(1) + hash_name = res.group(2).replace("-", "") + hash_module = load_hash_by_name(hash_name) + continue + + hash_obj = hash_module.new(tv.msg) + ecc_key = ECC.construct(curve=curve_name, d=tv.d) + signer = DSS.new(ecc_key, 'fips-186-3', randfunc=StrRNG(tv.k)) + + def sign_test(self, signer=signer, hash_obj=hash_obj, signature=tv.r+tv.s): + self.assertEqual(signer.sign(hash_obj), signature) + setattr(FIPS_ECDSA_Tests_KAT, "test_sign_%d" % idx, sign_test) + + +class Det_DSA_Tests(unittest.TestCase): + """Tests from rfc6979""" + + # Each key is (p, q, g, x, y, desc) + keys = [ + ( + """ + 86F5CA03DCFEB225063FF830A0C769B9DD9D6153AD91D7CE27F787C43278B447 + E6533B86B18BED6E8A48B784A14C252C5BE0DBF60B86D6385BD2F12FB763ED88 + 73ABFD3F5BA2E0A8C0A59082EAC056935E529DAF7C610467899C77ADEDFC846C + 881870B7B19B2B58F9BE0521A17002E3BDD6B86685EE90B3D9A1B02B782B1779""", + "996F967F6C8E388D9E28D01E205FBA957A5698B1", + """ + 07B0F92546150B62514BB771E2A0C0CE387F03BDA6C56B505209FF25FD3C133D + 89BBCD97E904E09114D9A7DEFDEADFC9078EA544D2E401AEECC40BB9FBBF78FD + 87995A10A1C27CB7789B594BA7EFB5C4326A9FE59A070E136DB77175464ADCA4 + 17BE5DCE2F40D10A46A3A3943F26AB7FD9C0398FF8C76EE0A56826A8A88F1DBD""", + "411602CB19A6CCC34494D79D98EF1E7ED5AF25F7", + """ + 5DF5E01DED31D0297E274E1691C192FE5868FEF9E19A84776454B100CF16F653 + 92195A38B90523E2542EE61871C0440CB87C322FC4B4D2EC5E1E7EC766E1BE8D + 4CE935437DC11C3C8FD426338933EBFE739CB3465F4D3668C5E473508253B1E6 + 82F65CBDC4FAE93C2EA212390E54905A86E2223170B44EAA7DA5DD9FFCFB7F3B""", + "DSA1024" + ), + ( + """ + 9DB6FB5951B66BB6FE1E140F1D2CE5502374161FD6538DF1648218642F0B5C48 + C8F7A41AADFA187324B87674FA1822B00F1ECF8136943D7C55757264E5A1A44F + FE012E9936E00C1D3E9310B01C7D179805D3058B2A9F4BB6F9716BFE6117C6B5 + B3CC4D9BE341104AD4A80AD6C94E005F4B993E14F091EB51743BF33050C38DE2 + 35567E1B34C3D6A5C0CEAA1A0F368213C3D19843D0B4B09DCB9FC72D39C8DE41 + F1BF14D4BB4563CA28371621CAD3324B6A2D392145BEBFAC748805236F5CA2FE + 92B871CD8F9C36D3292B5509CA8CAA77A2ADFC7BFD77DDA6F71125A7456FEA15 + 3E433256A2261C6A06ED3693797E7995FAD5AABBCFBE3EDA2741E375404AE25B""", + "F2C3119374CE76C9356990B465374A17F23F9ED35089BD969F61C6DDE9998C1F", + """ + 5C7FF6B06F8F143FE8288433493E4769C4D988ACE5BE25A0E24809670716C613 + D7B0CEE6932F8FAA7C44D2CB24523DA53FBE4F6EC3595892D1AA58C4328A06C4 + 6A15662E7EAA703A1DECF8BBB2D05DBE2EB956C142A338661D10461C0D135472 + 085057F3494309FFA73C611F78B32ADBB5740C361C9F35BE90997DB2014E2EF5 + AA61782F52ABEB8BD6432C4DD097BC5423B285DAFB60DC364E8161F4A2A35ACA + 3A10B1C4D203CC76A470A33AFDCBDD92959859ABD8B56E1725252D78EAC66E71 + BA9AE3F1DD2487199874393CD4D832186800654760E1E34C09E4D155179F9EC0 + DC4473F996BDCE6EED1CABED8B6F116F7AD9CF505DF0F998E34AB27514B0FFE7""", + "69C7548C21D0DFEA6B9A51C9EAD4E27C33D3B3F180316E5BCAB92C933F0E4DBC", + """ + 667098C654426C78D7F8201EAC6C203EF030D43605032C2F1FA937E5237DBD94 + 9F34A0A2564FE126DC8B715C5141802CE0979C8246463C40E6B6BDAA2513FA61 + 1728716C2E4FD53BC95B89E69949D96512E873B9C8F8DFD499CC312882561ADE + CB31F658E934C0C197F2C4D96B05CBAD67381E7B768891E4DA3843D24D94CDFB + 5126E9B8BF21E8358EE0E0A30EF13FD6A664C0DCE3731F7FB49A4845A4FD8254 + 687972A2D382599C9BAC4E0ED7998193078913032558134976410B89D2C171D1 + 23AC35FD977219597AA7D15C1A9A428E59194F75C721EBCBCFAE44696A499AFA + 74E04299F132026601638CB87AB79190D4A0986315DA8EEC6561C938996BEADF""", + "DSA2048" + ), + ] + + # This is a sequence of items: + # message, k, r, s, hash module + signatures = [ + ( + "sample", + "7BDB6B0FF756E1BB5D53583EF979082F9AD5BD5B", + "2E1A0C2562B2912CAAF89186FB0F42001585DA55", + "29EFB6B0AFF2D7A68EB70CA313022253B9A88DF5", + SHA1, + 'DSA1024' + ), + ( + "sample", + "562097C06782D60C3037BA7BE104774344687649", + "4BC3B686AEA70145856814A6F1BB53346F02101E", + "410697B92295D994D21EDD2F4ADA85566F6F94C1", + SHA224, + 'DSA1024' + ), + ( + "sample", + "519BA0546D0C39202A7D34D7DFA5E760B318BCFB", + "81F2F5850BE5BC123C43F71A3033E9384611C545", + "4CDD914B65EB6C66A8AAAD27299BEE6B035F5E89", + SHA256, + 'DSA1024' + ), + ( + "sample", + "95897CD7BBB944AA932DBC579C1C09EB6FCFC595", + "07F2108557EE0E3921BC1774F1CA9B410B4CE65A", + "54DF70456C86FAC10FAB47C1949AB83F2C6F7595", + SHA384, + 'DSA1024' + ), + ( + "sample", + "09ECE7CA27D0F5A4DD4E556C9DF1D21D28104F8B", + "16C3491F9B8C3FBBDD5E7A7B667057F0D8EE8E1B", + "02C36A127A7B89EDBB72E4FFBC71DABC7D4FC69C", + SHA512, + 'DSA1024' + ), + ( + "test", + "5C842DF4F9E344EE09F056838B42C7A17F4A6433", + "42AB2052FD43E123F0607F115052A67DCD9C5C77", + "183916B0230D45B9931491D4C6B0BD2FB4AAF088", + SHA1, + 'DSA1024' + ), + ( + "test", + "4598B8EFC1A53BC8AECD58D1ABBB0C0C71E67297", + "6868E9964E36C1689F6037F91F28D5F2C30610F2", + "49CEC3ACDC83018C5BD2674ECAAD35B8CD22940F", + SHA224, + 'DSA1024' + ), + ( + "test", + "5A67592E8128E03A417B0484410FB72C0B630E1A", + "22518C127299B0F6FDC9872B282B9E70D0790812", + "6837EC18F150D55DE95B5E29BE7AF5D01E4FE160", + SHA256, + 'DSA1024' + ), + ( + "test", + "220156B761F6CA5E6C9F1B9CF9C24BE25F98CD89", + "854CF929B58D73C3CBFDC421E8D5430CD6DB5E66", + "91D0E0F53E22F898D158380676A871A157CDA622", + SHA384, + 'DSA1024' + ), + ( + "test", + "65D2C2EEB175E370F28C75BFCDC028D22C7DBE9C", + "8EA47E475BA8AC6F2D821DA3BD212D11A3DEB9A0", + "7C670C7AD72B6C050C109E1790008097125433E8", + SHA512, + 'DSA1024' + ), + ( + "sample", + "888FA6F7738A41BDC9846466ABDB8174C0338250AE50CE955CA16230F9CBD53E", + "3A1B2DBD7489D6ED7E608FD036C83AF396E290DBD602408E8677DAABD6E7445A", + "D26FCBA19FA3E3058FFC02CA1596CDBB6E0D20CB37B06054F7E36DED0CDBBCCF", + SHA1, + 'DSA2048' + ), + ( + "sample", + "BC372967702082E1AA4FCE892209F71AE4AD25A6DFD869334E6F153BD0C4D806", + "DC9F4DEADA8D8FF588E98FED0AB690FFCE858DC8C79376450EB6B76C24537E2C", + "A65A9C3BC7BABE286B195D5DA68616DA8D47FA0097F36DD19F517327DC848CEC", + SHA224, + 'DSA2048' + ), + ( + "sample", + "8926A27C40484216F052F4427CFD5647338B7B3939BC6573AF4333569D597C52", + "EACE8BDBBE353C432A795D9EC556C6D021F7A03F42C36E9BC87E4AC7932CC809", + "7081E175455F9247B812B74583E9E94F9EA79BD640DC962533B0680793A38D53", + SHA256, + 'DSA2048' + ), + ( + "sample", + "C345D5AB3DA0A5BCB7EC8F8FB7A7E96069E03B206371EF7D83E39068EC564920", + "B2DA945E91858834FD9BF616EBAC151EDBC4B45D27D0DD4A7F6A22739F45C00B", + "19048B63D9FD6BCA1D9BAE3664E1BCB97F7276C306130969F63F38FA8319021B", + SHA384, + 'DSA2048' + ), + ( + "sample", + "5A12994431785485B3F5F067221517791B85A597B7A9436995C89ED0374668FC", + "2016ED092DC5FB669B8EFB3D1F31A91EECB199879BE0CF78F02BA062CB4C942E", + "D0C76F84B5F091E141572A639A4FB8C230807EEA7D55C8A154A224400AFF2351", + SHA512, + 'DSA2048' + ), + ( + "test", + "6EEA486F9D41A037B2C640BC5645694FF8FF4B98D066A25F76BE641CCB24BA4F", + "C18270A93CFC6063F57A4DFA86024F700D980E4CF4E2CB65A504397273D98EA0", + "414F22E5F31A8B6D33295C7539C1C1BA3A6160D7D68D50AC0D3A5BEAC2884FAA", + SHA1, + 'DSA2048' + ), + ( + "test", + "06BD4C05ED74719106223BE33F2D95DA6B3B541DAD7BFBD7AC508213B6DA6670", + "272ABA31572F6CC55E30BF616B7A265312018DD325BE031BE0CC82AA17870EA3", + "E9CC286A52CCE201586722D36D1E917EB96A4EBDB47932F9576AC645B3A60806", + SHA224, + 'DSA2048' + ), + ( + "test", + "1D6CE6DDA1C5D37307839CD03AB0A5CBB18E60D800937D67DFB4479AAC8DEAD7", + "8190012A1969F9957D56FCCAAD223186F423398D58EF5B3CEFD5A4146A4476F0", + "7452A53F7075D417B4B013B278D1BB8BBD21863F5E7B1CEE679CF2188E1AB19E", + SHA256, + 'DSA2048' + ), + ( + "test", + "206E61F73DBE1B2DC8BE736B22B079E9DACD974DB00EEBBC5B64CAD39CF9F91C", + "239E66DDBE8F8C230A3D071D601B6FFBDFB5901F94D444C6AF56F732BEB954BE", + "6BD737513D5E72FE85D1C750E0F73921FE299B945AAD1C802F15C26A43D34961", + SHA384, + 'DSA2048' + ), + ( + "test", + "AFF1651E4CD6036D57AA8B2A05CCF1A9D5A40166340ECBBDC55BE10B568AA0AA", + "89EC4BB1400ECCFF8E7D9AA515CD1DE7803F2DAFF09693EE7FD1353E90A68307", + "C9F0BDABCC0D880BB137A994CC7F3980CE91CC10FAF529FC46565B15CEA854E1", + SHA512, + 'DSA2048' + ) + ] + + def setUp(self): + # Convert DSA key components from hex strings to integers + # Each key is (p, q, g, x, y, desc) + + from collections import namedtuple + + TestKey = namedtuple('TestKey', 'p q g x y') + new_keys = {} + for k in self.keys: + tk = TestKey(*[t2l(y) for y in k[:-1]]) + new_keys[k[-1]] = tk + self.keys = new_keys + + # Convert signature encoding + TestSig = namedtuple('TestSig', 'message nonce result module test_key') + new_signatures = [] + for message, nonce, r, s, module, test_key in self.signatures: + tsig = TestSig( + tobytes(message), + t2l(nonce), + t2b(r) + t2b(s), + module, + self.keys[test_key] + ) + new_signatures.append(tsig) + self.signatures = new_signatures + + def test1(self): + q = 0x4000000000000000000020108A2E0CC0D99F8A5EF + x = 0x09A4D6792295A7F730FC3F2B49CBC0F62E862272F + p = 2 * q + 1 + y = pow(2, x, p) + key = DSA.construct([pow(y, 2, p), 2, p, q, x], False) + signer = DSS.new(key, 'deterministic-rfc6979') + + # Test _int2octets + self.assertEqual(hexlify(signer._int2octets(x)), + b'009a4d6792295a7f730fc3f2b49cbc0f62e862272f') + + # Test _bits2octets + h1 = SHA256.new(b"sample").digest() + self.assertEqual(hexlify(signer._bits2octets(h1)), + b'01795edf0d54db760f156d0dac04c0322b3a204224') + + def test2(self): + + for sig in self.signatures: + tk = sig.test_key + key = DSA.construct([tk.y, tk.g, tk.p, tk.q, tk.x], False) + signer = DSS.new(key, 'deterministic-rfc6979') + + hash_obj = sig.module.new(sig.message) + result = signer.sign(hash_obj) + self.assertEqual(sig.result, result) + + +class Det_ECDSA_Tests(unittest.TestCase): + + key_priv_p192 = ECC.construct(curve="P-192", d=0x6FAB034934E4C0FC9AE67F5B5659A9D7D1FEFD187EE09FD4) + key_pub_p192 = key_priv_p192.public_key() + + key_priv_p224 = ECC.construct(curve="P-224", d=0xF220266E1105BFE3083E03EC7A3A654651F45E37167E88600BF257C1) + key_pub_p224 = key_priv_p224.public_key() + + key_priv_p256 = ECC.construct(curve="P-256", d=0xC9AFA9D845BA75166B5C215767B1D6934E50C3DB36E89B127B8A622B120F6721) + key_pub_p256 = key_priv_p256.public_key() + + key_priv_p384 = ECC.construct(curve="P-384", d=0x6B9D3DAD2E1B8C1C05B19875B6659F4DE23C3B667BF297BA9AA47740787137D896D5724E4C70A825F872C9EA60D2EDF5) + key_pub_p384 = key_priv_p384.public_key() + + key_priv_p521 = ECC.construct(curve="P-521", d=0x0FAD06DAA62BA3B25D2FB40133DA757205DE67F5BB0018FEE8C86E1B68C7E75CAA896EB32F1F47C70855836A6D16FCC1466F6D8FBEC67DB89EC0C08B0E996B83538) + key_pub_p521 = key_priv_p521.public_key() + + # This is a sequence of items: + # message, k, r, s, hash module + # taken from RFC6979 + signatures_p192_ = ( + ( + "sample", + "37D7CA00D2C7B0E5E412AC03BD44BA837FDD5B28CD3B0021", + "98C6BD12B23EAF5E2A2045132086BE3EB8EBD62ABF6698FF", + "57A22B07DEA9530F8DE9471B1DC6624472E8E2844BC25B64", + SHA1 + ), + ( + "sample", + "4381526B3FC1E7128F202E194505592F01D5FF4C5AF015D8", + "A1F00DAD97AEEC91C95585F36200C65F3C01812AA60378F5", + "E07EC1304C7C6C9DEBBE980B9692668F81D4DE7922A0F97A", + SHA224 + ), + ( + "sample", + "32B1B6D7D42A05CB449065727A84804FB1A3E34D8F261496", + "4B0B8CE98A92866A2820E20AA6B75B56382E0F9BFD5ECB55", + "CCDB006926EA9565CBADC840829D8C384E06DE1F1E381B85", + SHA256 + ), + ( + "sample", + "4730005C4FCB01834C063A7B6760096DBE284B8252EF4311", + "DA63BF0B9ABCF948FBB1E9167F136145F7A20426DCC287D5", + "C3AA2C960972BD7A2003A57E1C4C77F0578F8AE95E31EC5E", + SHA384 + ), + ( + "sample", + "A2AC7AB055E4F20692D49209544C203A7D1F2C0BFBC75DB1", + "4D60C5AB1996BD848343B31C00850205E2EA6922DAC2E4B8", + "3F6E837448F027A1BF4B34E796E32A811CBB4050908D8F67", + SHA512 + ), + ( + "test", + "D9CF9C3D3297D3260773A1DA7418DB5537AB8DD93DE7FA25", + "0F2141A0EBBC44D2E1AF90A50EBCFCE5E197B3B7D4DE036D", + "EB18BC9E1F3D7387500CB99CF5F7C157070A8961E38700B7", + SHA1 + ), + ( + "test", + "F5DC805F76EF851800700CCE82E7B98D8911B7D510059FBE", + "6945A1C1D1B2206B8145548F633BB61CEF04891BAF26ED34", + "B7FB7FDFC339C0B9BD61A9F5A8EAF9BE58FC5CBA2CB15293", + SHA224 + ), + ( + "test", + "5C4CE89CF56D9E7C77C8585339B006B97B5F0680B4306C6C", + "3A718BD8B4926C3B52EE6BBE67EF79B18CB6EB62B1AD97AE", + "5662E6848A4A19B1F1AE2F72ACD4B8BBE50F1EAC65D9124F", + SHA256 + ), + ( + "test", + "5AFEFB5D3393261B828DB6C91FBC68C230727B030C975693", + "B234B60B4DB75A733E19280A7A6034BD6B1EE88AF5332367", + "7994090B2D59BB782BE57E74A44C9A1C700413F8ABEFE77A", + SHA384 + ), + ( + "test", + "0758753A5254759C7CFBAD2E2D9B0792EEE44136C9480527", + "FE4F4AE86A58B6507946715934FE2D8FF9D95B6B098FE739", + "74CF5605C98FBA0E1EF34D4B5A1577A7DCF59457CAE52290", + SHA512 + ) + ) + + signatures_p224_ = ( + ( + "sample", + "7EEFADD91110D8DE6C2C470831387C50D3357F7F4D477054B8B426BC", + "22226F9D40A96E19C4A301CE5B74B115303C0F3A4FD30FC257FB57AC", + "66D1CDD83E3AF75605DD6E2FEFF196D30AA7ED7A2EDF7AF475403D69", + SHA1 + ), + ( + "sample", + "C1D1F2F10881088301880506805FEB4825FE09ACB6816C36991AA06D", + "1CDFE6662DDE1E4A1EC4CDEDF6A1F5A2FB7FBD9145C12113E6ABFD3E", + "A6694FD7718A21053F225D3F46197CA699D45006C06F871808F43EBC", + SHA224 + ), + ( + "sample", + "AD3029E0278F80643DE33917CE6908C70A8FF50A411F06E41DEDFCDC", + "61AA3DA010E8E8406C656BC477A7A7189895E7E840CDFE8FF42307BA", + "BC814050DAB5D23770879494F9E0A680DC1AF7161991BDE692B10101", + SHA256 + ), + ( + "sample", + "52B40F5A9D3D13040F494E83D3906C6079F29981035C7BD51E5CAC40", + "0B115E5E36F0F9EC81F1325A5952878D745E19D7BB3EABFABA77E953", + "830F34CCDFE826CCFDC81EB4129772E20E122348A2BBD889A1B1AF1D", + SHA384 + ), + ( + "sample", + "9DB103FFEDEDF9CFDBA05184F925400C1653B8501BAB89CEA0FBEC14", + "074BD1D979D5F32BF958DDC61E4FB4872ADCAFEB2256497CDAC30397", + "A4CECA196C3D5A1FF31027B33185DC8EE43F288B21AB342E5D8EB084", + SHA512 + ), + ( + "test", + "2519178F82C3F0E4F87ED5883A4E114E5B7A6E374043D8EFD329C253", + "DEAA646EC2AF2EA8AD53ED66B2E2DDAA49A12EFD8356561451F3E21C", + "95987796F6CF2062AB8135271DE56AE55366C045F6D9593F53787BD2", + SHA1 + ), + ( + "test", + "DF8B38D40DCA3E077D0AC520BF56B6D565134D9B5F2EAE0D34900524", + "C441CE8E261DED634E4CF84910E4C5D1D22C5CF3B732BB204DBEF019", + "902F42847A63BDC5F6046ADA114953120F99442D76510150F372A3F4", + SHA224 + ), + ( + "test", + "FF86F57924DA248D6E44E8154EB69F0AE2AEBAEE9931D0B5A969F904", + "AD04DDE87B84747A243A631EA47A1BA6D1FAA059149AD2440DE6FBA6", + "178D49B1AE90E3D8B629BE3DB5683915F4E8C99FDF6E666CF37ADCFD", + SHA256 + ), + ( + "test", + "7046742B839478C1B5BD31DB2E862AD868E1A45C863585B5F22BDC2D", + "389B92682E399B26518A95506B52C03BC9379A9DADF3391A21FB0EA4", + "414A718ED3249FF6DBC5B50C27F71F01F070944DA22AB1F78F559AAB", + SHA384 + ), + ( + "test", + "E39C2AA4EA6BE2306C72126D40ED77BF9739BB4D6EF2BBB1DCB6169D", + "049F050477C5ADD858CAC56208394B5A55BAEBBE887FDF765047C17C", + "077EB13E7005929CEFA3CD0403C7CDCC077ADF4E44F3C41B2F60ECFF", + SHA512 + ) + ) + + signatures_p256_ = ( + ( + "sample", + "882905F1227FD620FBF2ABF21244F0BA83D0DC3A9103DBBEE43A1FB858109DB4", + "61340C88C3AAEBEB4F6D667F672CA9759A6CCAA9FA8811313039EE4A35471D32", + "6D7F147DAC089441BB2E2FE8F7A3FA264B9C475098FDCF6E00D7C996E1B8B7EB", + SHA1 + ), + ( + "sample", + "103F90EE9DC52E5E7FB5132B7033C63066D194321491862059967C715985D473", + "53B2FFF5D1752B2C689DF257C04C40A587FABABB3F6FC2702F1343AF7CA9AA3F", + "B9AFB64FDC03DC1A131C7D2386D11E349F070AA432A4ACC918BEA988BF75C74C", + SHA224 + ), + ( + "sample", + "A6E3C57DD01ABE90086538398355DD4C3B17AA873382B0F24D6129493D8AAD60", + "EFD48B2AACB6A8FD1140DD9CD45E81D69D2C877B56AAF991C34D0EA84EAF3716", + "F7CB1C942D657C41D436C7A1B6E29F65F3E900DBB9AFF4064DC4AB2F843ACDA8", + SHA256 + ), + ( + "sample", + "09F634B188CEFD98E7EC88B1AA9852D734D0BC272F7D2A47DECC6EBEB375AAD4", + "0EAFEA039B20E9B42309FB1D89E213057CBF973DC0CFC8F129EDDDC800EF7719", + "4861F0491E6998B9455193E34E7B0D284DDD7149A74B95B9261F13ABDE940954", + SHA384 + ), + ( + "sample", + "5FA81C63109BADB88C1F367B47DA606DA28CAD69AA22C4FE6AD7DF73A7173AA5", + "8496A60B5E9B47C825488827E0495B0E3FA109EC4568FD3F8D1097678EB97F00", + "2362AB1ADBE2B8ADF9CB9EDAB740EA6049C028114F2460F96554F61FAE3302FE", + SHA512 + ), + ( + "test", + "8C9520267C55D6B980DF741E56B4ADEE114D84FBFA2E62137954164028632A2E", + "0CBCC86FD6ABD1D99E703E1EC50069EE5C0B4BA4B9AC60E409E8EC5910D81A89", + "01B9D7B73DFAA60D5651EC4591A0136F87653E0FD780C3B1BC872FFDEAE479B1", + SHA1 + ), + ( + "test", + "669F4426F2688B8BE0DB3A6BD1989BDAEFFF84B649EEB84F3DD26080F667FAA7", + "C37EDB6F0AE79D47C3C27E962FA269BB4F441770357E114EE511F662EC34A692", + "C820053A05791E521FCAAD6042D40AEA1D6B1A540138558F47D0719800E18F2D", + SHA224 + ), + ( + "test", + "D16B6AE827F17175E040871A1C7EC3500192C4C92677336EC2537ACAEE0008E0", + "F1ABB023518351CD71D881567B1EA663ED3EFCF6C5132B354F28D3B0B7D38367", + "019F4113742A2B14BD25926B49C649155F267E60D3814B4C0CC84250E46F0083", + SHA256 + ), + ( + "test", + "16AEFFA357260B04B1DD199693960740066C1A8F3E8EDD79070AA914D361B3B8", + "83910E8B48BB0C74244EBDF7F07A1C5413D61472BD941EF3920E623FBCCEBEB6", + "8DDBEC54CF8CD5874883841D712142A56A8D0F218F5003CB0296B6B509619F2C", + SHA384 + ), + ( + "test", + "6915D11632ACA3C40D5D51C08DAF9C555933819548784480E93499000D9F0B7F", + "461D93F31B6540894788FD206C07CFA0CC35F46FA3C91816FFF1040AD1581A04", + "39AF9F15DE0DB8D97E72719C74820D304CE5226E32DEDAE67519E840D1194E55", + SHA512 + ) + ) + + signatures_p384_ = ( + ( + "sample", + "4471EF7518BB2C7C20F62EAE1C387AD0C5E8E470995DB4ACF694466E6AB096630F29E5938D25106C3C340045A2DB01A7", + "EC748D839243D6FBEF4FC5C4859A7DFFD7F3ABDDF72014540C16D73309834FA37B9BA002899F6FDA3A4A9386790D4EB2", + "A3BCFA947BEEF4732BF247AC17F71676CB31A847B9FF0CBC9C9ED4C1A5B3FACF26F49CA031D4857570CCB5CA4424A443", + SHA1 + ), + ( + "sample", + "A4E4D2F0E729EB786B31FC20AD5D849E304450E0AE8E3E341134A5C1AFA03CAB8083EE4E3C45B06A5899EA56C51B5879", + "42356E76B55A6D9B4631C865445DBE54E056D3B3431766D0509244793C3F9366450F76EE3DE43F5A125333A6BE060122", + "9DA0C81787064021E78DF658F2FBB0B042BF304665DB721F077A4298B095E4834C082C03D83028EFBF93A3C23940CA8D", + SHA224 + ), + ( + "sample", + "180AE9F9AEC5438A44BC159A1FCB277C7BE54FA20E7CF404B490650A8ACC414E375572342863C899F9F2EDF9747A9B60", + "21B13D1E013C7FA1392D03C5F99AF8B30C570C6F98D4EA8E354B63A21D3DAA33BDE1E888E63355D92FA2B3C36D8FB2CD", + "F3AA443FB107745BF4BD77CB3891674632068A10CA67E3D45DB2266FA7D1FEEBEFDC63ECCD1AC42EC0CB8668A4FA0AB0", + SHA256 + ), + ( + "sample", + "94ED910D1A099DAD3254E9242AE85ABDE4BA15168EAF0CA87A555FD56D10FBCA2907E3E83BA95368623B8C4686915CF9", + "94EDBB92A5ECB8AAD4736E56C691916B3F88140666CE9FA73D64C4EA95AD133C81A648152E44ACF96E36DD1E80FABE46", + "99EF4AEB15F178CEA1FE40DB2603138F130E740A19624526203B6351D0A3A94FA329C145786E679E7B82C71A38628AC8", + SHA384 + ), + ( + "sample", + "92FC3C7183A883E24216D1141F1A8976C5B0DD797DFA597E3D7B32198BD35331A4E966532593A52980D0E3AAA5E10EC3", + "ED0959D5880AB2D869AE7F6C2915C6D60F96507F9CB3E047C0046861DA4A799CFE30F35CC900056D7C99CD7882433709", + "512C8CCEEE3890A84058CE1E22DBC2198F42323CE8ACA9135329F03C068E5112DC7CC3EF3446DEFCEB01A45C2667FDD5", + SHA512 + ), + ( + "test", + "66CC2C8F4D303FC962E5FF6A27BD79F84EC812DDAE58CF5243B64A4AD8094D47EC3727F3A3C186C15054492E30698497", + "4BC35D3A50EF4E30576F58CD96CE6BF638025EE624004A1F7789A8B8E43D0678ACD9D29876DAF46638645F7F404B11C7", + "D5A6326C494ED3FF614703878961C0FDE7B2C278F9A65FD8C4B7186201A2991695BA1C84541327E966FA7B50F7382282", + SHA1 + ), + ( + "test", + "18FA39DB95AA5F561F30FA3591DC59C0FA3653A80DAFFA0B48D1A4C6DFCBFF6E3D33BE4DC5EB8886A8ECD093F2935726", + "E8C9D0B6EA72A0E7837FEA1D14A1A9557F29FAA45D3E7EE888FC5BF954B5E62464A9A817C47FF78B8C11066B24080E72", + "07041D4A7A0379AC7232FF72E6F77B6DDB8F09B16CCE0EC3286B2BD43FA8C6141C53EA5ABEF0D8231077A04540A96B66", + SHA224 + ), + ( + "test", + "0CFAC37587532347DC3389FDC98286BBA8C73807285B184C83E62E26C401C0FAA48DD070BA79921A3457ABFF2D630AD7", + "6D6DEFAC9AB64DABAFE36C6BF510352A4CC27001263638E5B16D9BB51D451559F918EEDAF2293BE5B475CC8F0188636B", + "2D46F3BECBCC523D5F1A1256BF0C9B024D879BA9E838144C8BA6BAEB4B53B47D51AB373F9845C0514EEFB14024787265", + SHA256 + ), + ( + "test", + "015EE46A5BF88773ED9123A5AB0807962D193719503C527B031B4C2D225092ADA71F4A459BC0DA98ADB95837DB8312EA", + "8203B63D3C853E8D77227FB377BCF7B7B772E97892A80F36AB775D509D7A5FEB0542A7F0812998DA8F1DD3CA3CF023DB", + "DDD0760448D42D8A43AF45AF836FCE4DE8BE06B485E9B61B827C2F13173923E06A739F040649A667BF3B828246BAA5A5", + SHA384 + ), + ( + "test", + "3780C4F67CB15518B6ACAE34C9F83568D2E12E47DEAB6C50A4E4EE5319D1E8CE0E2CC8A136036DC4B9C00E6888F66B6C", + "A0D5D090C9980FAF3C2CE57B7AE951D31977DD11C775D314AF55F76C676447D06FB6495CD21B4B6E340FC236584FB277", + "976984E59B4C77B0E8E4460DCA3D9F20E07B9BB1F63BEEFAF576F6B2E8B224634A2092CD3792E0159AD9CEE37659C736", + SHA512 + ), + ) + + signatures_p521_ = ( + ( + "sample", + "0089C071B419E1C2820962321787258469511958E80582E95D8378E0C2CCDB3CB42BEDE42F50E3FA3C71F5A76724281D31D9C89F0F91FC1BE4918DB1C03A5838D0F9", + "00343B6EC45728975EA5CBA6659BBB6062A5FF89EEA58BE3C80B619F322C87910FE092F7D45BB0F8EEE01ED3F20BABEC079D202AE677B243AB40B5431D497C55D75D", + "00E7B0E675A9B24413D448B8CC119D2BF7B2D2DF032741C096634D6D65D0DBE3D5694625FB9E8104D3B842C1B0E2D0B98BEA19341E8676AEF66AE4EBA3D5475D5D16", + SHA1 + ), + ( + "sample", + "0121415EC2CD7726330A61F7F3FA5DE14BE9436019C4DB8CB4041F3B54CF31BE0493EE3F427FB906393D895A19C9523F3A1D54BB8702BD4AA9C99DAB2597B92113F3", + "01776331CFCDF927D666E032E00CF776187BC9FDD8E69D0DABB4109FFE1B5E2A30715F4CC923A4A5E94D2503E9ACFED92857B7F31D7152E0F8C00C15FF3D87E2ED2E", + "0050CB5265417FE2320BBB5A122B8E1A32BD699089851128E360E620A30C7E17BA41A666AF126CE100E5799B153B60528D5300D08489CA9178FB610A2006C254B41F", + SHA224 + ), + ( + "sample", + "00EDF38AFCAAECAB4383358B34D67C9F2216C8382AAEA44A3DAD5FDC9C32575761793FEF24EB0FC276DFC4F6E3EC476752F043CF01415387470BCBD8678ED2C7E1A0", + "01511BB4D675114FE266FC4372B87682BAECC01D3CC62CF2303C92B3526012659D16876E25C7C1E57648F23B73564D67F61C6F14D527D54972810421E7D87589E1A7", + "004A171143A83163D6DF460AAF61522695F207A58B95C0644D87E52AA1A347916E4F7A72930B1BC06DBE22CE3F58264AFD23704CBB63B29B931F7DE6C9D949A7ECFC", + SHA256 + ), + ( + "sample", + "01546A108BC23A15D6F21872F7DED661FA8431DDBD922D0DCDB77CC878C8553FFAD064C95A920A750AC9137E527390D2D92F153E66196966EA554D9ADFCB109C4211", + "01EA842A0E17D2DE4F92C15315C63DDF72685C18195C2BB95E572B9C5136CA4B4B576AD712A52BE9730627D16054BA40CC0B8D3FF035B12AE75168397F5D50C67451", + "01F21A3CEE066E1961025FB048BD5FE2B7924D0CD797BABE0A83B66F1E35EEAF5FDE143FA85DC394A7DEE766523393784484BDF3E00114A1C857CDE1AA203DB65D61", + SHA384 + ), + ( + "sample", + "01DAE2EA071F8110DC26882D4D5EAE0621A3256FC8847FB9022E2B7D28E6F10198B1574FDD03A9053C08A1854A168AA5A57470EC97DD5CE090124EF52A2F7ECBFFD3", + "00C328FAFCBD79DD77850370C46325D987CB525569FB63C5D3BC53950E6D4C5F174E25A1EE9017B5D450606ADD152B534931D7D4E8455CC91F9B15BF05EC36E377FA", + "00617CCE7CF5064806C467F678D3B4080D6F1CC50AF26CA209417308281B68AF282623EAA63E5B5C0723D8B8C37FF0777B1A20F8CCB1DCCC43997F1EE0E44DA4A67A", + SHA512 + ), + ( + "test", + "00BB9F2BF4FE1038CCF4DABD7139A56F6FD8BB1386561BD3C6A4FC818B20DF5DDBA80795A947107A1AB9D12DAA615B1ADE4F7A9DC05E8E6311150F47F5C57CE8B222", + "013BAD9F29ABE20DE37EBEB823C252CA0F63361284015A3BF430A46AAA80B87B0693F0694BD88AFE4E661FC33B094CD3B7963BED5A727ED8BD6A3A202ABE009D0367", + "01E9BB81FF7944CA409AD138DBBEE228E1AFCC0C890FC78EC8604639CB0DBDC90F717A99EAD9D272855D00162EE9527567DD6A92CBD629805C0445282BBC916797FF", + SHA1 + ), + ( + "test", + "0040D09FCF3C8A5F62CF4FB223CBBB2B9937F6B0577C27020A99602C25A01136987E452988781484EDBBCF1C47E554E7FC901BC3085E5206D9F619CFF07E73D6F706", + "01C7ED902E123E6815546065A2C4AF977B22AA8EADDB68B2C1110E7EA44D42086BFE4A34B67DDC0E17E96536E358219B23A706C6A6E16BA77B65E1C595D43CAE17FB", + "0177336676304FCB343CE028B38E7B4FBA76C1C1B277DA18CAD2A8478B2A9A9F5BEC0F3BA04F35DB3E4263569EC6AADE8C92746E4C82F8299AE1B8F1739F8FD519A4", + SHA224 + ), + ( + "test", + "001DE74955EFAABC4C4F17F8E84D881D1310B5392D7700275F82F145C61E843841AF09035BF7A6210F5A431A6A9E81C9323354A9E69135D44EBD2FCAA7731B909258", + "000E871C4A14F993C6C7369501900C4BC1E9C7B0B4BA44E04868B30B41D8071042EB28C4C250411D0CE08CD197E4188EA4876F279F90B3D8D74A3C76E6F1E4656AA8", + "00CD52DBAA33B063C3A6CD8058A1FB0A46A4754B034FCC644766CA14DA8CA5CA9FDE00E88C1AD60CCBA759025299079D7A427EC3CC5B619BFBC828E7769BCD694E86", + SHA256 + ), + ( + "test", + "01F1FC4A349A7DA9A9E116BFDD055DC08E78252FF8E23AC276AC88B1770AE0B5DCEB1ED14A4916B769A523CE1E90BA22846AF11DF8B300C38818F713DADD85DE0C88", + "014BEE21A18B6D8B3C93FAB08D43E739707953244FDBE924FA926D76669E7AC8C89DF62ED8975C2D8397A65A49DCC09F6B0AC62272741924D479354D74FF6075578C", + "0133330865C067A0EAF72362A65E2D7BC4E461E8C8995C3B6226A21BD1AA78F0ED94FE536A0DCA35534F0CD1510C41525D163FE9D74D134881E35141ED5E8E95B979", + SHA384 + ), + ( + "test", + "016200813020EC986863BEDFC1B121F605C1215645018AEA1A7B215A564DE9EB1B38A67AA1128B80CE391C4FB71187654AAA3431027BFC7F395766CA988C964DC56D", + "013E99020ABF5CEE7525D16B69B229652AB6BDF2AFFCAEF38773B4B7D08725F10CDB93482FDCC54EDCEE91ECA4166B2A7C6265EF0CE2BD7051B7CEF945BABD47EE6D", + "01FBD0013C674AA79CB39849527916CE301C66EA7CE8B80682786AD60F98F7E78A19CA69EFF5C57400E3B3A0AD66CE0978214D13BAF4E9AC60752F7B155E2DE4DCE3", + SHA512 + ), + ) + + signatures_p192 = [] + for a, b, c, d, e in signatures_p192_: + new_tv = (tobytes(a), unhexlify(b), unhexlify(c), unhexlify(d), e) + signatures_p192.append(new_tv) + + signatures_p224 = [] + for a, b, c, d, e in signatures_p224_: + new_tv = (tobytes(a), unhexlify(b), unhexlify(c), unhexlify(d), e) + signatures_p224.append(new_tv) + + signatures_p256 = [] + for a, b, c, d, e in signatures_p256_: + new_tv = (tobytes(a), unhexlify(b), unhexlify(c), unhexlify(d), e) + signatures_p256.append(new_tv) + + signatures_p384 = [] + for a, b, c, d, e in signatures_p384_: + new_tv = (tobytes(a), unhexlify(b), unhexlify(c), unhexlify(d), e) + signatures_p384.append(new_tv) + + signatures_p521 = [] + for a, b, c, d, e in signatures_p521_: + new_tv = (tobytes(a), unhexlify(b), unhexlify(c), unhexlify(d), e) + signatures_p521.append(new_tv) + + def shortDescription(self): + return "Deterministic ECDSA Tests" + + def test_loopback_p192(self): + hashed_msg = SHA512.new(b"test") + signer = DSS.new(self.key_priv_p192, 'deterministic-rfc6979') + signature = signer.sign(hashed_msg) + + verifier = DSS.new(self.key_pub_p192, 'deterministic-rfc6979') + verifier.verify(hashed_msg, signature) + + def test_loopback_p224(self): + hashed_msg = SHA512.new(b"test") + signer = DSS.new(self.key_priv_p224, 'deterministic-rfc6979') + signature = signer.sign(hashed_msg) + + verifier = DSS.new(self.key_pub_p224, 'deterministic-rfc6979') + verifier.verify(hashed_msg, signature) + + def test_loopback_p256(self): + hashed_msg = SHA512.new(b"test") + signer = DSS.new(self.key_priv_p256, 'deterministic-rfc6979') + signature = signer.sign(hashed_msg) + + verifier = DSS.new(self.key_pub_p256, 'deterministic-rfc6979') + verifier.verify(hashed_msg, signature) + + def test_loopback_p384(self): + hashed_msg = SHA512.new(b"test") + signer = DSS.new(self.key_priv_p384, 'deterministic-rfc6979') + signature = signer.sign(hashed_msg) + + verifier = DSS.new(self.key_pub_p384, 'deterministic-rfc6979') + verifier.verify(hashed_msg, signature) + + def test_loopback_p521(self): + hashed_msg = SHA512.new(b"test") + signer = DSS.new(self.key_priv_p521, 'deterministic-rfc6979') + signature = signer.sign(hashed_msg) + + verifier = DSS.new(self.key_pub_p521, 'deterministic-rfc6979') + verifier.verify(hashed_msg, signature) + + def test_data_rfc6979_p192(self): + signer = DSS.new(self.key_priv_p192, 'deterministic-rfc6979') + for message, k, r, s, module in self.signatures_p192: + hash_obj = module.new(message) + result = signer.sign(hash_obj) + self.assertEqual(r + s, result) + + def test_data_rfc6979_p224(self): + signer = DSS.new(self.key_priv_p224, 'deterministic-rfc6979') + for message, k, r, s, module in self.signatures_p224: + hash_obj = module.new(message) + result = signer.sign(hash_obj) + self.assertEqual(r + s, result) + + def test_data_rfc6979_p256(self): + signer = DSS.new(self.key_priv_p256, 'deterministic-rfc6979') + for message, k, r, s, module in self.signatures_p256: + hash_obj = module.new(message) + result = signer.sign(hash_obj) + self.assertEqual(r + s, result) + + def test_data_rfc6979_p384(self): + signer = DSS.new(self.key_priv_p384, 'deterministic-rfc6979') + for message, k, r, s, module in self.signatures_p384: + hash_obj = module.new(message) + result = signer.sign(hash_obj) + self.assertEqual(r + s, result) + + def test_data_rfc6979_p521(self): + signer = DSS.new(self.key_priv_p521, 'deterministic-rfc6979') + for message, k, r, s, module in self.signatures_p521: + hash_obj = module.new(message) + result = signer.sign(hash_obj) + self.assertEqual(r + s, result) + + +def get_hash_module(hash_name): + if hash_name == "SHA-512": + hash_module = SHA512 + elif hash_name == "SHA-512/224": + hash_module = SHA512.new(truncate="224") + elif hash_name == "SHA-512/256": + hash_module = SHA512.new(truncate="256") + elif hash_name == "SHA-384": + hash_module = SHA384 + elif hash_name == "SHA-256": + hash_module = SHA256 + elif hash_name == "SHA-224": + hash_module = SHA224 + elif hash_name == "SHA-1": + hash_module = SHA1 + elif hash_name == "SHA3-224": + hash_module = SHA3_224 + elif hash_name == "SHA3-256": + hash_module = SHA3_256 + elif hash_name == "SHA3-384": + hash_module = SHA3_384 + elif hash_name == "SHA3-512": + hash_module = SHA3_512 + else: + raise ValueError("Unknown hash algorithm: " + hash_name) + return hash_module + + +class TestVectorsDSAWycheproof(unittest.TestCase): + + def __init__(self, wycheproof_warnings, slow_tests): + unittest.TestCase.__init__(self) + self._wycheproof_warnings = wycheproof_warnings + self._slow_tests = slow_tests + self._id = "None" + self.tv = [] + + def setUp(self): + + def filter_dsa(group): + return DSA.import_key(group['keyPem']) + + def filter_sha(group): + return get_hash_module(group['sha']) + + def filter_type(group): + sig_type = group['type'] + if sig_type != 'DsaVerify': + raise ValueError("Unknown signature type " + sig_type) + return sig_type + + result = load_test_vectors_wycheproof(("Signature", "wycheproof"), + "dsa_test.json", + "Wycheproof DSA signature", + group_tag={'key': filter_dsa, + 'hash_module': filter_sha, + 'sig_type': filter_type}) + self.tv += result + + def shortDescription(self): + return self._id + + def warn(self, tv): + if tv.warning and self._wycheproof_warnings: + import warnings + warnings.warn("Wycheproof warning: %s (%s)" % (self._id, tv.comment)) + + def test_verify(self, tv): + self._id = "Wycheproof DSA Test #" + str(tv.id) + + hashed_msg = tv.hash_module.new(tv.msg) + signer = DSS.new(tv.key, 'fips-186-3', encoding='der') + try: + signature = signer.verify(hashed_msg, tv.sig) + except ValueError as e: + if tv.warning: + return + assert not tv.valid + else: + assert tv.valid + self.warn(tv) + + def runTest(self): + for tv in self.tv: + self.test_verify(tv) + + +class TestVectorsECDSAWycheproof(unittest.TestCase): + + def __init__(self, wycheproof_warnings, slow_tests): + unittest.TestCase.__init__(self) + self._wycheproof_warnings = wycheproof_warnings + self._slow_tests = slow_tests + self._id = "None" + + def add_tests(self, filename): + + def filter_ecc(group): + # These are the only curves we accept to skip + if group['key']['curve'] in ('secp224k1', 'secp256k1', + 'brainpoolP224r1', 'brainpoolP224t1', + 'brainpoolP256r1', 'brainpoolP256t1', + 'brainpoolP320r1', 'brainpoolP320t1', + 'brainpoolP384r1', 'brainpoolP384t1', + 'brainpoolP512r1', 'brainpoolP512t1', + ): + return None + return ECC.import_key(group['keyPem']) + + def filter_sha(group): + return get_hash_module(group['sha']) + + def filter_encoding(group): + encoding_name = group['type'] + if encoding_name == "EcdsaVerify": + return "der" + elif encoding_name == "EcdsaP1363Verify": + return "binary" + else: + raise ValueError("Unknown signature type " + encoding_name) + + result = load_test_vectors_wycheproof(("Signature", "wycheproof"), + filename, + "Wycheproof ECDSA signature (%s)" % filename, + group_tag={'key': filter_ecc, + 'hash_module': filter_sha, + 'encoding': filter_encoding, + }) + self.tv += result + + def setUp(self): + self.tv = [] + self.add_tests("ecdsa_secp224r1_sha224_p1363_test.json") + self.add_tests("ecdsa_secp224r1_sha224_test.json") + if self._slow_tests: + self.add_tests("ecdsa_secp224r1_sha256_p1363_test.json") + self.add_tests("ecdsa_secp224r1_sha256_test.json") + self.add_tests("ecdsa_secp224r1_sha3_224_test.json") + self.add_tests("ecdsa_secp224r1_sha3_256_test.json") + self.add_tests("ecdsa_secp224r1_sha3_512_test.json") + self.add_tests("ecdsa_secp224r1_sha512_p1363_test.json") + self.add_tests("ecdsa_secp224r1_sha512_test.json") + self.add_tests("ecdsa_secp256r1_sha256_p1363_test.json") + self.add_tests("ecdsa_secp256r1_sha256_test.json") + self.add_tests("ecdsa_secp256r1_sha3_256_test.json") + self.add_tests("ecdsa_secp256r1_sha3_512_test.json") + self.add_tests("ecdsa_secp256r1_sha512_p1363_test.json") + self.add_tests("ecdsa_secp256r1_sha512_test.json") + if self._slow_tests: + self.add_tests("ecdsa_secp384r1_sha3_384_test.json") + self.add_tests("ecdsa_secp384r1_sha3_512_test.json") + self.add_tests("ecdsa_secp384r1_sha384_p1363_test.json") + self.add_tests("ecdsa_secp384r1_sha384_test.json") + self.add_tests("ecdsa_secp384r1_sha512_p1363_test.json") + self.add_tests("ecdsa_secp384r1_sha512_test.json") + if self._slow_tests: + self.add_tests("ecdsa_secp521r1_sha3_512_test.json") + self.add_tests("ecdsa_secp521r1_sha512_p1363_test.json") + self.add_tests("ecdsa_secp521r1_sha512_test.json") + self.add_tests("ecdsa_test.json") + self.add_tests("ecdsa_webcrypto_test.json") + + def shortDescription(self): + return self._id + + def warn(self, tv): + if tv.warning and self._wycheproof_warnings: + import warnings + warnings.warn("Wycheproof warning: %s (%s)" % (self._id, tv.comment)) + + def test_verify(self, tv): + self._id = "Wycheproof ECDSA Test #%d (%s, %s)" % (tv.id, tv.comment, tv.filename) + + # Skip tests with unsupported curves + if tv.key is None: + return + + hashed_msg = tv.hash_module.new(tv.msg) + signer = DSS.new(tv.key, 'fips-186-3', encoding=tv.encoding) + try: + signature = signer.verify(hashed_msg, tv.sig) + except ValueError as e: + if tv.warning: + return + if tv.comment == "k*G has a large x-coordinate": + return + assert not tv.valid + else: + assert tv.valid + self.warn(tv) + + def runTest(self): + for tv in self.tv: + self.test_verify(tv) + + +def get_tests(config={}): + wycheproof_warnings = config.get('wycheproof_warnings') + + tests = [] + tests += list_test_cases(FIPS_DSA_Tests) + tests += list_test_cases(FIPS_ECDSA_Tests) + tests += list_test_cases(Det_DSA_Tests) + tests += list_test_cases(Det_ECDSA_Tests) + + slow_tests = config.get('slow_tests') + if slow_tests: + tests += list_test_cases(FIPS_DSA_Tests_KAT) + tests += list_test_cases(FIPS_ECDSA_Tests_KAT) + + tests += [TestVectorsDSAWycheproof(wycheproof_warnings, slow_tests)] + tests += [TestVectorsECDSAWycheproof(wycheproof_warnings, slow_tests)] + + return tests + + +if __name__ == '__main__': + def suite(): + return unittest.TestSuite(get_tests()) + unittest.main(defaultTest='suite') diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Signature/test_eddsa.py b/venv/Lib/site-packages/Cryptodome/SelfTest/Signature/test_eddsa.py new file mode 100644 index 0000000..3215bbc --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/SelfTest/Signature/test_eddsa.py @@ -0,0 +1,604 @@ +# +# Copyright (c) 2022, Legrandin +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# =================================================================== + +import unittest +from binascii import unhexlify + +from Cryptodome.PublicKey import ECC +from Cryptodome.Signature import eddsa +from Cryptodome.Hash import SHA512, SHAKE256 +from Cryptodome.SelfTest.st_common import list_test_cases +from Cryptodome.SelfTest.loader import load_test_vectors_wycheproof +from Cryptodome.Util.number import bytes_to_long + +rfc8032_tv_str = ( + # 7.1 Ed25519 + ( + "9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60", + "d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a", + "", + None, + "", + "e5564300c360ac729086e2cc806e828a" + "84877f1eb8e5d974d873e06522490155" + "5fb8821590a33bacc61e39701cf9b46b" + "d25bf5f0595bbe24655141438e7a100b" + ), + ( + "4ccd089b28ff96da9db6c346ec114e0f5b8a319f35aba624da8cf6ed4fb8a6fb", + "3d4017c3e843895a92b70aa74d1b7ebc9c982ccf2ec4968cc0cd55f12af4660c", + "72", + None, + "", + "92a009a9f0d4cab8720e820b5f642540" + "a2b27b5416503f8fb3762223ebdb69da" + "085ac1e43e15996e458f3613d0f11d8c" + "387b2eaeb4302aeeb00d291612bb0c00" + ), + ( + "c5aa8df43f9f837bedb7442f31dcb7b166d38535076f094b85ce3a2e0b4458f7", + "fc51cd8e6218a1a38da47ed00230f0580816ed13ba3303ac5deb911548908025", + "af82", + None, + "", + "6291d657deec24024827e69c3abe01a3" + "0ce548a284743a445e3680d7db5ac3ac" + "18ff9b538d16f290ae67f760984dc659" + "4a7c15e9716ed28dc027beceea1ec40a" + ), + ( + "f5e5767cf153319517630f226876b86c8160cc583bc013744c6bf255f5cc0ee5", + "278117fc144c72340f67d0f2316e8386ceffbf2b2428c9c51fef7c597f1d426e", + "08b8b2b733424243760fe426a4b54908" + "632110a66c2f6591eabd3345e3e4eb98" + "fa6e264bf09efe12ee50f8f54e9f77b1" + "e355f6c50544e23fb1433ddf73be84d8" + "79de7c0046dc4996d9e773f4bc9efe57" + "38829adb26c81b37c93a1b270b20329d" + "658675fc6ea534e0810a4432826bf58c" + "941efb65d57a338bbd2e26640f89ffbc" + "1a858efcb8550ee3a5e1998bd177e93a" + "7363c344fe6b199ee5d02e82d522c4fe" + "ba15452f80288a821a579116ec6dad2b" + "3b310da903401aa62100ab5d1a36553e" + "06203b33890cc9b832f79ef80560ccb9" + "a39ce767967ed628c6ad573cb116dbef" + "efd75499da96bd68a8a97b928a8bbc10" + "3b6621fcde2beca1231d206be6cd9ec7" + "aff6f6c94fcd7204ed3455c68c83f4a4" + "1da4af2b74ef5c53f1d8ac70bdcb7ed1" + "85ce81bd84359d44254d95629e9855a9" + "4a7c1958d1f8ada5d0532ed8a5aa3fb2" + "d17ba70eb6248e594e1a2297acbbb39d" + "502f1a8c6eb6f1ce22b3de1a1f40cc24" + "554119a831a9aad6079cad88425de6bd" + "e1a9187ebb6092cf67bf2b13fd65f270" + "88d78b7e883c8759d2c4f5c65adb7553" + "878ad575f9fad878e80a0c9ba63bcbcc" + "2732e69485bbc9c90bfbd62481d9089b" + "eccf80cfe2df16a2cf65bd92dd597b07" + "07e0917af48bbb75fed413d238f5555a" + "7a569d80c3414a8d0859dc65a46128ba" + "b27af87a71314f318c782b23ebfe808b" + "82b0ce26401d2e22f04d83d1255dc51a" + "ddd3b75a2b1ae0784504df543af8969b" + "e3ea7082ff7fc9888c144da2af58429e" + "c96031dbcad3dad9af0dcbaaaf268cb8" + "fcffead94f3c7ca495e056a9b47acdb7" + "51fb73e666c6c655ade8297297d07ad1" + "ba5e43f1bca32301651339e22904cc8c" + "42f58c30c04aafdb038dda0847dd988d" + "cda6f3bfd15c4b4c4525004aa06eeff8" + "ca61783aacec57fb3d1f92b0fe2fd1a8" + "5f6724517b65e614ad6808d6f6ee34df" + "f7310fdc82aebfd904b01e1dc54b2927" + "094b2db68d6f903b68401adebf5a7e08" + "d78ff4ef5d63653a65040cf9bfd4aca7" + "984a74d37145986780fc0b16ac451649" + "de6188a7dbdf191f64b5fc5e2ab47b57" + "f7f7276cd419c17a3ca8e1b939ae49e4" + "88acba6b965610b5480109c8b17b80e1" + "b7b750dfc7598d5d5011fd2dcc5600a3" + "2ef5b52a1ecc820e308aa342721aac09" + "43bf6686b64b2579376504ccc493d97e" + "6aed3fb0f9cd71a43dd497f01f17c0e2" + "cb3797aa2a2f256656168e6c496afc5f" + "b93246f6b1116398a346f1a641f3b041" + "e989f7914f90cc2c7fff357876e506b5" + "0d334ba77c225bc307ba537152f3f161" + "0e4eafe595f6d9d90d11faa933a15ef1" + "369546868a7f3a45a96768d40fd9d034" + "12c091c6315cf4fde7cb68606937380d" + "b2eaaa707b4c4185c32eddcdd306705e" + "4dc1ffc872eeee475a64dfac86aba41c" + "0618983f8741c5ef68d3a101e8a3b8ca" + "c60c905c15fc910840b94c00a0b9d0", + None, + "", + "0aab4c900501b3e24d7cdf4663326a3a" + "87df5e4843b2cbdb67cbf6e460fec350" + "aa5371b1508f9f4528ecea23c436d94b" + "5e8fcd4f681e30a6ac00a9704a188a03" + ), + # 7.2 Ed25519ctx + ( + "0305334e381af78f141cb666f6199f57" + "bc3495335a256a95bd2a55bf546663f6", + "dfc9425e4f968f7f0c29f0259cf5f9ae" + "d6851c2bb4ad8bfb860cfee0ab248292", + "f726936d19c800494e3fdaff20b276a8", + None, + "666f6f", + "55a4cc2f70a54e04288c5f4cd1e45a7b" + "b520b36292911876cada7323198dd87a" + "8b36950b95130022907a7fb7c4e9b2d5" + "f6cca685a587b4b21f4b888e4e7edb0d" + ), + ( + "0305334e381af78f141cb666f6199f57" + "bc3495335a256a95bd2a55bf546663f6", + "dfc9425e4f968f7f0c29f0259cf5f9ae" + "d6851c2bb4ad8bfb860cfee0ab248292", + "f726936d19c800494e3fdaff20b276a8", + None, + "626172", + "fc60d5872fc46b3aa69f8b5b4351d580" + "8f92bcc044606db097abab6dbcb1aee3" + "216c48e8b3b66431b5b186d1d28f8ee1" + "5a5ca2df6668346291c2043d4eb3e90d" + ), + ( + "0305334e381af78f141cb666f6199f57" + "bc3495335a256a95bd2a55bf546663f6", + "dfc9425e4f968f7f0c29f0259cf5f9ae" + "d6851c2bb4ad8bfb860cfee0ab248292", + "508e9e6882b979fea900f62adceaca35", + None, + "666f6f", + "8b70c1cc8310e1de20ac53ce28ae6e72" + "07f33c3295e03bb5c0732a1d20dc6490" + "8922a8b052cf99b7c4fe107a5abb5b2c" + "4085ae75890d02df26269d8945f84b0b" + ), + ( + "ab9c2853ce297ddab85c993b3ae14bca" + "d39b2c682beabc27d6d4eb20711d6560", + "0f1d1274943b91415889152e893d80e9" + "3275a1fc0b65fd71b4b0dda10ad7d772", + "f726936d19c800494e3fdaff20b276a8", + None, + "666f6f", + "21655b5f1aa965996b3f97b3c849eafb" + "a922a0a62992f73b3d1b73106a84ad85" + "e9b86a7b6005ea868337ff2d20a7f5fb" + "d4cd10b0be49a68da2b2e0dc0ad8960f" + ), + # 7.3 Ed25519ph + ( + "833fe62409237b9d62ec77587520911e" + "9a759cec1d19755b7da901b96dca3d42", + "ec172b93ad5e563bf4932c70e1245034" + "c35467ef2efd4d64ebf819683467e2bf", + "616263", + SHA512, + "", + "98a70222f0b8121aa9d30f813d683f80" + "9e462b469c7ff87639499bb94e6dae41" + "31f85042463c2a355a2003d062adf5aa" + "a10b8c61e636062aaad11c2a26083406" + ), + # 7.4 Ed448 + ( + "6c82a562cb808d10d632be89c8513ebf6c929f34ddfa8c9f63c9960ef6e348a3" + "528c8a3fcc2f044e39a3fc5b94492f8f032e7549a20098f95b", + "5fd7449b59b461fd2ce787ec616ad46a1da1342485a70e1f8a0ea75d80e96778" + "edf124769b46c7061bd6783df1e50f6cd1fa1abeafe8256180", + "", + None, + "", + "533a37f6bbe457251f023c0d88f976ae2dfb504a843e34d2074fd823d41a591f" + "2b233f034f628281f2fd7a22ddd47d7828c59bd0a21bfd3980ff0d2028d4b18a" + "9df63e006c5d1c2d345b925d8dc00b4104852db99ac5c7cdda8530a113a0f4db" + "b61149f05a7363268c71d95808ff2e652600" + ), + ( + "c4eab05d357007c632f3dbb48489924d552b08fe0c353a0d4a1f00acda2c463a" + "fbea67c5e8d2877c5e3bc397a659949ef8021e954e0a12274e", + "43ba28f430cdff456ae531545f7ecd0ac834a55d9358c0372bfa0c6c6798c086" + "6aea01eb00742802b8438ea4cb82169c235160627b4c3a9480", + "03", + None, + "", + "26b8f91727bd62897af15e41eb43c377efb9c610d48f2335cb0bd0087810f435" + "2541b143c4b981b7e18f62de8ccdf633fc1bf037ab7cd779805e0dbcc0aae1cb" + "cee1afb2e027df36bc04dcecbf154336c19f0af7e0a6472905e799f1953d2a0f" + "f3348ab21aa4adafd1d234441cf807c03a00", + ), + ( + "c4eab05d357007c632f3dbb48489924d552b08fe0c353a0d4a1f00acda2c463a" + "fbea67c5e8d2877c5e3bc397a659949ef8021e954e0a12274e", + "43ba28f430cdff456ae531545f7ecd0ac834a55d9358c0372bfa0c6c6798c086" + "6aea01eb00742802b8438ea4cb82169c235160627b4c3a9480", + "03", + None, + "666f6f", + "d4f8f6131770dd46f40867d6fd5d5055de43541f8c5e35abbcd001b32a89f7d2" + "151f7647f11d8ca2ae279fb842d607217fce6e042f6815ea000c85741de5c8da" + "1144a6a1aba7f96de42505d7a7298524fda538fccbbb754f578c1cad10d54d0d" + "5428407e85dcbc98a49155c13764e66c3c00", + ), + ( + "cd23d24f714274e744343237b93290f511f6425f98e64459ff203e8985083ffd" + "f60500553abc0e05cd02184bdb89c4ccd67e187951267eb328", + "dcea9e78f35a1bf3499a831b10b86c90aac01cd84b67a0109b55a36e9328b1e3" + "65fce161d71ce7131a543ea4cb5f7e9f1d8b00696447001400", + "0c3e544074ec63b0265e0c", + None, + "", + "1f0a8888ce25e8d458a21130879b840a9089d999aaba039eaf3e3afa090a09d3" + "89dba82c4ff2ae8ac5cdfb7c55e94d5d961a29fe0109941e00b8dbdeea6d3b05" + "1068df7254c0cdc129cbe62db2dc957dbb47b51fd3f213fb8698f064774250a5" + "028961c9bf8ffd973fe5d5c206492b140e00", + ), + ( + "258cdd4ada32ed9c9ff54e63756ae582fb8fab2ac721f2c8e676a72768513d93" + "9f63dddb55609133f29adf86ec9929dccb52c1c5fd2ff7e21b", + "3ba16da0c6f2cc1f30187740756f5e798d6bc5fc015d7c63cc9510ee3fd44adc" + "24d8e968b6e46e6f94d19b945361726bd75e149ef09817f580", + "64a65f3cdedcdd66811e2915", + None, + "", + "7eeeab7c4e50fb799b418ee5e3197ff6bf15d43a14c34389b59dd1a7b1b85b4a" + "e90438aca634bea45e3a2695f1270f07fdcdf7c62b8efeaf00b45c2c96ba457e" + "b1a8bf075a3db28e5c24f6b923ed4ad747c3c9e03c7079efb87cb110d3a99861" + "e72003cbae6d6b8b827e4e6c143064ff3c00", + ), + ( + "7ef4e84544236752fbb56b8f31a23a10e42814f5f55ca037cdcc11c64c9a3b29" + "49c1bb60700314611732a6c2fea98eebc0266a11a93970100e", + "b3da079b0aa493a5772029f0467baebee5a8112d9d3a22532361da294f7bb381" + "5c5dc59e176b4d9f381ca0938e13c6c07b174be65dfa578e80", + "64a65f3cdedcdd66811e2915e7", + None, + "", + "6a12066f55331b6c22acd5d5bfc5d71228fbda80ae8dec26bdd306743c5027cb" + "4890810c162c027468675ecf645a83176c0d7323a2ccde2d80efe5a1268e8aca" + "1d6fbc194d3f77c44986eb4ab4177919ad8bec33eb47bbb5fc6e28196fd1caf5" + "6b4e7e0ba5519234d047155ac727a1053100", + ), + ( + "d65df341ad13e008567688baedda8e9dcdc17dc024974ea5b4227b6530e339bf" + "f21f99e68ca6968f3cca6dfe0fb9f4fab4fa135d5542ea3f01", + "df9705f58edbab802c7f8363cfe5560ab1c6132c20a9f1dd163483a26f8ac53a" + "39d6808bf4a1dfbd261b099bb03b3fb50906cb28bd8a081f00", + "bd0f6a3747cd561bdddf4640a332461a4a30a12a434cd0bf40d766d9c6d458e5" + "512204a30c17d1f50b5079631f64eb3112182da3005835461113718d1a5ef944", + None, + "", + "554bc2480860b49eab8532d2a533b7d578ef473eeb58c98bb2d0e1ce488a98b1" + "8dfde9b9b90775e67f47d4a1c3482058efc9f40d2ca033a0801b63d45b3b722e" + "f552bad3b4ccb667da350192b61c508cf7b6b5adadc2c8d9a446ef003fb05cba" + "5f30e88e36ec2703b349ca229c2670833900", + ), + ( + "2ec5fe3c17045abdb136a5e6a913e32ab75ae68b53d2fc149b77e504132d3756" + "9b7e766ba74a19bd6162343a21c8590aa9cebca9014c636df5", + "79756f014dcfe2079f5dd9e718be4171e2ef2486a08f25186f6bff43a9936b9b" + "fe12402b08ae65798a3d81e22e9ec80e7690862ef3d4ed3a00", + "15777532b0bdd0d1389f636c5f6b9ba734c90af572877e2d272dd078aa1e567c" + "fa80e12928bb542330e8409f3174504107ecd5efac61ae7504dabe2a602ede89" + "e5cca6257a7c77e27a702b3ae39fc769fc54f2395ae6a1178cab4738e543072f" + "c1c177fe71e92e25bf03e4ecb72f47b64d0465aaea4c7fad372536c8ba516a60" + "39c3c2a39f0e4d832be432dfa9a706a6e5c7e19f397964ca4258002f7c0541b5" + "90316dbc5622b6b2a6fe7a4abffd96105eca76ea7b98816af0748c10df048ce0" + "12d901015a51f189f3888145c03650aa23ce894c3bd889e030d565071c59f409" + "a9981b51878fd6fc110624dcbcde0bf7a69ccce38fabdf86f3bef6044819de11", + None, + "", + "c650ddbb0601c19ca11439e1640dd931f43c518ea5bea70d3dcde5f4191fe53f" + "00cf966546b72bcc7d58be2b9badef28743954e3a44a23f880e8d4f1cfce2d7a" + "61452d26da05896f0a50da66a239a8a188b6d825b3305ad77b73fbac0836ecc6" + "0987fd08527c1a8e80d5823e65cafe2a3d00", + ), + ( + "872d093780f5d3730df7c212664b37b8a0f24f56810daa8382cd4fa3f77634ec" + "44dc54f1c2ed9bea86fafb7632d8be199ea165f5ad55dd9ce8", + "a81b2e8a70a5ac94ffdbcc9badfc3feb0801f258578bb114ad44ece1ec0e799d" + "a08effb81c5d685c0c56f64eecaef8cdf11cc38737838cf400", + "6ddf802e1aae4986935f7f981ba3f0351d6273c0a0c22c9c0e8339168e675412" + "a3debfaf435ed651558007db4384b650fcc07e3b586a27a4f7a00ac8a6fec2cd" + "86ae4bf1570c41e6a40c931db27b2faa15a8cedd52cff7362c4e6e23daec0fbc" + "3a79b6806e316efcc7b68119bf46bc76a26067a53f296dafdbdc11c77f7777e9" + "72660cf4b6a9b369a6665f02e0cc9b6edfad136b4fabe723d2813db3136cfde9" + "b6d044322fee2947952e031b73ab5c603349b307bdc27bc6cb8b8bbd7bd32321" + "9b8033a581b59eadebb09b3c4f3d2277d4f0343624acc817804728b25ab79717" + "2b4c5c21a22f9c7839d64300232eb66e53f31c723fa37fe387c7d3e50bdf9813" + "a30e5bb12cf4cd930c40cfb4e1fc622592a49588794494d56d24ea4b40c89fc0" + "596cc9ebb961c8cb10adde976a5d602b1c3f85b9b9a001ed3c6a4d3b1437f520" + "96cd1956d042a597d561a596ecd3d1735a8d570ea0ec27225a2c4aaff26306d1" + "526c1af3ca6d9cf5a2c98f47e1c46db9a33234cfd4d81f2c98538a09ebe76998" + "d0d8fd25997c7d255c6d66ece6fa56f11144950f027795e653008f4bd7ca2dee" + "85d8e90f3dc315130ce2a00375a318c7c3d97be2c8ce5b6db41a6254ff264fa6" + "155baee3b0773c0f497c573f19bb4f4240281f0b1f4f7be857a4e59d416c06b4" + "c50fa09e1810ddc6b1467baeac5a3668d11b6ecaa901440016f389f80acc4db9" + "77025e7f5924388c7e340a732e554440e76570f8dd71b7d640b3450d1fd5f041" + "0a18f9a3494f707c717b79b4bf75c98400b096b21653b5d217cf3565c9597456" + "f70703497a078763829bc01bb1cbc8fa04eadc9a6e3f6699587a9e75c94e5bab" + "0036e0b2e711392cff0047d0d6b05bd2a588bc109718954259f1d86678a579a3" + "120f19cfb2963f177aeb70f2d4844826262e51b80271272068ef5b3856fa8535" + "aa2a88b2d41f2a0e2fda7624c2850272ac4a2f561f8f2f7a318bfd5caf969614" + "9e4ac824ad3460538fdc25421beec2cc6818162d06bbed0c40a387192349db67" + "a118bada6cd5ab0140ee273204f628aad1c135f770279a651e24d8c14d75a605" + "9d76b96a6fd857def5e0b354b27ab937a5815d16b5fae407ff18222c6d1ed263" + "be68c95f32d908bd895cd76207ae726487567f9a67dad79abec316f683b17f2d" + "02bf07e0ac8b5bc6162cf94697b3c27cd1fea49b27f23ba2901871962506520c" + "392da8b6ad0d99f7013fbc06c2c17a569500c8a7696481c1cd33e9b14e40b82e" + "79a5f5db82571ba97bae3ad3e0479515bb0e2b0f3bfcd1fd33034efc6245eddd" + "7ee2086ddae2600d8ca73e214e8c2b0bdb2b047c6a464a562ed77b73d2d841c4" + "b34973551257713b753632efba348169abc90a68f42611a40126d7cb21b58695" + "568186f7e569d2ff0f9e745d0487dd2eb997cafc5abf9dd102e62ff66cba87", + None, + "", + "e301345a41a39a4d72fff8df69c98075a0cc082b802fc9b2b6bc503f926b65bd" + "df7f4c8f1cb49f6396afc8a70abe6d8aef0db478d4c6b2970076c6a0484fe76d" + "76b3a97625d79f1ce240e7c576750d295528286f719b413de9ada3e8eb78ed57" + "3603ce30d8bb761785dc30dbc320869e1a00" + ), + # 7.5 Ed448ph + ( + "833fe62409237b9d62ec77587520911e9a759cec1d19755b7da901b96dca3d42" + "ef7822e0d5104127dc05d6dbefde69e3ab2cec7c867c6e2c49", + "259b71c19f83ef77a7abd26524cbdb3161b590a48f7d17de3ee0ba9c52beb743" + "c09428a131d6b1b57303d90d8132c276d5ed3d5d01c0f53880", + "616263", + SHAKE256, + "", + "822f6901f7480f3d5f562c592994d9693602875614483256505600bbc281ae38" + "1f54d6bce2ea911574932f52a4e6cadd78769375ec3ffd1b801a0d9b3f4030cd" + "433964b6457ea39476511214f97469b57dd32dbc560a9a94d00bff07620464a3" + "ad203df7dc7ce360c3cd3696d9d9fab90f00" + ), + ( + "833fe62409237b9d62ec77587520911e9a759cec1d19755b7da901b96dca3d42" + "ef7822e0d5104127dc05d6dbefde69e3ab2cec7c867c6e2c49", + "259b71c19f83ef77a7abd26524cbdb3161b590a48f7d17de3ee0ba9c52beb743" + "c09428a131d6b1b57303d90d8132c276d5ed3d5d01c0f53880", + "616263", + SHAKE256, + "666f6f", + "c32299d46ec8ff02b54540982814dce9a05812f81962b649d528095916a2aa48" + "1065b1580423ef927ecf0af5888f90da0f6a9a85ad5dc3f280d91224ba9911a3" + "653d00e484e2ce232521481c8658df304bb7745a73514cdb9bf3e15784ab7128" + "4f8d0704a608c54a6b62d97beb511d132100", + ), +) + + +rfc8032_tv_bytes = [] +for tv_str in rfc8032_tv_str: + rfc8032_tv_bytes.append([unhexlify(i) if isinstance(i, str) else i for i in tv_str]) + + +class TestEdDSA(unittest.TestCase): + + def test_sign(self): + for sk, _, msg, hashmod, ctx, exp_signature in rfc8032_tv_bytes: + key = eddsa.import_private_key(sk) + signer = eddsa.new(key, 'rfc8032', context=ctx) + if hashmod is None: + # PureEdDSA + signature = signer.sign(msg) + else: + # HashEdDSA + hashobj = hashmod.new(msg) + signature = signer.sign(hashobj) + self.assertEqual(exp_signature, signature) + + def test_verify(self): + for _, pk, msg, hashmod, ctx, exp_signature in rfc8032_tv_bytes: + key = eddsa.import_public_key(pk) + verifier = eddsa.new(key, 'rfc8032', context=ctx) + if hashmod is None: + # PureEdDSA + verifier.verify(msg, exp_signature) + else: + # HashEdDSA + hashobj = hashmod.new(msg) + verifier.verify(hashobj, exp_signature) + + def test_double_sign_verify_ed25519(self): + msg_hash = SHA512.new(b'abc') + key = ECC.generate(curve='ed25519') + signer = eddsa.new(key, 'rfc8032') + verifier = eddsa.new(key, 'rfc8032') + + signature = signer.sign(msg_hash) + signature2 = signer.sign(msg_hash) + self.assertEqual(signature, signature2) + + verifier.verify(msg_hash, signature) + verifier.verify(msg_hash, signature) + + def test_double_sign_verify_ed448(self): + msg_hash = SHAKE256.new(b'abc') + key = ECC.generate(curve='ed448') + signer = eddsa.new(key, 'rfc8032') + verifier = eddsa.new(key, 'rfc8032') + + signature = signer.sign(msg_hash) + signature2 = signer.sign(msg_hash) + self.assertEqual(signature, signature2) + + verifier.verify(msg_hash, signature) + verifier.verify(msg_hash, signature) + + def test_negative(self): + key = ECC.generate(curve="ed25519") + self.assertRaises(ValueError, eddsa.new, key, 'rfc9999') + + nist_key = ECC.generate(curve="p256") + self.assertRaises(ValueError, eddsa.new, nist_key, 'rfc8032') + + +class TestExport_Ed25519(unittest.TestCase): + + def test_raw(self): + key = ECC.generate(curve="Ed25519") + x, y = key.pointQ.xy + raw = bytearray(key._export_eddsa_public()) + sign_x = raw[31] >> 7 + raw[31] &= 0x7F + yt = bytes_to_long(raw[::-1]) + self.assertEqual(y, yt) + self.assertEqual(x & 1, sign_x) + + key = ECC.construct(point_x=0, point_y=1, curve="Ed25519") + out = key._export_eddsa_public() + self.assertEqual(b'\x01' + b'\x00' * 31, out) + + +class TestExport_Ed448(unittest.TestCase): + + def test_raw(self): + key = ECC.generate(curve="Ed448") + x, y = key.pointQ.xy + raw = bytearray(key._export_eddsa_public()) + sign_x = raw[56] >> 7 + raw[56] &= 0x7F + yt = bytes_to_long(raw[::-1]) + self.assertEqual(y, yt) + self.assertEqual(x & 1, sign_x) + + key = ECC.construct(point_x=0, point_y=1, curve="Ed448") + out = key._export_eddsa_public() + self.assertEqual(b'\x01' + b'\x00' * 56, out) + + +class TestImport_Ed25519(unittest.TestCase): + + def test_raw(self): + Px = 24407857220263921307776619664228778204996144802740950419837658238229122415920 + Py = 56480760040633817885061096979765646085062883740629155052073094891081309750690 + encoded = b'\xa2\x05\xd6\x00\xe1 \xe1\xc0\xff\x96\xee?V\x8e\xba/\xd3\x89\x06\xd7\xc4c\xe8$\xc2d\xd7a1\xfa\xde|' + key = eddsa.import_public_key(encoded) + self.assertEqual(Py, key.pointQ.y) + self.assertEqual(Px, key.pointQ.x) + + encoded = b'\x01' + b'\x00' * 31 + key = eddsa.import_public_key(encoded) + self.assertEqual(1, key.pointQ.y) + self.assertEqual(0, key.pointQ.x) + + +class TestImport_Ed448(unittest.TestCase): + + def test_raw(self): + Px = 0x153f42025aba3b0daecaa5cd79458b3146c7c9378c16c17b4a59bc3561113d90c169045bc12966c3f93e140c2ca0a3acc33d9205b9daf9b1 + Py = 0x38f5c0015d3dedd576c232810dd90373b5b1d631a12894c043b7be529cbae03ede177d8fa490b56131dbcb2465d2aba777ef839fc1719b25 + encoded = unhexlify("259b71c19f83ef77a7abd26524cbdb31" + "61b590a48f7d17de3ee0ba9c52beb743" + "c09428a131d6b1b57303d90d8132c276" + "d5ed3d5d01c0f53880") + key = eddsa.import_public_key(encoded) + self.assertEqual(Py, key.pointQ.y) + self.assertEqual(Px, key.pointQ.x) + + encoded = b'\x01' + b'\x00' * 56 + key = eddsa.import_public_key(encoded) + self.assertEqual(1, key.pointQ.y) + self.assertEqual(0, key.pointQ.x) + + +class TestVectorsEdDSAWycheproof(unittest.TestCase): + + def add_tests(self, filename): + + def pk(group): + elem = group['key']['pk'] + return unhexlify(elem) + + def sk(group): + elem = group['key']['sk'] + return unhexlify(elem) + + result = load_test_vectors_wycheproof(("Signature", "wycheproof"), + filename, + "Wycheproof ECDSA signature (%s)" + % filename, + group_tag={'pk': pk, 'sk': sk}) + self.tv += result + + def setUp(self): + self.tv = [] + self.add_tests("eddsa_test.json") + self.add_tests("ed448_test.json") + + def test_sign(self, tv): + if not tv.valid: + return + + self._id = "Wycheproof EdDSA Sign Test #%d (%s, %s)" % (tv.id, tv.comment, tv.filename) + key = eddsa.import_private_key(tv.sk) + signer = eddsa.new(key, 'rfc8032') + signature = signer.sign(tv.msg) + self.assertEqual(signature, tv.sig) + + def test_verify(self, tv): + self._id = "Wycheproof EdDSA Verify Test #%d (%s, %s)" % (tv.id, tv.comment, tv.filename) + key = eddsa.import_public_key(tv.pk) + verifier = eddsa.new(key, 'rfc8032') + try: + verifier.verify(tv.msg, tv.sig) + except ValueError: + assert not tv.valid + else: + assert tv.valid + + def runTest(self): + for tv in self.tv: + self.test_sign(tv) + self.test_verify(tv) + + +def get_tests(config={}): + + tests = [] + tests += list_test_cases(TestExport_Ed25519) + tests += list_test_cases(TestExport_Ed448) + tests += list_test_cases(TestImport_Ed25519) + tests += list_test_cases(TestImport_Ed448) + tests += list_test_cases(TestEdDSA) + tests += [TestVectorsEdDSAWycheproof()] + return tests + + +if __name__ == '__main__': + def suite(): + return unittest.TestSuite(get_tests()) + unittest.main(defaultTest='suite') diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Signature/test_pkcs1_15.py b/venv/Lib/site-packages/Cryptodome/SelfTest/Signature/test_pkcs1_15.py new file mode 100644 index 0000000..3a3e30b --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/SelfTest/Signature/test_pkcs1_15.py @@ -0,0 +1,348 @@ +# =================================================================== +# +# Copyright (c) 2014, Legrandin +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# =================================================================== + +import json +import unittest +from binascii import unhexlify + +from Cryptodome.Util.py3compat import bchr +from Cryptodome.Util.number import bytes_to_long +from Cryptodome.Util.strxor import strxor +from Cryptodome.SelfTest.st_common import list_test_cases +from Cryptodome.SelfTest.loader import load_test_vectors, load_test_vectors_wycheproof + +from Cryptodome.Hash import (SHA1, SHA224, SHA256, SHA384, SHA512, SHA3_384, + SHA3_224, SHA3_256, SHA3_512) +from Cryptodome.PublicKey import RSA +from Cryptodome.Signature import pkcs1_15 +from Cryptodome.Signature import PKCS1_v1_5 + +from Cryptodome.Util._file_system import pycryptodome_filename +from Cryptodome.Util.strxor import strxor + + +def load_hash_by_name(hash_name): + return __import__("Cryptodome.Hash." + hash_name, globals(), locals(), ["new"]) + + +class FIPS_PKCS1_Verify_Tests(unittest.TestCase): + + def shortDescription(self): + return "FIPS PKCS1 Tests (Verify)" + + def test_can_sign(self): + test_public_key = RSA.generate(1024).public_key() + verifier = pkcs1_15.new(test_public_key) + self.assertEqual(verifier.can_sign(), False) + + +class FIPS_PKCS1_Verify_Tests_KAT(unittest.TestCase): + pass + + +test_vectors_verify = load_test_vectors(("Signature", "PKCS1-v1.5"), + "SigVer15_186-3.rsp", + "Signature Verification 186-3", + {'shaalg': lambda x: x, + 'd': lambda x: int(x), + 'result': lambda x: x}) or [] + + +for count, tv in enumerate(test_vectors_verify): + if isinstance(tv, str): + continue + if hasattr(tv, "n"): + modulus = tv.n + continue + + hash_module = load_hash_by_name(tv.shaalg.upper()) + hash_obj = hash_module.new(tv.msg) + public_key = RSA.construct([bytes_to_long(x) for x in (modulus, tv.e)]) # type: ignore + verifier = pkcs1_15.new(public_key) + + def positive_test(self, hash_obj=hash_obj, verifier=verifier, signature=tv.s): + verifier.verify(hash_obj, signature) + + def negative_test(self, hash_obj=hash_obj, verifier=verifier, signature=tv.s): + self.assertRaises(ValueError, verifier.verify, hash_obj, signature) + + if tv.result == 'f': + setattr(FIPS_PKCS1_Verify_Tests_KAT, "test_negative_%d" % count, negative_test) + else: + setattr(FIPS_PKCS1_Verify_Tests_KAT, "test_positive_%d" % count, positive_test) + + +class FIPS_PKCS1_Sign_Tests(unittest.TestCase): + + def shortDescription(self): + return "FIPS PKCS1 Tests (Sign)" + + def test_can_sign(self): + test_private_key = RSA.generate(1024) + signer = pkcs1_15.new(test_private_key) + self.assertEqual(signer.can_sign(), True) + + +class FIPS_PKCS1_Sign_Tests_KAT(unittest.TestCase): + pass + + +test_vectors_sign = load_test_vectors(("Signature", "PKCS1-v1.5"), + "SigGen15_186-2.txt", + "Signature Generation 186-2", + {'shaalg': lambda x: x}) or [] + +test_vectors_sign += load_test_vectors(("Signature", "PKCS1-v1.5"), + "SigGen15_186-3.txt", + "Signature Generation 186-3", + {'shaalg': lambda x: x}) or [] + +for count, tv in enumerate(test_vectors_sign): + if isinstance(tv, str): + continue + if hasattr(tv, "n"): + modulus = tv.n + continue + if hasattr(tv, "e"): + private_key = RSA.construct([bytes_to_long(x) for x in (modulus, tv.e, tv.d)]) # type: ignore + signer = pkcs1_15.new(private_key) + continue + + hash_module = load_hash_by_name(tv.shaalg.upper()) + hash_obj = hash_module.new(tv.msg) + + def new_test(self, hash_obj=hash_obj, signer=signer, result=tv.s): + signature = signer.sign(hash_obj) + self.assertEqual(signature, result) + + setattr(FIPS_PKCS1_Sign_Tests_KAT, "test_%d" % count, new_test) + + +class PKCS1_15_NoParams(unittest.TestCase): + """Verify that PKCS#1 v1.5 signatures pass even without NULL parameters in + the algorithm identifier (PyCrypto/LP bug #1119552).""" + + rsakey = """-----BEGIN RSA PRIVATE KEY----- + MIIBOwIBAAJBAL8eJ5AKoIsjURpcEoGubZMxLD7+kT+TLr7UkvEtFrRhDDKMtuII + q19FrL4pUIMymPMSLBn3hJLe30Dw48GQM4UCAwEAAQJACUSDEp8RTe32ftq8IwG8 + Wojl5mAd1wFiIOrZ/Uv8b963WJOJiuQcVN29vxU5+My9GPZ7RA3hrDBEAoHUDPrI + OQIhAPIPLz4dphiD9imAkivY31Rc5AfHJiQRA7XixTcjEkojAiEAyh/pJHks/Mlr + +rdPNEpotBjfV4M4BkgGAA/ipcmaAjcCIQCHvhwwKVBLzzTscT2HeUdEeBMoiXXK + JACAr3sJQJGxIQIgarRp+m1WSKV1MciwMaTOnbU7wxFs9DP1pva76lYBzgUCIQC9 + n0CnZCJ6IZYqSt0H5N7+Q+2Ro64nuwV/OSQfM6sBwQ== + -----END RSA PRIVATE KEY-----""" + + msg = b"This is a test\x0a" + + # PKCS1 v1.5 signature of the message computed using SHA-1. + # The digestAlgorithm SEQUENCE does NOT contain the NULL parameter. + sig_str = "a287a13517f716e72fb14eea8e33a8db4a4643314607e7ca3e3e28"\ + "1893db74013dda8b855fd99f6fecedcb25fcb7a434f35cd0a101f8"\ + "b19348e0bd7b6f152dfc" + signature = unhexlify(sig_str) + + def runTest(self): + verifier = pkcs1_15.new(RSA.importKey(self.rsakey)) + hashed = SHA1.new(self.msg) + verifier.verify(hashed, self.signature) + + +class PKCS1_Legacy_Module_Tests(unittest.TestCase): + """Verify that the legacy module Cryptodome.Signature.PKCS1_v1_5 + behaves as expected. The only difference is that the verify() + method returns True/False and does not raise exceptions.""" + + def shortDescription(self): + return "Test legacy Cryptodome.Signature.PKCS1_v1_5" + + def runTest(self): + key = RSA.importKey(PKCS1_15_NoParams.rsakey) + hashed = SHA1.new(b"Test") + good_signature = PKCS1_v1_5.new(key).sign(hashed) + verifier = PKCS1_v1_5.new(key.public_key()) + + self.assertEqual(verifier.verify(hashed, good_signature), True) + + # Flip a few bits in the signature + bad_signature = strxor(good_signature, bchr(1) * len(good_signature)) + self.assertEqual(verifier.verify(hashed, bad_signature), False) + + +class PKCS1_All_Hashes_Tests(unittest.TestCase): + + def shortDescription(self): + return "Test PKCS#1v1.5 signature in combination with all hashes" + + def runTest(self): + + key = RSA.generate(1024) + signer = pkcs1_15.new(key) + hash_names = ("MD2", "MD4", "MD5", "RIPEMD160", "SHA1", + "SHA224", "SHA256", "SHA384", "SHA512", + "SHA3_224", "SHA3_256", "SHA3_384", "SHA3_512") + + for name in hash_names: + hashed = load_hash_by_name(name).new(b"Test") + signer.sign(hashed) + + from Cryptodome.Hash import BLAKE2b, BLAKE2s + for hash_size in (20, 32, 48, 64): + hashed_b = BLAKE2b.new(digest_bytes=hash_size, data=b"Test") + signer.sign(hashed_b) + for hash_size in (16, 20, 28, 32): + hashed_s = BLAKE2s.new(digest_bytes=hash_size, data=b"Test") + signer.sign(hashed_s) + + +class TestVectorsWycheproof(unittest.TestCase): + + def __init__(self, wycheproof_warnings): + unittest.TestCase.__init__(self) + self._wycheproof_warnings = wycheproof_warnings + self._id = "None" + + def setUp(self): + self.tv = [] + self.add_tests("rsa_sig_gen_misc_test.json") + self.add_tests("rsa_signature_2048_sha224_test.json") + self.add_tests("rsa_signature_2048_sha256_test.json") + self.add_tests("rsa_signature_2048_sha384_test.json") + self.add_tests("rsa_signature_2048_sha3_224_test.json") + self.add_tests("rsa_signature_2048_sha3_256_test.json") + self.add_tests("rsa_signature_2048_sha3_384_test.json") + self.add_tests("rsa_signature_2048_sha3_512_test.json") + self.add_tests("rsa_signature_2048_sha512_test.json") + self.add_tests("rsa_signature_2048_sha512_224_test.json") + self.add_tests("rsa_signature_2048_sha512_256_test.json") + self.add_tests("rsa_signature_3072_sha256_test.json") + self.add_tests("rsa_signature_3072_sha384_test.json") + self.add_tests("rsa_signature_3072_sha3_256_test.json") + self.add_tests("rsa_signature_3072_sha3_384_test.json") + self.add_tests("rsa_signature_3072_sha3_512_test.json") + self.add_tests("rsa_signature_3072_sha512_test.json") + self.add_tests("rsa_signature_3072_sha512_256_test.json") + self.add_tests("rsa_signature_4096_sha384_test.json") + self.add_tests("rsa_signature_4096_sha512_test.json") + self.add_tests("rsa_signature_4096_sha512_256_test.json") + self.add_tests("rsa_signature_test.json") + + def add_tests(self, filename): + + def filter_rsa(group): + return RSA.import_key(group['keyPem']) + + def filter_sha(group): + hash_name = group['sha'] + if hash_name == "SHA-512": + return SHA512 + elif hash_name == "SHA-512/224": + return SHA512.new(truncate="224") + elif hash_name == "SHA-512/256": + return SHA512.new(truncate="256") + elif hash_name == "SHA3-512": + return SHA3_512 + elif hash_name == "SHA-384": + return SHA384 + elif hash_name == "SHA3-384": + return SHA3_384 + elif hash_name == "SHA-256": + return SHA256 + elif hash_name == "SHA3-256": + return SHA3_256 + elif hash_name == "SHA-224": + return SHA224 + elif hash_name == "SHA3-224": + return SHA3_224 + elif hash_name == "SHA-1": + return SHA1 + else: + raise ValueError("Unknown hash algorithm: " + hash_name) + + def filter_type(group): + type_name = group['type'] + if type_name not in ("RsassaPkcs1Verify", "RsassaPkcs1Generate"): + raise ValueError("Unknown type name " + type_name) + + result = load_test_vectors_wycheproof(("Signature", "wycheproof"), + filename, + "Wycheproof PKCS#1v1.5 signature (%s)" % filename, + group_tag={'rsa_key': filter_rsa, + 'hash_mod': filter_sha, + 'type': filter_type}) + return result + + def shortDescription(self): + return self._id + + def warn(self, tv): + if tv.warning and self._wycheproof_warnings: + import warnings + warnings.warn("Wycheproof warning: %s (%s)" % (self._id, tv.comment)) + + def test_verify(self, tv): + self._id = "Wycheproof RSA PKCS$#1 Test #" + str(tv.id) + + hashed_msg = tv.hash_module.new(tv.msg) + signer = pkcs1_15.new(tv.key) + try: + signature = signer.verify(hashed_msg, tv.sig) + except ValueError as e: + if tv.warning: + return + assert not tv.valid + else: + assert tv.valid + self.warn(tv) + + def runTest(self): + for tv in self.tv: + self.test_verify(tv) + + +def get_tests(config={}): + wycheproof_warnings = config.get('wycheproof_warnings') + + tests = [] + tests += list_test_cases(FIPS_PKCS1_Verify_Tests) + tests += list_test_cases(FIPS_PKCS1_Sign_Tests) + tests += list_test_cases(PKCS1_15_NoParams) + tests += list_test_cases(PKCS1_Legacy_Module_Tests) + tests += list_test_cases(PKCS1_All_Hashes_Tests) + tests += [ TestVectorsWycheproof(wycheproof_warnings) ] + + if config.get('slow_tests'): + tests += list_test_cases(FIPS_PKCS1_Verify_Tests_KAT) + tests += list_test_cases(FIPS_PKCS1_Sign_Tests_KAT) + + return tests + +if __name__ == '__main__': + suite = lambda: unittest.TestSuite(get_tests()) + unittest.main(defaultTest='suite') diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Signature/test_pss.py b/venv/Lib/site-packages/Cryptodome/SelfTest/Signature/test_pss.py new file mode 100644 index 0000000..c3b1ce5 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/SelfTest/Signature/test_pss.py @@ -0,0 +1,377 @@ +# =================================================================== +# +# Copyright (c) 2014, Legrandin +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# =================================================================== + +import unittest + +from Cryptodome.Util.py3compat import b, bchr +from Cryptodome.Util.number import bytes_to_long +from Cryptodome.Util.strxor import strxor +from Cryptodome.SelfTest.st_common import list_test_cases +from Cryptodome.SelfTest.loader import load_test_vectors, load_test_vectors_wycheproof + +from Cryptodome.Hash import SHA1, SHA224, SHA256, SHA384, SHA512 +from Cryptodome.PublicKey import RSA +from Cryptodome.Signature import pss +from Cryptodome.Signature import PKCS1_PSS + +from Cryptodome.Signature.pss import MGF1 + + +def load_hash_by_name(hash_name): + return __import__("Cryptodome.Hash." + hash_name, globals(), locals(), ["new"]) + + +class PRNG(object): + + def __init__(self, stream): + self.stream = stream + self.idx = 0 + + def __call__(self, rnd_size): + result = self.stream[self.idx:self.idx + rnd_size] + self.idx += rnd_size + return result + + +class PSS_Tests(unittest.TestCase): + + rsa_key = b'-----BEGIN RSA PRIVATE KEY-----\nMIIEowIBAAKCAQEAsvI34FgiTK8+txBvmooNGpNwk23YTU51dwNZi5yha3W4lA/Q\nvcZrDalkmD7ekWQwnduxVKa6pRSI13KBgeUOIqJoGXSWhntEtY3FEwvWOHW5AE7Q\njUzTzCiYT6TVaCcpa/7YLai+p6ai2g5f5Zfh4jSawa9uYeuggFygQq4IVW796MgV\nyqxYMM/arEj+/sKz3Viua9Rp9fFosertCYCX4DUTgW0mX9bwEnEOgjSI3pLOPXz1\n8vx+DRZS5wMCmwCUa0sKonLn3cAUPq+sGix7+eo7T0Z12MU8ud7IYVX/75r3cXiF\nPaYE2q8Le0kgOApIXbb+x74x0rNgyIh1yGygkwIDAQABAoIBABz4t1A0pLT6qHI2\nEIOaNz3mwhK0dZEqkz0GB1Dhtoax5ATgvKCFB98J3lYB08IBURe1snOsnMpOVUtg\naBRSM+QqnCUG6bnzKjAkuFP5liDE+oNQv1YpKp9CsUovuzdmI8Au3ewihl+ZTIN2\nUVNYMEOR1b5m+z2SSwWNOYsiJwpBrT7zkpdlDyjat7FiiPhMMIMXjhQFVxURMIcB\njUBtPzGvV/PG90cVDWi1wRGeeP1dDqti/jsnvykQ15KW1MqGrpeNKRmDdTy/Ucl1\nWIoYklKw3U456lgZ/rDTDB818+Tlnk35z4yF7d5ANPM8CKfqOPcnO1BCKVFzf4eq\n54wvUtkCgYEA1Zv2lp06l7rXMsvNtyYQjbFChezRDRnPwZmN4NCdRtTgGG1G0Ryd\nYz6WWoPGqZp0b4LAaaHd3W2GTcpXF8WXMKfMX1W+tMAxMozfsXRKMcHoypwuS5wT\nfJRXJCG4pvd57AB0iVUEJW2we+uGKU5Zxcx//id2nXGCpoRyViIplQsCgYEA1nVC\neHupHChht0Fh4N09cGqZHZzuwXjOUMzR3Vsfz+4WzVS3NvIgN4g5YgmQFOeKwo5y\niRq5yvubcNdFvf85eHWClg0zPAyxJCVUWigCrrOanGEhJo6re4idJvNVzu4Ucg0v\n6B3SJ1HsCda+ZSNz24bSyqRep8A+RoAaoVSFx5kCgYEAn3RvXPs9s+obnqWYiPF3\nRe5etE6Vt2vfNKwFxx6zaR6bsmBQjuUHcABWiHb6I71S0bMPI0tbrWGG8ibrYKl1\nNTLtUvVVCOS3VP7oNTWT9RTFTAnOXU7DFSo+6o/poWn3r36ff6zhDXeWWMr2OXtt\ndEQ1/2lCGEGVv+v61eVmmQUCgYABFHITPTwqwiFL1O5zPWnzyPWgaovhOYSAb6eW\n38CXQXGn8wdBJZL39J2lWrr4//l45VK6UgIhfYbY2JynSkO10ZGow8RARygVMILu\nOUlaK9lZdDvAf/NpGdUAvzTtZ9F+iYZ2OsA2JnlzyzsGM1l//3vMPWukmJk3ral0\nqoJJ8QKBgGRG3eVHnIegBbFVuMDp2NTcfuSuDVUQ1fGAwtPiFa8u81IodJnMk2pq\niXu2+0ytNA/M+SVrAnE2AgIzcaJbtr0p2srkuVM7KMWnG1vWFNjtXN8fAhf/joOv\nD+NmPL/N4uE57e40tbiU/H7KdyZaDt+5QiTmdhuyAe6CBjKsF2jy\n-----END RSA PRIVATE KEY-----' + msg = b'AAA' + tag = b'\x00[c5\xd8\xb0\x8b!D\x81\x83\x07\xc0\xdd\xb9\xb4\xb2`\x92\xe7\x02\xf1\xe1P\xea\xc3\xf0\xe3>\xddX5\xdd\x8e\xc5\x89\xef\xf3\xc2\xdc\xfeP\x02\x7f\x12+\xc9\xaf\xbb\xec\xfe\xb0\xa5\xb9\x08\x11P\x8fL\xee5\x9b\xb0k{=_\xd2\x14\xfb\x01R\xb7\xfe\x14}b\x03\x8d5Y\x89~}\xfc\xf2l\xd01-\xbd\xeb\x11\xcdV\x11\xe9l\x19k/o5\xa2\x0f\x15\xe7Q$\t=\xec\x1dAB\x19\xa5P\x9a\xaf\xa3G\x86"\xd6~\xf0j\xfcqkbs\x13\x84b\xe4\xbdm(\xed`\xa4F\xfb\x8f.\xe1\x8c)/_\x9eS\x98\xa4v\xb8\xdc\xfe\xf7/D\x18\x19\xb3T\x97:\xe2\x96s\xe8<\xa2\xb4\xb9\xf8/' + + def test_positive_1(self): + key = RSA.import_key(self.rsa_key) + h = SHA256.new(self.msg) + verifier = pss.new(key) + verifier.verify(h, self.tag) + + def test_negative_1(self): + key = RSA.import_key(self.rsa_key) + h = SHA256.new(self.msg + b'A') + verifier = pss.new(key) + tag = bytearray(self.tag) + self.assertRaises(ValueError, verifier.verify, h, tag) + + def test_negative_2(self): + key = RSA.import_key(self.rsa_key) + h = SHA256.new(self.msg) + verifier = pss.new(key, salt_bytes=1000) + tag = bytearray(self.tag) + self.assertRaises(ValueError, verifier.verify, h, tag) + + +class FIPS_PKCS1_Verify_Tests(unittest.TestCase): + + def shortDescription(self): + return "FIPS PKCS1 Tests (Verify)" + + def verify_positive(self, hashmod, message, public_key, salt, signature): + prng = PRNG(salt) + hashed = hashmod.new(message) + verifier = pss.new(public_key, salt_bytes=len(salt), rand_func=prng) + verifier.verify(hashed, signature) + + def verify_negative(self, hashmod, message, public_key, salt, signature): + prng = PRNG(salt) + hashed = hashmod.new(message) + verifier = pss.new(public_key, salt_bytes=len(salt), rand_func=prng) + self.assertRaises(ValueError, verifier.verify, hashed, signature) + + def test_can_sign(self): + test_public_key = RSA.generate(1024).public_key() + verifier = pss.new(test_public_key) + self.assertEqual(verifier.can_sign(), False) + + +class FIPS_PKCS1_Verify_Tests_KAT(unittest.TestCase): + pass + + +test_vectors_verify = load_test_vectors(("Signature", "PKCS1-PSS"), + "SigVerPSS_186-3.rsp", + "Signature Verification 186-3", + {'shaalg': lambda x: x, + 'result': lambda x: x}) or [] + + +for count, tv in enumerate(test_vectors_verify): + if isinstance(tv, str): + continue + if hasattr(tv, "n"): + modulus = tv.n + continue + if hasattr(tv, "p"): + continue + + hash_module = load_hash_by_name(tv.shaalg.upper()) + hash_obj = hash_module.new(tv.msg) + public_key = RSA.construct([bytes_to_long(x) for x in (modulus, tv.e)]) # type: ignore + if tv.saltval != b("\x00"): + prng = PRNG(tv.saltval) + verifier = pss.new(public_key, salt_bytes=len(tv.saltval), rand_func=prng) + else: + verifier = pss.new(public_key, salt_bytes=0) + + def positive_test(self, hash_obj=hash_obj, verifier=verifier, signature=tv.s): + verifier.verify(hash_obj, signature) + + def negative_test(self, hash_obj=hash_obj, verifier=verifier, signature=tv.s): + self.assertRaises(ValueError, verifier.verify, hash_obj, signature) + + if tv.result == 'p': + setattr(FIPS_PKCS1_Verify_Tests_KAT, "test_positive_%d" % count, positive_test) + else: + setattr(FIPS_PKCS1_Verify_Tests_KAT, "test_negative_%d" % count, negative_test) + + +class FIPS_PKCS1_Sign_Tests(unittest.TestCase): + + def shortDescription(self): + return "FIPS PKCS1 Tests (Sign)" + + def test_can_sign(self): + test_private_key = RSA.generate(1024) + signer = pss.new(test_private_key) + self.assertEqual(signer.can_sign(), True) + + +class FIPS_PKCS1_Sign_Tests_KAT(unittest.TestCase): + pass + + +test_vectors_sign = load_test_vectors(("Signature", "PKCS1-PSS"), + "SigGenPSS_186-2.txt", + "Signature Generation 186-2", + {'shaalg': lambda x: x}) or [] + +test_vectors_sign += load_test_vectors(("Signature", "PKCS1-PSS"), + "SigGenPSS_186-3.txt", + "Signature Generation 186-3", + {'shaalg': lambda x: x}) or [] + +for count, tv in enumerate(test_vectors_sign): + if isinstance(tv, str): + continue + if hasattr(tv, "n"): + modulus = tv.n + continue + if hasattr(tv, "e"): + private_key = RSA.construct([bytes_to_long(x) for x in (modulus, tv.e, tv.d)]) # type: ignore + continue + + hash_module = load_hash_by_name(tv.shaalg.upper()) + hash_obj = hash_module.new(tv.msg) + if tv.saltval != b("\x00"): + prng = PRNG(tv.saltval) + signer = pss.new(private_key, salt_bytes=len(tv.saltval), rand_func=prng) + else: + signer = pss.new(private_key, salt_bytes=0) + + def new_test(self, hash_obj=hash_obj, signer=signer, result=tv.s): + signature = signer.sign(hash_obj) + self.assertEqual(signature, result) + + setattr(FIPS_PKCS1_Sign_Tests_KAT, "test_%d" % count, new_test) + + +class PKCS1_Legacy_Module_Tests(unittest.TestCase): + """Verify that the legacy module Cryptodome.Signature.PKCS1_PSS + behaves as expected. The only difference is that the verify() + method returns True/False and does not raise exceptions.""" + + def shortDescription(self): + return "Test legacy Cryptodome.Signature.PKCS1_PSS" + + def runTest(self): + key = RSA.generate(1024) + hashed = SHA1.new(b("Test")) + good_signature = PKCS1_PSS.new(key).sign(hashed) + verifier = PKCS1_PSS.new(key.public_key()) + + self.assertEqual(verifier.verify(hashed, good_signature), True) + + # Flip a few bits in the signature + bad_signature = strxor(good_signature, bchr(1) * len(good_signature)) + self.assertEqual(verifier.verify(hashed, bad_signature), False) + + +class PKCS1_All_Hashes_Tests(unittest.TestCase): + + def shortDescription(self): + return "Test PKCS#1 PSS signature in combination with all hashes" + + def runTest(self): + + key = RSA.generate(1280) + signer = pss.new(key) + hash_names = ("MD2", "MD4", "MD5", "RIPEMD160", "SHA1", + "SHA224", "SHA256", "SHA384", "SHA512", + "SHA3_224", "SHA3_256", "SHA3_384", "SHA3_512") + + for name in hash_names: + hashed = load_hash_by_name(name).new(b("Test")) + signer.sign(hashed) + + from Cryptodome.Hash import BLAKE2b, BLAKE2s + for hash_size in (20, 32, 48, 64): + hashed_b = BLAKE2b.new(digest_bytes=hash_size, data=b("Test")) + signer.sign(hashed_b) + for hash_size in (16, 20, 28, 32): + hashed_s = BLAKE2s.new(digest_bytes=hash_size, data=b("Test")) + signer.sign(hashed_s) + + +def get_hash_module(hash_name): + if hash_name == "SHA-512": + hash_module = SHA512 + elif hash_name == "SHA-512/224": + hash_module = SHA512.new(truncate="224") + elif hash_name == "SHA-512/256": + hash_module = SHA512.new(truncate="256") + elif hash_name == "SHA-384": + hash_module = SHA384 + elif hash_name == "SHA-256": + hash_module = SHA256 + elif hash_name == "SHA-224": + hash_module = SHA224 + elif hash_name == "SHA-1": + hash_module = SHA1 + else: + raise ValueError("Unknown hash algorithm: " + hash_name) + return hash_module + + +class TestVectorsPSSWycheproof(unittest.TestCase): + + def __init__(self, wycheproof_warnings): + unittest.TestCase.__init__(self) + self._wycheproof_warnings = wycheproof_warnings + self._id = "None" + + def add_tests(self, filename): + + def filter_rsa(group): + return RSA.import_key(group['keyPem']) + + def filter_sha(group): + return get_hash_module(group['sha']) + + def filter_type(group): + type_name = group['type'] + if type_name not in ("RsassaPssVerify", ): + raise ValueError("Unknown type name " + type_name) + + def filter_slen(group): + return group['sLen'] + + def filter_mgf(group): + mgf = group['mgf'] + if mgf not in ("MGF1", ): + raise ValueError("Unknown MGF " + mgf) + mgf1_hash = get_hash_module(group['mgfSha']) + + def mgf(x, y, mh=mgf1_hash): + return MGF1(x, y, mh) + + return mgf + + result = load_test_vectors_wycheproof(("Signature", "wycheproof"), + filename, + "Wycheproof PSS signature (%s)" % filename, + group_tag={'key': filter_rsa, + 'hash_module': filter_sha, + 'sLen': filter_slen, + 'mgf': filter_mgf, + 'type': filter_type}) + return result + + def setUp(self): + self.tv = [] + self.add_tests("rsa_pss_2048_sha1_mgf1_20_test.json") + self.add_tests("rsa_pss_2048_sha256_mgf1_0_test.json") + self.add_tests("rsa_pss_2048_sha256_mgf1_32_test.json") + self.add_tests("rsa_pss_2048_sha512_256_mgf1_28_test.json") + self.add_tests("rsa_pss_2048_sha512_256_mgf1_32_test.json") + self.add_tests("rsa_pss_3072_sha256_mgf1_32_test.json") + self.add_tests("rsa_pss_4096_sha256_mgf1_32_test.json") + self.add_tests("rsa_pss_4096_sha512_mgf1_32_test.json") + self.add_tests("rsa_pss_misc_test.json") + + def shortDescription(self): + return self._id + + def warn(self, tv): + if tv.warning and self._wycheproof_warnings: + import warnings + warnings.warn("Wycheproof warning: %s (%s)" % (self._id, tv.comment)) + + def test_verify(self, tv): + self._id = "Wycheproof RSA PSS Test #%d (%s)" % (tv.id, tv.comment) + + hashed_msg = tv.hash_module.new(tv.msg) + signer = pss.new(tv.key, mask_func=tv.mgf, salt_bytes=tv.sLen) + try: + signature = signer.verify(hashed_msg, tv.sig) + except ValueError as e: + if tv.warning: + return + assert not tv.valid + else: + assert tv.valid + self.warn(tv) + + def runTest(self): + for tv in self.tv: + self.test_verify(tv) + + +def get_tests(config={}): + wycheproof_warnings = config.get('wycheproof_warnings') + + tests = [] + tests += list_test_cases(PSS_Tests) + tests += list_test_cases(FIPS_PKCS1_Verify_Tests) + tests += list_test_cases(FIPS_PKCS1_Sign_Tests) + tests += list_test_cases(PKCS1_Legacy_Module_Tests) + tests += list_test_cases(PKCS1_All_Hashes_Tests) + + if config.get('slow_tests'): + tests += list_test_cases(FIPS_PKCS1_Verify_Tests_KAT) + tests += list_test_cases(FIPS_PKCS1_Sign_Tests_KAT) + + tests += [TestVectorsPSSWycheproof(wycheproof_warnings)] + + return tests + + +if __name__ == '__main__': + def suite(): + return unittest.TestSuite(get_tests()) + unittest.main(defaultTest='suite') diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Util/__init__.py b/venv/Lib/site-packages/Cryptodome/SelfTest/Util/__init__.py new file mode 100644 index 0000000..e52c490 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/SelfTest/Util/__init__.py @@ -0,0 +1,46 @@ +# -*- coding: utf-8 -*- +# +# SelfTest/Util/__init__.py: Self-test for utility modules +# +# Written in 2008 by Dwayne C. Litzenberger +# +# =================================================================== +# The contents of this file are dedicated to the public domain. To +# the extent that dedication to the public domain is not available, +# everyone is granted a worldwide, perpetual, royalty-free, +# non-exclusive license to exercise all rights associated with the +# contents of this file for any purpose whatsoever. +# No rights are reserved. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# =================================================================== + +"""Self-test for utility modules""" + +__revision__ = "$Id$" + +import os + +def get_tests(config={}): + tests = [] + from Cryptodome.SelfTest.Util import test_number; tests += test_number.get_tests(config=config) + from Cryptodome.SelfTest.Util import test_Counter; tests += test_Counter.get_tests(config=config) + from Cryptodome.SelfTest.Util import test_Padding; tests += test_Padding.get_tests(config=config) + from Cryptodome.SelfTest.Util import test_strxor; tests += test_strxor.get_tests(config=config) + from Cryptodome.SelfTest.Util import test_asn1; tests += test_asn1.get_tests(config=config) + from Cryptodome.SelfTest.Util import test_rfc1751; tests += test_rfc1751.get_tests(config=config) + return tests + +if __name__ == '__main__': + import unittest + suite = lambda: unittest.TestSuite(get_tests()) + unittest.main(defaultTest='suite') + +# vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Util/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/SelfTest/Util/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000..e7bb4c9 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/SelfTest/Util/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Util/__pycache__/test_Counter.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/SelfTest/Util/__pycache__/test_Counter.cpython-312.pyc new file mode 100644 index 0000000..526bf71 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/SelfTest/Util/__pycache__/test_Counter.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Util/__pycache__/test_Padding.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/SelfTest/Util/__pycache__/test_Padding.cpython-312.pyc new file mode 100644 index 0000000..4309d13 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/SelfTest/Util/__pycache__/test_Padding.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Util/__pycache__/test_asn1.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/SelfTest/Util/__pycache__/test_asn1.cpython-312.pyc new file mode 100644 index 0000000..a1479bb Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/SelfTest/Util/__pycache__/test_asn1.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Util/__pycache__/test_number.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/SelfTest/Util/__pycache__/test_number.cpython-312.pyc new file mode 100644 index 0000000..51f184a Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/SelfTest/Util/__pycache__/test_number.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Util/__pycache__/test_rfc1751.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/SelfTest/Util/__pycache__/test_rfc1751.cpython-312.pyc new file mode 100644 index 0000000..5be9f96 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/SelfTest/Util/__pycache__/test_rfc1751.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Util/__pycache__/test_strxor.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/SelfTest/Util/__pycache__/test_strxor.cpython-312.pyc new file mode 100644 index 0000000..c5dc1ad Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/SelfTest/Util/__pycache__/test_strxor.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Util/test_Counter.py b/venv/Lib/site-packages/Cryptodome/SelfTest/Util/test_Counter.py new file mode 100644 index 0000000..0d1e089 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/SelfTest/Util/test_Counter.py @@ -0,0 +1,67 @@ +# -*- coding: utf-8 -*- +# +# SelfTest/Util/test_Counter: Self-test for the Cryptodome.Util.Counter module +# +# Written in 2009 by Dwayne C. Litzenberger +# +# =================================================================== +# The contents of this file are dedicated to the public domain. To +# the extent that dedication to the public domain is not available, +# everyone is granted a worldwide, perpetual, royalty-free, +# non-exclusive license to exercise all rights associated with the +# contents of this file for any purpose whatsoever. +# No rights are reserved. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# =================================================================== + +"""Self-tests for Cryptodome.Util.Counter""" + +from Cryptodome.Util.py3compat import * + +import unittest + +class CounterTests(unittest.TestCase): + def setUp(self): + global Counter + from Cryptodome.Util import Counter + + def test_BE(self): + """Big endian""" + c = Counter.new(128) + c = Counter.new(128, little_endian=False) + + def test_LE(self): + """Little endian""" + c = Counter.new(128, little_endian=True) + + def test_nbits(self): + c = Counter.new(nbits=128) + self.assertRaises(ValueError, Counter.new, 129) + + def test_prefix(self): + c = Counter.new(128, prefix=b("xx")) + + def test_suffix(self): + c = Counter.new(128, suffix=b("xx")) + + def test_iv(self): + c = Counter.new(128, initial_value=2) + self.assertRaises(ValueError, Counter.new, 16, initial_value=0x1FFFF) + +def get_tests(config={}): + from Cryptodome.SelfTest.st_common import list_test_cases + return list_test_cases(CounterTests) + +if __name__ == '__main__': + suite = lambda: unittest.TestSuite(get_tests()) + unittest.main(defaultTest='suite') + +# vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Util/test_Padding.py b/venv/Lib/site-packages/Cryptodome/SelfTest/Util/test_Padding.py new file mode 100644 index 0000000..a9c3eb6 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/SelfTest/Util/test_Padding.py @@ -0,0 +1,153 @@ +# +# SelfTest/Util/test_Padding.py: Self-test for padding functions +# +# =================================================================== +# +# Copyright (c) 2014, Legrandin +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# =================================================================== + +import unittest +from binascii import unhexlify as uh + +from Cryptodome.Util.py3compat import * +from Cryptodome.SelfTest.st_common import list_test_cases +from Cryptodome.Util.Padding import pad, unpad + +class PKCS7_Tests(unittest.TestCase): + + def test1(self): + padded = pad(b(""), 4) + self.assertTrue(padded == uh(b("04040404"))) + padded = pad(b(""), 4, 'pkcs7') + self.assertTrue(padded == uh(b("04040404"))) + back = unpad(padded, 4) + self.assertTrue(back == b("")) + + def test2(self): + padded = pad(uh(b("12345678")), 4) + self.assertTrue(padded == uh(b("1234567804040404"))) + back = unpad(padded, 4) + self.assertTrue(back == uh(b("12345678"))) + + def test3(self): + padded = pad(uh(b("123456")), 4) + self.assertTrue(padded == uh(b("12345601"))) + back = unpad(padded, 4) + self.assertTrue(back == uh(b("123456"))) + + def test4(self): + padded = pad(uh(b("1234567890")), 4) + self.assertTrue(padded == uh(b("1234567890030303"))) + back = unpad(padded, 4) + self.assertTrue(back == uh(b("1234567890"))) + + def testn1(self): + self.assertRaises(ValueError, pad, uh(b("12")), 4, 'pkcs8') + + def testn2(self): + self.assertRaises(ValueError, unpad, b("\0\0\0"), 4) + self.assertRaises(ValueError, unpad, b(""), 4) + + def testn3(self): + self.assertRaises(ValueError, unpad, b("123456\x02"), 4) + self.assertRaises(ValueError, unpad, b("123456\x00"), 4) + self.assertRaises(ValueError, unpad, b("123456\x05\x05\x05\x05\x05"), 4) + +class X923_Tests(unittest.TestCase): + + def test1(self): + padded = pad(b(""), 4, 'x923') + self.assertTrue(padded == uh(b("00000004"))) + back = unpad(padded, 4, 'x923') + self.assertTrue(back == b("")) + + def test2(self): + padded = pad(uh(b("12345678")), 4, 'x923') + self.assertTrue(padded == uh(b("1234567800000004"))) + back = unpad(padded, 4, 'x923') + self.assertTrue(back == uh(b("12345678"))) + + def test3(self): + padded = pad(uh(b("123456")), 4, 'x923') + self.assertTrue(padded == uh(b("12345601"))) + back = unpad(padded, 4, 'x923') + self.assertTrue(back == uh(b("123456"))) + + def test4(self): + padded = pad(uh(b("1234567890")), 4, 'x923') + self.assertTrue(padded == uh(b("1234567890000003"))) + back = unpad(padded, 4, 'x923') + self.assertTrue(back == uh(b("1234567890"))) + + def testn1(self): + self.assertRaises(ValueError, unpad, b("123456\x02"), 4, 'x923') + self.assertRaises(ValueError, unpad, b("123456\x00"), 4, 'x923') + self.assertRaises(ValueError, unpad, b("123456\x00\x00\x00\x00\x05"), 4, 'x923') + self.assertRaises(ValueError, unpad, b(""), 4, 'x923') + +class ISO7816_Tests(unittest.TestCase): + + def test1(self): + padded = pad(b(""), 4, 'iso7816') + self.assertTrue(padded == uh(b("80000000"))) + back = unpad(padded, 4, 'iso7816') + self.assertTrue(back == b("")) + + def test2(self): + padded = pad(uh(b("12345678")), 4, 'iso7816') + self.assertTrue(padded == uh(b("1234567880000000"))) + back = unpad(padded, 4, 'iso7816') + self.assertTrue(back == uh(b("12345678"))) + + def test3(self): + padded = pad(uh(b("123456")), 4, 'iso7816') + self.assertTrue(padded == uh(b("12345680"))) + back = unpad(padded, 4, 'iso7816') + self.assertTrue(back == uh(b("123456"))) + + def test4(self): + padded = pad(uh(b("1234567890")), 4, 'iso7816') + self.assertTrue(padded == uh(b("1234567890800000"))) + back = unpad(padded, 4, 'iso7816') + self.assertTrue(back == uh(b("1234567890"))) + + def testn1(self): + self.assertRaises(ValueError, unpad, b("123456\x81"), 4, 'iso7816') + self.assertRaises(ValueError, unpad, b(""), 4, 'iso7816') + +def get_tests(config={}): + tests = [] + tests += list_test_cases(PKCS7_Tests) + tests += list_test_cases(X923_Tests) + tests += list_test_cases(ISO7816_Tests) + return tests + +if __name__ == '__main__': + suite = lambda: unittest.TestSuite(get_tests()) + unittest.main(defaultTest='suite') + diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Util/test_asn1.py b/venv/Lib/site-packages/Cryptodome/SelfTest/Util/test_asn1.py new file mode 100644 index 0000000..811ac84 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/SelfTest/Util/test_asn1.py @@ -0,0 +1,851 @@ +# +# SelfTest/Util/test_asn.py: Self-test for the Cryptodome.Util.asn1 module +# +# =================================================================== +# +# Copyright (c) 2014, Legrandin +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# =================================================================== + +"""Self-tests for Cryptodome.Util.asn1""" + +import unittest + +from Cryptodome.Util.py3compat import * +from Cryptodome.Util.asn1 import (DerObject, DerSetOf, DerInteger, + DerBitString, + DerObjectId, DerNull, DerOctetString, + DerSequence, DerBoolean) + +class DerObjectTests(unittest.TestCase): + + def testObjInit1(self): + # Fail with invalid tag format (must be 1 byte) + self.assertRaises(ValueError, DerObject, b('\x00\x99')) + # Fail with invalid implicit tag (must be <0x1F) + self.assertRaises(ValueError, DerObject, 0x1F) + + # ------ + + def testObjEncode1(self): + # No payload + der = DerObject(b('\x02')) + self.assertEqual(der.encode(), b('\x02\x00')) + # Small payload (primitive) + der.payload = b('\x45') + self.assertEqual(der.encode(), b('\x02\x01\x45')) + # Invariant + self.assertEqual(der.encode(), b('\x02\x01\x45')) + # Initialize with numerical tag + der = DerObject(0x04) + der.payload = b('\x45') + self.assertEqual(der.encode(), b('\x04\x01\x45')) + # Initialize with constructed type + der = DerObject(b('\x10'), constructed=True) + self.assertEqual(der.encode(), b('\x30\x00')) + + def testObjEncode2(self): + # Initialize with payload + der = DerObject(0x03, b('\x12\x12')) + self.assertEqual(der.encode(), b('\x03\x02\x12\x12')) + + def testObjEncode3(self): + # Long payload + der = DerObject(b('\x10')) + der.payload = b("0")*128 + self.assertEqual(der.encode(), b('\x10\x81\x80' + "0"*128)) + + def testObjEncode4(self): + # Implicit tags (constructed) + der = DerObject(0x10, implicit=1, constructed=True) + der.payload = b('ppll') + self.assertEqual(der.encode(), b('\xa1\x04ppll')) + # Implicit tags (primitive) + der = DerObject(0x02, implicit=0x1E, constructed=False) + der.payload = b('ppll') + self.assertEqual(der.encode(), b('\x9E\x04ppll')) + + def testObjEncode5(self): + # Encode type with explicit tag + der = DerObject(0x10, explicit=5) + der.payload = b("xxll") + self.assertEqual(der.encode(), b("\xa5\x06\x10\x04xxll")) + + # ----- + + def testObjDecode1(self): + # Decode short payload + der = DerObject(0x02) + der.decode(b('\x02\x02\x01\x02')) + self.assertEqual(der.payload, b("\x01\x02")) + self.assertEqual(der._tag_octet, 0x02) + + def testObjDecode2(self): + # Decode long payload + der = DerObject(0x02) + der.decode(b('\x02\x81\x80' + "1"*128)) + self.assertEqual(der.payload, b("1")*128) + self.assertEqual(der._tag_octet, 0x02) + + def testObjDecode3(self): + # Decode payload with too much data gives error + der = DerObject(0x02) + self.assertRaises(ValueError, der.decode, b('\x02\x02\x01\x02\xFF')) + # Decode payload with too little data gives error + der = DerObject(0x02) + self.assertRaises(ValueError, der.decode, b('\x02\x02\x01')) + + def testObjDecode4(self): + # Decode implicit tag (primitive) + der = DerObject(0x02, constructed=False, implicit=0xF) + self.assertRaises(ValueError, der.decode, b('\x02\x02\x01\x02')) + der.decode(b('\x8F\x01\x00')) + self.assertEqual(der.payload, b('\x00')) + # Decode implicit tag (constructed) + der = DerObject(0x02, constructed=True, implicit=0xF) + self.assertRaises(ValueError, der.decode, b('\x02\x02\x01\x02')) + der.decode(b('\xAF\x01\x00')) + self.assertEqual(der.payload, b('\x00')) + + def testObjDecode5(self): + # Decode payload with unexpected tag gives error + der = DerObject(0x02) + self.assertRaises(ValueError, der.decode, b('\x03\x02\x01\x02')) + + def testObjDecode6(self): + # Arbitrary DER object + der = DerObject() + der.decode(b('\x65\x01\x88')) + self.assertEqual(der._tag_octet, 0x65) + self.assertEqual(der.payload, b('\x88')) + + def testObjDecode7(self): + # Decode explicit tag + der = DerObject(0x10, explicit=5) + der.decode(b("\xa5\x06\x10\x04xxll")) + self.assertEqual(der._inner_tag_octet, 0x10) + self.assertEqual(der.payload, b('xxll')) + + # Explicit tag may be 0 + der = DerObject(0x10, explicit=0) + der.decode(b("\xa0\x06\x10\x04xxll")) + self.assertEqual(der._inner_tag_octet, 0x10) + self.assertEqual(der.payload, b('xxll')) + + def testObjDecode8(self): + # Verify that decode returns the object + der = DerObject(0x02) + self.assertEqual(der, der.decode(b('\x02\x02\x01\x02'))) + +class DerIntegerTests(unittest.TestCase): + + def testInit1(self): + der = DerInteger(1) + self.assertEqual(der.encode(), b('\x02\x01\x01')) + + def testEncode1(self): + # Single-byte integers + # Value 0 + der = DerInteger(0) + self.assertEqual(der.encode(), b('\x02\x01\x00')) + # Value 1 + der = DerInteger(1) + self.assertEqual(der.encode(), b('\x02\x01\x01')) + # Value 127 + der = DerInteger(127) + self.assertEqual(der.encode(), b('\x02\x01\x7F')) + + def testEncode2(self): + # Multi-byte integers + # Value 128 + der = DerInteger(128) + self.assertEqual(der.encode(), b('\x02\x02\x00\x80')) + # Value 0x180 + der = DerInteger(0x180) + self.assertEqual(der.encode(), b('\x02\x02\x01\x80')) + # One very long integer + der = DerInteger(2**2048) + self.assertEqual(der.encode(), + b('\x02\x82\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00')) + + def testEncode3(self): + # Negative integers + # Value -1 + der = DerInteger(-1) + self.assertEqual(der.encode(), b('\x02\x01\xFF')) + # Value -128 + der = DerInteger(-128) + self.assertEqual(der.encode(), b('\x02\x01\x80')) + # Value + der = DerInteger(-87873) + self.assertEqual(der.encode(), b('\x02\x03\xFE\xA8\xBF')) + + def testEncode4(self): + # Explicit encoding + number = DerInteger(0x34, explicit=3) + self.assertEqual(number.encode(), b('\xa3\x03\x02\x01\x34')) + + # ----- + + def testDecode1(self): + # Single-byte integer + der = DerInteger() + # Value 0 + der.decode(b('\x02\x01\x00')) + self.assertEqual(der.value, 0) + # Value 1 + der.decode(b('\x02\x01\x01')) + self.assertEqual(der.value, 1) + # Value 127 + der.decode(b('\x02\x01\x7F')) + self.assertEqual(der.value, 127) + + def testDecode2(self): + # Multi-byte integer + der = DerInteger() + # Value 0x180L + der.decode(b('\x02\x02\x01\x80')) + self.assertEqual(der.value,0x180) + # One very long integer + der.decode( + b('\x02\x82\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00')) + self.assertEqual(der.value,2**2048) + + def testDecode3(self): + # Negative integer + der = DerInteger() + # Value -1 + der.decode(b('\x02\x01\xFF')) + self.assertEqual(der.value, -1) + # Value -32768 + der.decode(b('\x02\x02\x80\x00')) + self.assertEqual(der.value, -32768) + + def testDecode5(self): + # We still accept BER integer format + der = DerInteger() + # Redundant leading zeroes + der.decode(b('\x02\x02\x00\x01')) + self.assertEqual(der.value, 1) + # Redundant leading 0xFF + der.decode(b('\x02\x02\xFF\xFF')) + self.assertEqual(der.value, -1) + # Empty payload + der.decode(b('\x02\x00')) + self.assertEqual(der.value, 0) + + def testDecode6(self): + # Explicit encoding + number = DerInteger(explicit=3) + number.decode(b('\xa3\x03\x02\x01\x34')) + self.assertEqual(number.value, 0x34) + + def testDecode7(self): + # Verify decode returns the DerInteger + der = DerInteger() + self.assertEqual(der, der.decode(b('\x02\x01\x7F'))) + + ### + + def testStrict1(self): + number = DerInteger() + + number.decode(b'\x02\x02\x00\x01') + number.decode(b'\x02\x02\x00\x7F') + self.assertRaises(ValueError, number.decode, b'\x02\x02\x00\x01', strict=True) + self.assertRaises(ValueError, number.decode, b'\x02\x02\x00\x7F', strict=True) + + ### + + def testErrDecode1(self): + # Wide length field + der = DerInteger() + self.assertRaises(ValueError, der.decode, b('\x02\x81\x01\x01')) + + +class DerSequenceTests(unittest.TestCase): + + def testInit1(self): + der = DerSequence([1, DerInteger(2), b('0\x00')]) + self.assertEqual(der.encode(), b('0\x08\x02\x01\x01\x02\x01\x020\x00')) + + def testEncode1(self): + # Empty sequence + der = DerSequence() + self.assertEqual(der.encode(), b('0\x00')) + self.assertFalse(der.hasOnlyInts()) + # One single-byte integer (zero) + der.append(0) + self.assertEqual(der.encode(), b('0\x03\x02\x01\x00')) + self.assertEqual(der.hasInts(),1) + self.assertEqual(der.hasInts(False),1) + self.assertTrue(der.hasOnlyInts()) + self.assertTrue(der.hasOnlyInts(False)) + # Invariant + self.assertEqual(der.encode(), b('0\x03\x02\x01\x00')) + + def testEncode2(self): + # Indexing + der = DerSequence() + der.append(0) + der[0] = 1 + self.assertEqual(len(der),1) + self.assertEqual(der[0],1) + self.assertEqual(der[-1],1) + self.assertEqual(der.encode(), b('0\x03\x02\x01\x01')) + # + der[:] = [1] + self.assertEqual(len(der),1) + self.assertEqual(der[0],1) + self.assertEqual(der.encode(), b('0\x03\x02\x01\x01')) + + def testEncode3(self): + # One multi-byte integer (non-zero) + der = DerSequence() + der.append(0x180) + self.assertEqual(der.encode(), b('0\x04\x02\x02\x01\x80')) + + def testEncode4(self): + # One very long integer + der = DerSequence() + der.append(2**2048) + self.assertEqual(der.encode(), b('0\x82\x01\x05')+ + b('\x02\x82\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00')) + + def testEncode5(self): + der = DerSequence() + der += 1 + der += b('\x30\x00') + self.assertEqual(der.encode(), b('\x30\x05\x02\x01\x01\x30\x00')) + + def testEncode6(self): + # Two positive integers + der = DerSequence() + der.append(0x180) + der.append(0xFF) + self.assertEqual(der.encode(), b('0\x08\x02\x02\x01\x80\x02\x02\x00\xff')) + self.assertTrue(der.hasOnlyInts()) + self.assertTrue(der.hasOnlyInts(False)) + # Two mixed integers + der = DerSequence() + der.append(2) + der.append(-2) + self.assertEqual(der.encode(), b('0\x06\x02\x01\x02\x02\x01\xFE')) + self.assertEqual(der.hasInts(), 1) + self.assertEqual(der.hasInts(False), 2) + self.assertFalse(der.hasOnlyInts()) + self.assertTrue(der.hasOnlyInts(False)) + # + der.append(0x01) + der[1:] = [9,8] + self.assertEqual(len(der),3) + self.assertEqual(der[1:],[9,8]) + self.assertEqual(der[1:-1],[9]) + self.assertEqual(der.encode(), b('0\x09\x02\x01\x02\x02\x01\x09\x02\x01\x08')) + + def testEncode7(self): + # One integer and another type (already encoded) + der = DerSequence() + der.append(0x180) + der.append(b('0\x03\x02\x01\x05')) + self.assertEqual(der.encode(), b('0\x09\x02\x02\x01\x800\x03\x02\x01\x05')) + self.assertFalse(der.hasOnlyInts()) + + def testEncode8(self): + # One integer and another type (yet to encode) + der = DerSequence() + der.append(0x180) + der.append(DerSequence([5])) + self.assertEqual(der.encode(), b('0\x09\x02\x02\x01\x800\x03\x02\x01\x05')) + self.assertFalse(der.hasOnlyInts()) + + #### + + def testDecode1(self): + # Empty sequence + der = DerSequence() + der.decode(b('0\x00')) + self.assertEqual(len(der),0) + # One single-byte integer (zero) + der.decode(b('0\x03\x02\x01\x00')) + self.assertEqual(len(der),1) + self.assertEqual(der[0],0) + # Invariant + der.decode(b('0\x03\x02\x01\x00')) + self.assertEqual(len(der),1) + self.assertEqual(der[0],0) + + def testDecode2(self): + # One single-byte integer (non-zero) + der = DerSequence() + der.decode(b('0\x03\x02\x01\x7f')) + self.assertEqual(len(der),1) + self.assertEqual(der[0],127) + + def testDecode4(self): + # One very long integer + der = DerSequence() + der.decode(b('0\x82\x01\x05')+ + b('\x02\x82\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')+ + b('\x00\x00\x00\x00\x00\x00\x00\x00\x00')) + self.assertEqual(len(der),1) + self.assertEqual(der[0],2**2048) + + def testDecode6(self): + # Two integers + der = DerSequence() + der.decode(b('0\x08\x02\x02\x01\x80\x02\x02\x00\xff')) + self.assertEqual(len(der),2) + self.assertEqual(der[0],0x180) + self.assertEqual(der[1],0xFF) + + def testDecode7(self): + # One integer and 2 other types + der = DerSequence() + der.decode(b('0\x0A\x02\x02\x01\x80\x24\x02\xb6\x63\x12\x00')) + self.assertEqual(len(der),3) + self.assertEqual(der[0],0x180) + self.assertEqual(der[1],b('\x24\x02\xb6\x63')) + self.assertEqual(der[2],b('\x12\x00')) + + def testDecode8(self): + # Only 2 other types + der = DerSequence() + der.decode(b('0\x06\x24\x02\xb6\x63\x12\x00')) + self.assertEqual(len(der),2) + self.assertEqual(der[0],b('\x24\x02\xb6\x63')) + self.assertEqual(der[1],b('\x12\x00')) + self.assertEqual(der.hasInts(), 0) + self.assertEqual(der.hasInts(False), 0) + self.assertFalse(der.hasOnlyInts()) + self.assertFalse(der.hasOnlyInts(False)) + + def testDecode9(self): + # Verify that decode returns itself + der = DerSequence() + self.assertEqual(der, der.decode(b('0\x06\x24\x02\xb6\x63\x12\x00'))) + + ### + + def testErrDecode1(self): + # Not a sequence + der = DerSequence() + self.assertRaises(ValueError, der.decode, b('')) + self.assertRaises(ValueError, der.decode, b('\x00')) + self.assertRaises(ValueError, der.decode, b('\x30')) + + def testErrDecode2(self): + der = DerSequence() + # Too much data + self.assertRaises(ValueError, der.decode, b('\x30\x00\x00')) + + def testErrDecode3(self): + # Wrong length format + der = DerSequence() + # Missing length in sub-item + self.assertRaises(ValueError, der.decode, b('\x30\x04\x02\x01\x01\x00')) + # Valid BER, but invalid DER length + self.assertRaises(ValueError, der.decode, b('\x30\x81\x03\x02\x01\x01')) + self.assertRaises(ValueError, der.decode, b('\x30\x04\x02\x81\x01\x01')) + + def test_expected_nr_elements(self): + der_bin = DerSequence([1, 2, 3]).encode() + + DerSequence().decode(der_bin, nr_elements=3) + DerSequence().decode(der_bin, nr_elements=(2,3)) + self.assertRaises(ValueError, DerSequence().decode, der_bin, nr_elements=1) + self.assertRaises(ValueError, DerSequence().decode, der_bin, nr_elements=(4,5)) + + def test_expected_only_integers(self): + + der_bin1 = DerSequence([1, 2, 3]).encode() + der_bin2 = DerSequence([1, 2, DerSequence([3, 4])]).encode() + + DerSequence().decode(der_bin1, only_ints_expected=True) + DerSequence().decode(der_bin1, only_ints_expected=False) + DerSequence().decode(der_bin2, only_ints_expected=False) + self.assertRaises(ValueError, DerSequence().decode, der_bin2, only_ints_expected=True) + + +class DerOctetStringTests(unittest.TestCase): + + def testInit1(self): + der = DerOctetString(b('\xFF')) + self.assertEqual(der.encode(), b('\x04\x01\xFF')) + + def testEncode1(self): + # Empty sequence + der = DerOctetString() + self.assertEqual(der.encode(), b('\x04\x00')) + # Small payload + der.payload = b('\x01\x02') + self.assertEqual(der.encode(), b('\x04\x02\x01\x02')) + + #### + + def testDecode1(self): + # Empty sequence + der = DerOctetString() + der.decode(b('\x04\x00')) + self.assertEqual(der.payload, b('')) + # Small payload + der.decode(b('\x04\x02\x01\x02')) + self.assertEqual(der.payload, b('\x01\x02')) + + def testDecode2(self): + # Verify that decode returns the object + der = DerOctetString() + self.assertEqual(der, der.decode(b('\x04\x00'))) + + def testErrDecode1(self): + # No leftovers allowed + der = DerOctetString() + self.assertRaises(ValueError, der.decode, b('\x04\x01\x01\xff')) + +class DerNullTests(unittest.TestCase): + + def testEncode1(self): + der = DerNull() + self.assertEqual(der.encode(), b('\x05\x00')) + + #### + + def testDecode1(self): + # Empty sequence + der = DerNull() + self.assertEqual(der, der.decode(b('\x05\x00'))) + +class DerObjectIdTests(unittest.TestCase): + + def testInit1(self): + der = DerObjectId("1.1") + self.assertEqual(der.encode(), b'\x06\x01)') + + def testEncode1(self): + der = DerObjectId('1.2.840.113549.1.1.1') + self.assertEqual(der.encode(), b'\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01') + + der = DerObjectId() + der.value = '1.2.840.113549.1.1.1' + self.assertEqual(der.encode(), b'\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01') + + der = DerObjectId('2.999.1234') + self.assertEqual(der.encode(), b'\x06\x04\x88\x37\x89\x52') + + def testEncode2(self): + der = DerObjectId('3.4') + self.assertRaises(ValueError, der.encode) + + der = DerObjectId('1.40') + self.assertRaises(ValueError, der.encode) + + #### + + def testDecode1(self): + # Empty sequence + der = DerObjectId() + der.decode(b'\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01') + self.assertEqual(der.value, '1.2.840.113549.1.1.1') + + def testDecode2(self): + # Verify that decode returns the object + der = DerObjectId() + self.assertEqual(der, + der.decode(b'\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01')) + + def testDecode3(self): + der = DerObjectId() + der.decode(b'\x06\x09\x2A\x86\x48\x86\xF7\x0D\x01\x00\x01') + self.assertEqual(der.value, '1.2.840.113549.1.0.1') + + def testDecode4(self): + der = DerObjectId() + der.decode(b'\x06\x04\x88\x37\x89\x52') + self.assertEqual(der.value, '2.999.1234') + + +class DerBitStringTests(unittest.TestCase): + + def testInit1(self): + der = DerBitString(b("\xFF")) + self.assertEqual(der.encode(), b('\x03\x02\x00\xFF')) + + def testInit2(self): + der = DerBitString(DerInteger(1)) + self.assertEqual(der.encode(), b('\x03\x04\x00\x02\x01\x01')) + + def testEncode1(self): + # Empty sequence + der = DerBitString() + self.assertEqual(der.encode(), b('\x03\x01\x00')) + # Small payload + der = DerBitString(b('\x01\x02')) + self.assertEqual(der.encode(), b('\x03\x03\x00\x01\x02')) + # Small payload + der = DerBitString() + der.value = b('\x01\x02') + self.assertEqual(der.encode(), b('\x03\x03\x00\x01\x02')) + + #### + + def testDecode1(self): + # Empty sequence + der = DerBitString() + der.decode(b('\x03\x00')) + self.assertEqual(der.value, b('')) + # Small payload + der.decode(b('\x03\x03\x00\x01\x02')) + self.assertEqual(der.value, b('\x01\x02')) + + def testDecode2(self): + # Verify that decode returns the object + der = DerBitString() + self.assertEqual(der, der.decode(b('\x03\x00'))) + + +class DerSetOfTests(unittest.TestCase): + + def testInit1(self): + der = DerSetOf([DerInteger(1), DerInteger(2)]) + self.assertEqual(der.encode(), b('1\x06\x02\x01\x01\x02\x01\x02')) + + def testEncode1(self): + # Empty set + der = DerSetOf() + self.assertEqual(der.encode(), b('1\x00')) + # One single-byte integer (zero) + der.add(0) + self.assertEqual(der.encode(), b('1\x03\x02\x01\x00')) + # Invariant + self.assertEqual(der.encode(), b('1\x03\x02\x01\x00')) + + def testEncode2(self): + # Two integers + der = DerSetOf() + der.add(0x180) + der.add(0xFF) + self.assertEqual(der.encode(), b('1\x08\x02\x02\x00\xff\x02\x02\x01\x80')) + # Initialize with integers + der = DerSetOf([0x180, 0xFF]) + self.assertEqual(der.encode(), b('1\x08\x02\x02\x00\xff\x02\x02\x01\x80')) + + def testEncode3(self): + # One integer and another type (no matter what it is) + der = DerSetOf() + der.add(0x180) + self.assertRaises(ValueError, der.add, b('\x00\x02\x00\x00')) + + def testEncode4(self): + # Only non integers + der = DerSetOf() + der.add(b('\x01\x00')) + der.add(b('\x01\x01\x01')) + self.assertEqual(der.encode(), b('1\x05\x01\x00\x01\x01\x01')) + + #### + + def testDecode1(self): + # Empty sequence + der = DerSetOf() + der.decode(b('1\x00')) + self.assertEqual(len(der),0) + # One single-byte integer (zero) + der.decode(b('1\x03\x02\x01\x00')) + self.assertEqual(len(der),1) + self.assertEqual(list(der),[0]) + + def testDecode2(self): + # Two integers + der = DerSetOf() + der.decode(b('1\x08\x02\x02\x01\x80\x02\x02\x00\xff')) + self.assertEqual(len(der),2) + l = list(der) + self.assertTrue(0x180 in l) + self.assertTrue(0xFF in l) + + def testDecode3(self): + # One integer and 2 other types + der = DerSetOf() + #import pdb; pdb.set_trace() + self.assertRaises(ValueError, der.decode, + b('0\x0A\x02\x02\x01\x80\x24\x02\xb6\x63\x12\x00')) + + def testDecode4(self): + # Verify that decode returns the object + der = DerSetOf() + self.assertEqual(der, + der.decode(b('1\x08\x02\x02\x01\x80\x02\x02\x00\xff'))) + + ### + + def testErrDecode1(self): + # No leftovers allowed + der = DerSetOf() + self.assertRaises(ValueError, der.decode, + b('1\x08\x02\x02\x01\x80\x02\x02\x00\xff\xAA')) + + +class DerBooleanTests(unittest.TestCase): + + def testEncode1(self): + der = DerBoolean(False) + self.assertEqual(der.encode(), b'\x01\x01\x00') + + def testEncode2(self): + der = DerBoolean(True) + self.assertEqual(der.encode(), b'\x01\x01\xFF') + + def testEncode3(self): + der = DerBoolean(False, implicit=0x12) + self.assertEqual(der.encode(), b'\x92\x01\x00') + + def testEncode4(self): + der = DerBoolean(False, explicit=0x05) + self.assertEqual(der.encode(), b'\xA5\x03\x01\x01\x00') + #### + + def testDecode1(self): + der = DerBoolean() + der.decode(b'\x01\x01\x00') + self.assertEqual(der.value, False) + + def testDecode2(self): + der = DerBoolean() + der.decode(b'\x01\x01\xFF') + self.assertEqual(der.value, True) + + def testDecode3(self): + der = DerBoolean(implicit=0x12) + der.decode(b'\x92\x01\x00') + self.assertEqual(der.value, False) + + def testDecode4(self): + der = DerBoolean(explicit=0x05) + der.decode(b'\xA5\x03\x01\x01\x00') + self.assertEqual(der.value, False) + + def testErrorDecode1(self): + der = DerBoolean() + # Wrong tag + self.assertRaises(ValueError, der.decode, b'\x02\x01\x00') + + def testErrorDecode2(self): + der = DerBoolean() + # Payload too long + self.assertRaises(ValueError, der.decode, b'\x01\x01\x00\xFF') + + +def get_tests(config={}): + from Cryptodome.SelfTest.st_common import list_test_cases + listTests = [] + listTests += list_test_cases(DerObjectTests) + listTests += list_test_cases(DerIntegerTests) + listTests += list_test_cases(DerSequenceTests) + listTests += list_test_cases(DerOctetStringTests) + listTests += list_test_cases(DerNullTests) + listTests += list_test_cases(DerObjectIdTests) + listTests += list_test_cases(DerBitStringTests) + listTests += list_test_cases(DerSetOfTests) + listTests += list_test_cases(DerBooleanTests) + return listTests + +if __name__ == '__main__': + suite = lambda: unittest.TestSuite(get_tests()) + unittest.main(defaultTest='suite') + +# vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Util/test_number.py b/venv/Lib/site-packages/Cryptodome/SelfTest/Util/test_number.py new file mode 100644 index 0000000..8221443 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/SelfTest/Util/test_number.py @@ -0,0 +1,192 @@ +# -*- coding: utf-8 -*- +# +# SelfTest/Util/test_number.py: Self-test for parts of the Cryptodome.Util.number module +# +# Written in 2008 by Dwayne C. Litzenberger +# +# =================================================================== +# The contents of this file are dedicated to the public domain. To +# the extent that dedication to the public domain is not available, +# everyone is granted a worldwide, perpetual, royalty-free, +# non-exclusive license to exercise all rights associated with the +# contents of this file for any purpose whatsoever. +# No rights are reserved. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# =================================================================== + +"""Self-tests for (some of) Cryptodome.Util.number""" + +import math +import unittest + +from Cryptodome.Util.py3compat import * +from Cryptodome.SelfTest.st_common import list_test_cases + +from Cryptodome.Util import number +from Cryptodome.Util.number import long_to_bytes + + +class MyError(Exception): + """Dummy exception used for tests""" + +# NB: In some places, we compare tuples instead of just output values so that +# if any inputs cause a test failure, we'll be able to tell which ones. + +class MiscTests(unittest.TestCase): + + def test_ceil_div(self): + """Util.number.ceil_div""" + self.assertRaises(TypeError, number.ceil_div, "1", 1) + self.assertRaises(ZeroDivisionError, number.ceil_div, 1, 0) + self.assertRaises(ZeroDivisionError, number.ceil_div, -1, 0) + + # b = 1 + self.assertEqual(0, number.ceil_div(0, 1)) + self.assertEqual(1, number.ceil_div(1, 1)) + self.assertEqual(2, number.ceil_div(2, 1)) + self.assertEqual(3, number.ceil_div(3, 1)) + + # b = 2 + self.assertEqual(0, number.ceil_div(0, 2)) + self.assertEqual(1, number.ceil_div(1, 2)) + self.assertEqual(1, number.ceil_div(2, 2)) + self.assertEqual(2, number.ceil_div(3, 2)) + self.assertEqual(2, number.ceil_div(4, 2)) + self.assertEqual(3, number.ceil_div(5, 2)) + + # b = 3 + self.assertEqual(0, number.ceil_div(0, 3)) + self.assertEqual(1, number.ceil_div(1, 3)) + self.assertEqual(1, number.ceil_div(2, 3)) + self.assertEqual(1, number.ceil_div(3, 3)) + self.assertEqual(2, number.ceil_div(4, 3)) + self.assertEqual(2, number.ceil_div(5, 3)) + self.assertEqual(2, number.ceil_div(6, 3)) + self.assertEqual(3, number.ceil_div(7, 3)) + + # b = 4 + self.assertEqual(0, number.ceil_div(0, 4)) + self.assertEqual(1, number.ceil_div(1, 4)) + self.assertEqual(1, number.ceil_div(2, 4)) + self.assertEqual(1, number.ceil_div(3, 4)) + self.assertEqual(1, number.ceil_div(4, 4)) + self.assertEqual(2, number.ceil_div(5, 4)) + self.assertEqual(2, number.ceil_div(6, 4)) + self.assertEqual(2, number.ceil_div(7, 4)) + self.assertEqual(2, number.ceil_div(8, 4)) + self.assertEqual(3, number.ceil_div(9, 4)) + + def test_getPrime(self): + """Util.number.getPrime""" + self.assertRaises(ValueError, number.getPrime, -100) + self.assertRaises(ValueError, number.getPrime, 0) + self.assertRaises(ValueError, number.getPrime, 1) + + bits = 4 + for i in range(100): + x = number.getPrime(bits) + self.assertEqual(x >= (1 << bits - 1), 1) + self.assertEqual(x < (1 << bits), 1) + + bits = 512 + x = number.getPrime(bits) + self.assertNotEqual(x % 2, 0) + self.assertEqual(x >= (1 << bits - 1), 1) + self.assertEqual(x < (1 << bits), 1) + + def test_getStrongPrime(self): + """Util.number.getStrongPrime""" + self.assertRaises(ValueError, number.getStrongPrime, 256) + self.assertRaises(ValueError, number.getStrongPrime, 513) + bits = 512 + x = number.getStrongPrime(bits) + self.assertNotEqual(x % 2, 0) + self.assertEqual(x > (1 << bits-1)-1, 1) + self.assertEqual(x < (1 << bits), 1) + e = 2**16+1 + x = number.getStrongPrime(bits, e) + self.assertEqual(number.GCD(x-1, e), 1) + self.assertNotEqual(x % 2, 0) + self.assertEqual(x > (1 << bits-1)-1, 1) + self.assertEqual(x < (1 << bits), 1) + e = 2**16+2 + x = number.getStrongPrime(bits, e) + self.assertEqual(number.GCD((x-1)>>1, e), 1) + self.assertNotEqual(x % 2, 0) + self.assertEqual(x > (1 << bits-1)-1, 1) + self.assertEqual(x < (1 << bits), 1) + + def test_isPrime(self): + """Util.number.isPrime""" + self.assertEqual(number.isPrime(-3), False) # Regression test: negative numbers should not be prime + self.assertEqual(number.isPrime(-2), False) # Regression test: negative numbers should not be prime + self.assertEqual(number.isPrime(1), False) # Regression test: isPrime(1) caused some versions of PyCryptodome to crash. + self.assertEqual(number.isPrime(2), True) + self.assertEqual(number.isPrime(3), True) + self.assertEqual(number.isPrime(4), False) + self.assertEqual(number.isPrime(2**1279-1), True) + self.assertEqual(number.isPrime(-(2**1279-1)), False) # Regression test: negative numbers should not be prime + # test some known gmp pseudo-primes taken from + # http://www.trnicely.net/misc/mpzspsp.html + for composite in (43 * 127 * 211, 61 * 151 * 211, 15259 * 30517, + 346141 * 692281, 1007119 * 2014237, 3589477 * 7178953, + 4859419 * 9718837, 2730439 * 5460877, + 245127919 * 490255837, 963939391 * 1927878781, + 4186358431 * 8372716861, 1576820467 * 3153640933): + self.assertEqual(number.isPrime(int(composite)), False) + + def test_size(self): + self.assertEqual(number.size(2),2) + self.assertEqual(number.size(3),2) + self.assertEqual(number.size(0xa2),8) + self.assertEqual(number.size(0xa2ba40),8*3) + self.assertEqual(number.size(0xa2ba40ee07e3b2bd2f02ce227f36a195024486e49c19cb41bbbdfbba98b22b0e577c2eeaffa20d883a76e65e394c69d4b3c05a1e8fadda27edb2a42bc000fe888b9b32c22d15add0cd76b3e7936e19955b220dd17d4ea904b1ec102b2e4de7751222aa99151024c7cb41cc5ea21d00eeb41f7c800834d2c6e06bce3bce7ea9a5), 1024) + self.assertRaises(ValueError, number.size, -1) + + +class LongTests(unittest.TestCase): + + def test1(self): + self.assertEqual(long_to_bytes(0), b'\x00') + self.assertEqual(long_to_bytes(1), b'\x01') + self.assertEqual(long_to_bytes(0x100), b'\x01\x00') + self.assertEqual(long_to_bytes(0xFF00000000), b'\xFF\x00\x00\x00\x00') + self.assertEqual(long_to_bytes(0xFF00000000), b'\xFF\x00\x00\x00\x00') + self.assertEqual(long_to_bytes(0x1122334455667788), b'\x11\x22\x33\x44\x55\x66\x77\x88') + self.assertEqual(long_to_bytes(0x112233445566778899), b'\x11\x22\x33\x44\x55\x66\x77\x88\x99') + + def test2(self): + self.assertEqual(long_to_bytes(0, 1), b'\x00') + self.assertEqual(long_to_bytes(0, 2), b'\x00\x00') + self.assertEqual(long_to_bytes(1, 3), b'\x00\x00\x01') + self.assertEqual(long_to_bytes(65535, 2), b'\xFF\xFF') + self.assertEqual(long_to_bytes(65536, 2), b'\x00\x01\x00\x00') + self.assertEqual(long_to_bytes(0x100, 1), b'\x01\x00') + self.assertEqual(long_to_bytes(0xFF00000001, 6), b'\x00\xFF\x00\x00\x00\x01') + self.assertEqual(long_to_bytes(0xFF00000001, 8), b'\x00\x00\x00\xFF\x00\x00\x00\x01') + self.assertEqual(long_to_bytes(0xFF00000001, 10), b'\x00\x00\x00\x00\x00\xFF\x00\x00\x00\x01') + self.assertEqual(long_to_bytes(0xFF00000001, 11), b'\x00\x00\x00\x00\x00\x00\xFF\x00\x00\x00\x01') + + def test_err1(self): + self.assertRaises(ValueError, long_to_bytes, -1) + + +def get_tests(config={}): + tests = [] + tests += list_test_cases(MiscTests) + tests += list_test_cases(LongTests) + return tests + +if __name__ == '__main__': + suite = lambda: unittest.TestSuite(get_tests()) + unittest.main(defaultTest='suite') + +# vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Util/test_rfc1751.py b/venv/Lib/site-packages/Cryptodome/SelfTest/Util/test_rfc1751.py new file mode 100644 index 0000000..43b137d --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/SelfTest/Util/test_rfc1751.py @@ -0,0 +1,38 @@ +import unittest + +import binascii +from Cryptodome.Util.RFC1751 import key_to_english, english_to_key + + +class RFC1751_Tests(unittest.TestCase): + + def test1(self): + data = [ + ('EB33F77EE73D4053', 'TIDE ITCH SLOW REIN RULE MOT'), + ('CCAC2AED591056BE4F90FD441C534766', 'RASH BUSH MILK LOOK BAD BRIM AVID GAFF BAIT ROT POD LOVE'), + ('EFF81F9BFBC65350920CDD7416DE8009', 'TROD MUTE TAIL WARM CHAR KONG HAAG CITY BORE O TEAL AWL') + ] + + for key_hex, words in data: + key_bin = binascii.a2b_hex(key_hex) + + w2 = key_to_english(key_bin) + self.assertEqual(w2, words) + + k2 = english_to_key(words) + self.assertEqual(k2, key_bin) + + def test_error_key_to_english(self): + + self.assertRaises(ValueError, key_to_english, b'0' * 7) + + +def get_tests(config={}): + from Cryptodome.SelfTest.st_common import list_test_cases + tests = list_test_cases(RFC1751_Tests) + return tests + + +if __name__ == '__main__': + suite = lambda: unittest.TestSuite(get_tests()) + unittest.main(defaultTest='suite') diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/Util/test_strxor.py b/venv/Lib/site-packages/Cryptodome/SelfTest/Util/test_strxor.py new file mode 100644 index 0000000..6a96129 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/SelfTest/Util/test_strxor.py @@ -0,0 +1,280 @@ +# +# SelfTest/Util/test_strxor.py: Self-test for XORing +# +# =================================================================== +# +# Copyright (c) 2014, Legrandin +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# =================================================================== + +import unittest +from binascii import unhexlify, hexlify + +from Cryptodome.SelfTest.st_common import list_test_cases +from Cryptodome.Util.strxor import strxor, strxor_c + + +class StrxorTests(unittest.TestCase): + + def test1(self): + term1 = unhexlify(b"ff339a83e5cd4cdf5649") + term2 = unhexlify(b"383d4ba020573314395b") + result = unhexlify(b"c70ed123c59a7fcb6f12") + self.assertEqual(strxor(term1, term2), result) + self.assertEqual(strxor(term2, term1), result) + + def test2(self): + es = b"" + self.assertEqual(strxor(es, es), es) + + def test3(self): + term1 = unhexlify(b"ff339a83e5cd4cdf5649") + all_zeros = b"\x00" * len(term1) + self.assertEqual(strxor(term1, term1), all_zeros) + + def test_wrong_length(self): + term1 = unhexlify(b"ff339a83e5cd4cdf5649") + term2 = unhexlify(b"ff339a83e5cd4cdf564990") + self.assertRaises(ValueError, strxor, term1, term2) + + def test_bytearray(self): + term1 = unhexlify(b"ff339a83e5cd4cdf5649") + term1_ba = bytearray(term1) + term2 = unhexlify(b"383d4ba020573314395b") + result = unhexlify(b"c70ed123c59a7fcb6f12") + + self.assertEqual(strxor(term1_ba, term2), result) + + def test_memoryview(self): + term1 = unhexlify(b"ff339a83e5cd4cdf5649") + term1_mv = memoryview(term1) + term2 = unhexlify(b"383d4ba020573314395b") + result = unhexlify(b"c70ed123c59a7fcb6f12") + + self.assertEqual(strxor(term1_mv, term2), result) + + def test_output_bytearray(self): + """Verify result can be stored in pre-allocated memory""" + + term1 = unhexlify(b"ff339a83e5cd4cdf5649") + term2 = unhexlify(b"383d4ba020573314395b") + original_term1 = term1[:] + original_term2 = term2[:] + expected_xor = unhexlify(b"c70ed123c59a7fcb6f12") + output = bytearray(len(term1)) + + result = strxor(term1, term2, output=output) + + self.assertEqual(result, None) + self.assertEqual(output, expected_xor) + self.assertEqual(term1, original_term1) + self.assertEqual(term2, original_term2) + + def test_output_memoryview(self): + """Verify result can be stored in pre-allocated memory""" + + term1 = unhexlify(b"ff339a83e5cd4cdf5649") + term2 = unhexlify(b"383d4ba020573314395b") + original_term1 = term1[:] + original_term2 = term2[:] + expected_xor = unhexlify(b"c70ed123c59a7fcb6f12") + output = memoryview(bytearray(len(term1))) + + result = strxor(term1, term2, output=output) + + self.assertEqual(result, None) + self.assertEqual(output, expected_xor) + self.assertEqual(term1, original_term1) + self.assertEqual(term2, original_term2) + + def test_output_overlapping_bytearray(self): + """Verify result can be stored in overlapping memory""" + + term1 = bytearray(unhexlify(b"ff339a83e5cd4cdf5649")) + term2 = unhexlify(b"383d4ba020573314395b") + original_term2 = term2[:] + expected_xor = unhexlify(b"c70ed123c59a7fcb6f12") + + result = strxor(term1, term2, output=term1) + + self.assertEqual(result, None) + self.assertEqual(term1, expected_xor) + self.assertEqual(term2, original_term2) + + def test_output_overlapping_memoryview(self): + """Verify result can be stored in overlapping memory""" + + term1 = memoryview(bytearray(unhexlify(b"ff339a83e5cd4cdf5649"))) + term2 = unhexlify(b"383d4ba020573314395b") + original_term2 = term2[:] + expected_xor = unhexlify(b"c70ed123c59a7fcb6f12") + + result = strxor(term1, term2, output=term1) + + self.assertEqual(result, None) + self.assertEqual(term1, expected_xor) + self.assertEqual(term2, original_term2) + + def test_output_ro_bytes(self): + """Verify result cannot be stored in read-only memory""" + + term1 = unhexlify(b"ff339a83e5cd4cdf5649") + term2 = unhexlify(b"383d4ba020573314395b") + + self.assertRaises(TypeError, strxor, term1, term2, output=term1) + + def test_output_ro_memoryview(self): + """Verify result cannot be stored in read-only memory""" + + term1 = memoryview(unhexlify(b"ff339a83e5cd4cdf5649")) + term2 = unhexlify(b"383d4ba020573314395b") + + self.assertRaises(TypeError, strxor, term1, term2, output=term1) + + def test_output_incorrect_length(self): + """Verify result cannot be stored in memory of incorrect length""" + + term1 = unhexlify(b"ff339a83e5cd4cdf5649") + term2 = unhexlify(b"383d4ba020573314395b") + output = bytearray(len(term1) - 1) + + self.assertRaises(ValueError, strxor, term1, term2, output=output) + + +class Strxor_cTests(unittest.TestCase): + + def test1(self): + term1 = unhexlify(b"ff339a83e5cd4cdf5649") + result = unhexlify(b"be72dbc2a48c0d9e1708") + self.assertEqual(strxor_c(term1, 65), result) + + def test2(self): + term1 = unhexlify(b"ff339a83e5cd4cdf5649") + self.assertEqual(strxor_c(term1, 0), term1) + + def test3(self): + self.assertEqual(strxor_c(b"", 90), b"") + + def test_wrong_range(self): + term1 = unhexlify(b"ff339a83e5cd4cdf5649") + self.assertRaises(ValueError, strxor_c, term1, -1) + self.assertRaises(ValueError, strxor_c, term1, 256) + + def test_bytearray(self): + term1 = unhexlify(b"ff339a83e5cd4cdf5649") + term1_ba = bytearray(term1) + result = unhexlify(b"be72dbc2a48c0d9e1708") + + self.assertEqual(strxor_c(term1_ba, 65), result) + + def test_memoryview(self): + term1 = unhexlify(b"ff339a83e5cd4cdf5649") + term1_mv = memoryview(term1) + result = unhexlify(b"be72dbc2a48c0d9e1708") + + self.assertEqual(strxor_c(term1_mv, 65), result) + + def test_output_bytearray(self): + term1 = unhexlify(b"ff339a83e5cd4cdf5649") + original_term1 = term1[:] + expected_result = unhexlify(b"be72dbc2a48c0d9e1708") + output = bytearray(len(term1)) + + result = strxor_c(term1, 65, output=output) + + self.assertEqual(result, None) + self.assertEqual(output, expected_result) + self.assertEqual(term1, original_term1) + + def test_output_memoryview(self): + term1 = unhexlify(b"ff339a83e5cd4cdf5649") + original_term1 = term1[:] + expected_result = unhexlify(b"be72dbc2a48c0d9e1708") + output = memoryview(bytearray(len(term1))) + + result = strxor_c(term1, 65, output=output) + + self.assertEqual(result, None) + self.assertEqual(output, expected_result) + self.assertEqual(term1, original_term1) + + def test_output_overlapping_bytearray(self): + """Verify result can be stored in overlapping memory""" + + term1 = bytearray(unhexlify(b"ff339a83e5cd4cdf5649")) + expected_xor = unhexlify(b"be72dbc2a48c0d9e1708") + + result = strxor_c(term1, 65, output=term1) + + self.assertEqual(result, None) + self.assertEqual(term1, expected_xor) + + def test_output_overlapping_memoryview(self): + """Verify result can be stored in overlapping memory""" + + term1 = memoryview(bytearray(unhexlify(b"ff339a83e5cd4cdf5649"))) + expected_xor = unhexlify(b"be72dbc2a48c0d9e1708") + + result = strxor_c(term1, 65, output=term1) + + self.assertEqual(result, None) + self.assertEqual(term1, expected_xor) + + def test_output_ro_bytes(self): + """Verify result cannot be stored in read-only memory""" + + term1 = unhexlify(b"ff339a83e5cd4cdf5649") + + self.assertRaises(TypeError, strxor_c, term1, 65, output=term1) + + def test_output_ro_memoryview(self): + """Verify result cannot be stored in read-only memory""" + + term1 = memoryview(unhexlify(b"ff339a83e5cd4cdf5649")) + term2 = unhexlify(b"383d4ba020573314395b") + + self.assertRaises(TypeError, strxor_c, term1, 65, output=term1) + + def test_output_incorrect_length(self): + """Verify result cannot be stored in memory of incorrect length""" + + term1 = unhexlify(b"ff339a83e5cd4cdf5649") + output = bytearray(len(term1) - 1) + + self.assertRaises(ValueError, strxor_c, term1, 65, output=output) + + +def get_tests(config={}): + tests = [] + tests += list_test_cases(StrxorTests) + tests += list_test_cases(Strxor_cTests) + return tests + + +if __name__ == '__main__': + suite = lambda: unittest.TestSuite(get_tests()) + unittest.main(defaultTest='suite') diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/__init__.py b/venv/Lib/site-packages/Cryptodome/SelfTest/__init__.py new file mode 100644 index 0000000..09bb48c --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/SelfTest/__init__.py @@ -0,0 +1,102 @@ +# -*- coding: utf-8 -*- +# +# SelfTest/__init__.py: Self-test for PyCrypto +# +# Written in 2008 by Dwayne C. Litzenberger +# +# =================================================================== +# The contents of this file are dedicated to the public domain. To +# the extent that dedication to the public domain is not available, +# everyone is granted a worldwide, perpetual, royalty-free, +# non-exclusive license to exercise all rights associated with the +# contents of this file for any purpose whatsoever. +# No rights are reserved. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# =================================================================== + +"""Self tests + +These tests should perform quickly and can ideally be used every time an +application runs. +""" + +import sys +import unittest +from importlib import import_module +from Cryptodome.Util.py3compat import StringIO + + +class SelfTestError(Exception): + def __init__(self, message, result): + Exception.__init__(self, message, result) + self.message = message + self.result = result + + +def run(module=None, verbosity=0, stream=None, tests=None, config=None, **kwargs): + """Execute self-tests. + + This raises SelfTestError if any test is unsuccessful. + + You may optionally pass in a sub-module of SelfTest if you only want to + perform some of the tests. For example, the following would test only the + hash modules: + + Cryptodome.SelfTest.run(Cryptodome.SelfTest.Hash) + + """ + + if config is None: + config = {} + suite = unittest.TestSuite() + if module is None: + if tests is None: + tests = get_tests(config=config) + suite.addTests(tests) + else: + if tests is None: + suite.addTests(module.get_tests(config=config)) + else: + raise ValueError("'module' and 'tests' arguments are mutually exclusive") + if stream is None: + kwargs['stream'] = StringIO() + else: + kwargs['stream'] = stream + runner = unittest.TextTestRunner(verbosity=verbosity, **kwargs) + result = runner.run(suite) + if not result.wasSuccessful(): + if stream is None: + sys.stderr.write(kwargs['stream'].getvalue()) + raise SelfTestError("Self-test failed", result) + return result + + +def get_tests(config={}): + tests = [] + + module_names = [ + "Cipher", "Hash", "Protocol", "PublicKey", "Random", + "Util", "Signature", "IO", "Math", + ] + + for name in module_names: + module = import_module("Cryptodome.SelfTest." + name) + tests += module.get_tests(config=config) + + return tests + + +if __name__ == '__main__': + def suite(): + return unittest.TestSuite(get_tests()) + unittest.main(defaultTest='suite') + +# vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/__main__.py b/venv/Lib/site-packages/Cryptodome/SelfTest/__main__.py new file mode 100644 index 0000000..242d781 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/SelfTest/__main__.py @@ -0,0 +1,43 @@ +#! /usr/bin/env python +# +# __main__.py : Stand-along loader for PyCryptodome test suite +# +# =================================================================== +# The contents of this file are dedicated to the public domain. To +# the extent that dedication to the public domain is not available, +# everyone is granted a worldwide, perpetual, royalty-free, +# non-exclusive license to exercise all rights associated with the +# contents of this file for any purpose whatsoever. +# No rights are reserved. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# =================================================================== + +from __future__ import print_function + +import sys + +from Cryptodome import SelfTest + +slow_tests = not ("--skip-slow-tests" in sys.argv) +if not slow_tests: + print("Skipping slow tests") + +wycheproof_warnings = "--wycheproof-warnings" in sys.argv +if wycheproof_warnings: + print("Printing Wycheproof warnings") + +if "-v" in sys.argv: + verbosity=2 +else: + verbosity=1 + +config = {'slow_tests': slow_tests, 'wycheproof_warnings': wycheproof_warnings} +SelfTest.run(stream=sys.stdout, verbosity=verbosity, config=config) diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/SelfTest/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000..8946973 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/SelfTest/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/__pycache__/__main__.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/SelfTest/__pycache__/__main__.cpython-312.pyc new file mode 100644 index 0000000..6c4efdd Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/SelfTest/__pycache__/__main__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/__pycache__/loader.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/SelfTest/__pycache__/loader.cpython-312.pyc new file mode 100644 index 0000000..1413447 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/SelfTest/__pycache__/loader.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/__pycache__/st_common.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/SelfTest/__pycache__/st_common.cpython-312.pyc new file mode 100644 index 0000000..77f785e Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/SelfTest/__pycache__/st_common.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/loader.py b/venv/Lib/site-packages/Cryptodome/SelfTest/loader.py new file mode 100644 index 0000000..8699c3d --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/SelfTest/loader.py @@ -0,0 +1,250 @@ +# =================================================================== +# +# Copyright (c) 2016, Legrandin +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# =================================================================== + +import os +import re +import json +import errno +import binascii +import warnings +from binascii import unhexlify +from Cryptodome.Util.py3compat import FileNotFoundError + + +try: + import pycryptodome_test_vectors # type: ignore + test_vectors_available = True +except ImportError: + test_vectors_available = False + + +def _load_tests(dir_comps, file_in, description, conversions): + """Load and parse a test vector file + + Return a list of objects, one per group of adjacent + KV lines or for a single line in the form "[.*]". + + For a group of lines, the object has one attribute per line. + """ + + line_number = 0 + results = [] + + class TestVector(object): + def __init__(self, description, count): + self.desc = description + self.count = count + self.others = [] + + test_vector = None + count = 0 + new_group = True + + while True: + line_number += 1 + line = file_in.readline() + if not line: + if test_vector is not None: + results.append(test_vector) + break + line = line.strip() + + # Skip comments and empty lines + if line.startswith('#') or not line: + new_group = True + continue + + if line.startswith("["): + if test_vector is not None: + results.append(test_vector) + test_vector = None + results.append(line) + continue + + if new_group: + count += 1 + new_group = False + if test_vector is not None: + results.append(test_vector) + test_vector = TestVector("%s (#%d)" % (description, count), count) + + res = re.match("([A-Za-z0-9]+) = ?(.*)", line) + if not res: + test_vector.others += [line] + else: + token = res.group(1).lower() + data = res.group(2).lower() + + conversion = conversions.get(token, None) + if conversion is None: + if len(data) % 2 != 0: + data = "0" + data + setattr(test_vector, token, binascii.unhexlify(data)) + else: + setattr(test_vector, token, conversion(data)) + + # This line is ignored + return results + + +def load_test_vectors(dir_comps, file_name, description, conversions): + """Load and parse a test vector file, formatted using the NIST style. + + Args: + dir_comps (list of strings): + The path components under the ``pycryptodome_test_vectors`` package. + For instance ``("Cipher", "AES")``. + file_name (string): + The name of the file with the test vectors. + description (string): + A description applicable to the test vectors in the file. + conversions (dictionary): + The dictionary contains functions. + Values in the file that have an entry in this dictionary + will be converted usign the matching function. + Otherwise, values will be considered as hexadecimal and + converted to binary. + + Returns: + A list of test vector objects. + + The file is formatted in the following way: + + - Lines starting with "#" are comments and will be ignored. + - Each test vector is a sequence of 1 or more adjacent lines, where + each lines is an assignement. + - Test vectors are separated by an empty line, a comment, or + a line starting with "[". + + A test vector object has the following attributes: + + - desc (string): description + - counter (int): the order of the test vector in the file (from 1) + - others (list): zero or more lines of the test vector that were not assignments + - left-hand side of each assignment (lowercase): the value of the + assignement, either converted or bytes. + """ + + results = None + + try: + if not test_vectors_available: + raise FileNotFoundError(errno.ENOENT, + os.strerror(errno.ENOENT), + file_name) + + description = "%s test (%s)" % (description, file_name) + + init_dir = os.path.dirname(pycryptodome_test_vectors.__file__) + full_file_name = os.path.join(os.path.join(init_dir, *dir_comps), file_name) + with open(full_file_name) as file_in: + results = _load_tests(dir_comps, file_in, description, conversions) + + except FileNotFoundError: + warnings.warn("Warning: skipping extended tests for " + description, + UserWarning, + stacklevel=2) + + return results + + +def load_test_vectors_wycheproof(dir_comps, file_name, description, + root_tag={}, group_tag={}, unit_tag={}): + + result = [] + try: + if not test_vectors_available: + raise FileNotFoundError(errno.ENOENT, + os.strerror(errno.ENOENT), + file_name) + + init_dir = os.path.dirname(pycryptodome_test_vectors.__file__) + full_file_name = os.path.join(os.path.join(init_dir, *dir_comps), file_name) + with open(full_file_name) as file_in: + tv_tree = json.load(file_in) + + except FileNotFoundError: + warnings.warn("Warning: skipping extended tests for " + description, + UserWarning, + stacklevel=2) + return result + + class TestVector(object): + pass + + # Unique attributes that will be converted from + # hexadecimal to binary, unless the attribute is + # listed in the unit_tag dict + unit_attr_hex = {'key', 'iv', 'aad', 'msg', 'ct', 'tag', 'label', + 'ikm', 'salt', 'info', 'okm', 'sig', 'public', + 'shared'} + unit_attr_hex -= set(unit_tag.keys()) + + common_root = {} + for k, v in root_tag.items(): + common_root[k] = v(tv_tree) + + for group in tv_tree['testGroups']: + + common_group = {} + for k, v in group_tag.items(): + common_group[k] = v(group) + + for test in group['tests']: + tv = TestVector() + + for k, v in common_root.items(): + setattr(tv, k, v) + for k, v in common_group.items(): + setattr(tv, k, v) + + tv.id = test['tcId'] + tv.comment = test['comment'] + for attr in unit_attr_hex: + if attr in test: + try: + setattr(tv, attr, unhexlify(test[attr])) + except binascii.Error: + raise ValueError("Error decoding attribute '%s' (tcId=%s, file %s)" % (attr, tv.id, file_name)) + tv.filename = file_name + + for k, v in unit_tag.items(): + setattr(tv, k, v(test)) + + tv.valid = test['result'] != "invalid" + tv.warning = test['result'] == "acceptable" + tv.flags = test.get('flags') + + tv.filename = file_name + + result.append(tv) + + return result + diff --git a/venv/Lib/site-packages/Cryptodome/SelfTest/st_common.py b/venv/Lib/site-packages/Cryptodome/SelfTest/st_common.py new file mode 100644 index 0000000..3565251 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/SelfTest/st_common.py @@ -0,0 +1,55 @@ +# -*- coding: utf-8 -*- +# +# SelfTest/st_common.py: Common functions for SelfTest modules +# +# Written in 2008 by Dwayne C. Litzenberger +# +# =================================================================== +# The contents of this file are dedicated to the public domain. To +# the extent that dedication to the public domain is not available, +# everyone is granted a worldwide, perpetual, royalty-free, +# non-exclusive license to exercise all rights associated with the +# contents of this file for any purpose whatsoever. +# No rights are reserved. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# =================================================================== + +"""Common functions for SelfTest modules""" + +import unittest +import binascii +from Cryptodome.Util.py3compat import b + + +def list_test_cases(class_): + """Return a list of TestCase instances given a TestCase class + + This is useful when you have defined test* methods on your TestCase class. + """ + return unittest.TestLoader().loadTestsFromTestCase(class_) + +def strip_whitespace(s): + """Remove whitespace from a text or byte string""" + if isinstance(s,str): + return b("".join(s.split())) + else: + return b("").join(s.split()) + +def a2b_hex(s): + """Convert hexadecimal to binary, ignoring whitespace""" + return binascii.a2b_hex(strip_whitespace(s)) + +def b2a_hex(s): + """Convert binary to hexadecimal""" + # For completeness + return binascii.b2a_hex(s) + +# vim:set ts=4 sw=4 sts=4 expandtab: diff --git a/venv/Lib/site-packages/Cryptodome/Signature/DSS.py b/venv/Lib/site-packages/Cryptodome/Signature/DSS.py new file mode 100644 index 0000000..97d9c85 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Signature/DSS.py @@ -0,0 +1,403 @@ +# +# Signature/DSS.py : DSS.py +# +# =================================================================== +# +# Copyright (c) 2014, Legrandin +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# =================================================================== + +from Cryptodome.Util.asn1 import DerSequence +from Cryptodome.Util.number import long_to_bytes +from Cryptodome.Math.Numbers import Integer + +from Cryptodome.Hash import HMAC +from Cryptodome.PublicKey.ECC import EccKey +from Cryptodome.PublicKey.DSA import DsaKey + +__all__ = ['DssSigScheme', 'new'] + + +class DssSigScheme(object): + """A (EC)DSA signature object. + Do not instantiate directly. + Use :func:`Cryptodome.Signature.DSS.new`. + """ + + def __init__(self, key, encoding, order): + """Create a new Digital Signature Standard (DSS) object. + + Do not instantiate this object directly, + use `Cryptodome.Signature.DSS.new` instead. + """ + + self._key = key + self._encoding = encoding + self._order = order + + self._order_bits = self._order.size_in_bits() + self._order_bytes = (self._order_bits - 1) // 8 + 1 + + def can_sign(self): + """Return ``True`` if this signature object can be used + for signing messages.""" + + return self._key.has_private() + + def _compute_nonce(self, msg_hash): + raise NotImplementedError("To be provided by subclasses") + + def _valid_hash(self, msg_hash): + raise NotImplementedError("To be provided by subclasses") + + def sign(self, msg_hash): + """Compute the DSA/ECDSA signature of a message. + + Args: + msg_hash (hash object): + The hash that was carried out over the message. + The object belongs to the :mod:`Cryptodome.Hash` package. + Under mode ``'fips-186-3'``, the hash must be a FIPS + approved secure hash (SHA-2 or SHA-3). + + :return: The signature as ``bytes`` + :raise ValueError: if the hash algorithm is incompatible to the (EC)DSA key + :raise TypeError: if the (EC)DSA key has no private half + """ + + if not self._key.has_private(): + raise TypeError("Private key is needed to sign") + + if not self._valid_hash(msg_hash): + raise ValueError("Hash is not sufficiently strong") + + # Generate the nonce k (critical!) + nonce = self._compute_nonce(msg_hash) + + # Perform signature using the raw API + z = Integer.from_bytes(msg_hash.digest()[:self._order_bytes]) + sig_pair = self._key._sign(z, nonce) + + # Encode the signature into a single byte string + if self._encoding == 'binary': + output = b"".join([long_to_bytes(x, self._order_bytes) + for x in sig_pair]) + else: + # Dss-sig ::= SEQUENCE { + # r INTEGER, + # s INTEGER + # } + # Ecdsa-Sig-Value ::= SEQUENCE { + # r INTEGER, + # s INTEGER + # } + output = DerSequence(sig_pair).encode() + + return output + + def verify(self, msg_hash, signature): + """Check if a certain (EC)DSA signature is authentic. + + Args: + msg_hash (hash object): + The hash that was carried out over the message. + This is an object belonging to the :mod:`Cryptodome.Hash` module. + Under mode ``'fips-186-3'``, the hash must be a FIPS + approved secure hash (SHA-2 or SHA-3). + + signature (``bytes``): + The signature that needs to be validated. + + :raise ValueError: if the signature is not authentic + """ + + if not self._valid_hash(msg_hash): + raise ValueError("Hash is not sufficiently strong") + + if self._encoding == 'binary': + if len(signature) != (2 * self._order_bytes): + raise ValueError("The signature is not authentic (length)") + r_prime, s_prime = [Integer.from_bytes(x) + for x in (signature[:self._order_bytes], + signature[self._order_bytes:])] + else: + try: + der_seq = DerSequence().decode(signature, strict=True) + except (ValueError, IndexError): + raise ValueError("The signature is not authentic (DER)") + if len(der_seq) != 2 or not der_seq.hasOnlyInts(): + raise ValueError("The signature is not authentic (DER content)") + r_prime, s_prime = Integer(der_seq[0]), Integer(der_seq[1]) + + if not (0 < r_prime < self._order) or not (0 < s_prime < self._order): + raise ValueError("The signature is not authentic (d)") + + z = Integer.from_bytes(msg_hash.digest()[:self._order_bytes]) + result = self._key._verify(z, (r_prime, s_prime)) + if not result: + raise ValueError("The signature is not authentic") + # Make PyCryptodome code to fail + return False + + +class DeterministicDsaSigScheme(DssSigScheme): + # Also applicable to ECDSA + + def __init__(self, key, encoding, order, private_key): + super(DeterministicDsaSigScheme, self).__init__(key, encoding, order) + self._private_key = private_key + + def _bits2int(self, bstr): + """See 2.3.2 in RFC6979""" + + result = Integer.from_bytes(bstr) + q_len = self._order.size_in_bits() + b_len = len(bstr) * 8 + if b_len > q_len: + # Only keep leftmost q_len bits + result >>= (b_len - q_len) + return result + + def _int2octets(self, int_mod_q): + """See 2.3.3 in RFC6979""" + + assert 0 < int_mod_q < self._order + return long_to_bytes(int_mod_q, self._order_bytes) + + def _bits2octets(self, bstr): + """See 2.3.4 in RFC6979""" + + z1 = self._bits2int(bstr) + if z1 < self._order: + z2 = z1 + else: + z2 = z1 - self._order + return self._int2octets(z2) + + def _compute_nonce(self, mhash): + """Generate k in a deterministic way""" + + # See section 3.2 in RFC6979.txt + # Step a + h1 = mhash.digest() + # Step b + mask_v = b'\x01' * mhash.digest_size + # Step c + nonce_k = b'\x00' * mhash.digest_size + + for int_oct in (b'\x00', b'\x01'): + # Step d/f + nonce_k = HMAC.new(nonce_k, + mask_v + int_oct + + self._int2octets(self._private_key) + + self._bits2octets(h1), mhash).digest() + # Step e/g + mask_v = HMAC.new(nonce_k, mask_v, mhash).digest() + + nonce = -1 + while not (0 < nonce < self._order): + # Step h.C (second part) + if nonce != -1: + nonce_k = HMAC.new(nonce_k, mask_v + b'\x00', + mhash).digest() + mask_v = HMAC.new(nonce_k, mask_v, mhash).digest() + + # Step h.A + mask_t = b"" + + # Step h.B + while len(mask_t) < self._order_bytes: + mask_v = HMAC.new(nonce_k, mask_v, mhash).digest() + mask_t += mask_v + + # Step h.C (first part) + nonce = self._bits2int(mask_t) + return nonce + + def _valid_hash(self, msg_hash): + return True + + +class FipsDsaSigScheme(DssSigScheme): + + #: List of L (bit length of p) and N (bit length of q) combinations + #: that are allowed by FIPS 186-3. The security level is provided in + #: Table 2 of FIPS 800-57 (rev3). + _fips_186_3_L_N = ( + (1024, 160), # 80 bits (SHA-1 or stronger) + (2048, 224), # 112 bits (SHA-224 or stronger) + (2048, 256), # 128 bits (SHA-256 or stronger) + (3072, 256) # 256 bits (SHA-512) + ) + + def __init__(self, key, encoding, order, randfunc): + super(FipsDsaSigScheme, self).__init__(key, encoding, order) + self._randfunc = randfunc + + L = Integer(key.p).size_in_bits() + if (L, self._order_bits) not in self._fips_186_3_L_N: + error = ("L/N (%d, %d) is not compliant to FIPS 186-3" + % (L, self._order_bits)) + raise ValueError(error) + + def _compute_nonce(self, msg_hash): + # hash is not used + return Integer.random_range(min_inclusive=1, + max_exclusive=self._order, + randfunc=self._randfunc) + + def _valid_hash(self, msg_hash): + """Verify that SHA-1, SHA-2 or SHA-3 are used""" + return (msg_hash.oid == "1.3.14.3.2.26" or + msg_hash.oid.startswith("2.16.840.1.101.3.4.2.")) + + +class FipsEcDsaSigScheme(DssSigScheme): + + def __init__(self, key, encoding, order, randfunc): + super(FipsEcDsaSigScheme, self).__init__(key, encoding, order) + self._randfunc = randfunc + + def _compute_nonce(self, msg_hash): + return Integer.random_range(min_inclusive=1, + max_exclusive=self._key._curve.order, + randfunc=self._randfunc) + + def _valid_hash(self, msg_hash): + """Verify that the strength of the hash matches or exceeds + the strength of the EC. We fail if the hash is too weak.""" + + modulus_bits = self._key.pointQ.size_in_bits() + + # SHS: SHA-2, SHA-3, truncated SHA-512 + sha224 = ("2.16.840.1.101.3.4.2.4", "2.16.840.1.101.3.4.2.7", "2.16.840.1.101.3.4.2.5") + sha256 = ("2.16.840.1.101.3.4.2.1", "2.16.840.1.101.3.4.2.8", "2.16.840.1.101.3.4.2.6") + sha384 = ("2.16.840.1.101.3.4.2.2", "2.16.840.1.101.3.4.2.9") + sha512 = ("2.16.840.1.101.3.4.2.3", "2.16.840.1.101.3.4.2.10") + shs = sha224 + sha256 + sha384 + sha512 + + try: + result = msg_hash.oid in shs + except AttributeError: + result = False + return result + + +def new(key, mode, encoding='binary', randfunc=None): + """Create a signature object :class:`DssSigScheme` that + can perform (EC)DSA signature or verification. + + .. note:: + Refer to `NIST SP 800 Part 1 Rev 4`_ (or newer release) for an + overview of the recommended key lengths. + + Args: + key (:class:`Cryptodome.PublicKey.DSA` or :class:`Cryptodome.PublicKey.ECC`): + The key to use for computing the signature (*private* keys only) + or for verifying one. + For DSA keys, let ``L`` and ``N`` be the bit lengths of the modulus ``p`` + and of ``q``: the pair ``(L,N)`` must appear in the following list, + in compliance to section 4.2 of `FIPS 186-4`_: + + - (1024, 160) *legacy only; do not create new signatures with this* + - (2048, 224) *deprecated; do not create new signatures with this* + - (2048, 256) + - (3072, 256) + + For ECC, only keys over P-224, P-256, P-384, and P-521 are accepted. + + mode (string): + The parameter can take these values: + + - ``'fips-186-3'``. The signature generation is randomized and carried out + according to `FIPS 186-3`_: the nonce ``k`` is taken from the RNG. + - ``'deterministic-rfc6979'``. The signature generation is not + randomized. See RFC6979_. + + encoding (string): + How the signature is encoded. This value determines the output of + :meth:`sign` and the input to :meth:`verify`. + + The following values are accepted: + + - ``'binary'`` (default), the signature is the raw concatenation + of ``r`` and ``s``. It is defined in the IEEE P.1363 standard. + For DSA, the size in bytes of the signature is ``N/4`` bytes + (e.g. 64 for ``N=256``). + For ECDSA, the signature is always twice the length of a point + coordinate (e.g. 64 bytes for P-256). + + - ``'der'``, the signature is a ASN.1 DER SEQUENCE + with two INTEGERs (``r`` and ``s``). It is defined in RFC3279_. + The size of the signature is variable. + + randfunc (callable): + A function that returns random ``bytes``, of a given length. + If omitted, the internal RNG is used. + Only applicable for the *'fips-186-3'* mode. + + .. _FIPS 186-3: http://csrc.nist.gov/publications/fips/fips186-3/fips_186-3.pdf + .. _FIPS 186-4: http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf + .. _NIST SP 800 Part 1 Rev 4: http://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-57pt1r4.pdf + .. _RFC6979: http://tools.ietf.org/html/rfc6979 + .. _RFC3279: https://tools.ietf.org/html/rfc3279#section-2.2.2 + """ + + # The goal of the 'mode' parameter is to avoid to + # have the current version of the standard as default. + # + # Over time, such version will be superseded by (for instance) + # FIPS 186-4 and it will be odd to have -3 as default. + + if encoding not in ('binary', 'der'): + raise ValueError("Unknown encoding '%s'" % encoding) + + if isinstance(key, EccKey): + order = key._curve.order + private_key_attr = 'd' + if not key.curve.startswith("NIST"): + raise ValueError("ECC key is not on a NIST P curve") + elif isinstance(key, DsaKey): + order = Integer(key.q) + private_key_attr = 'x' + else: + raise ValueError("Unsupported key type " + str(type(key))) + + if key.has_private(): + private_key = getattr(key, private_key_attr) + else: + private_key = None + + if mode == 'deterministic-rfc6979': + return DeterministicDsaSigScheme(key, encoding, order, private_key) + elif mode == 'fips-186-3': + if isinstance(key, EccKey): + return FipsEcDsaSigScheme(key, encoding, order, randfunc) + else: + return FipsDsaSigScheme(key, encoding, order, randfunc) + else: + raise ValueError("Unknown DSS mode '%s'" % mode) diff --git a/venv/Lib/site-packages/Cryptodome/Signature/DSS.pyi b/venv/Lib/site-packages/Cryptodome/Signature/DSS.pyi new file mode 100644 index 0000000..52ecc8f --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Signature/DSS.pyi @@ -0,0 +1,27 @@ +from typing import Union, Optional, Callable +from typing_extensions import Protocol + +from Cryptodome.PublicKey.DSA import DsaKey +from Cryptodome.PublicKey.ECC import EccKey + +class Hash(Protocol): + def digest(self) -> bytes: ... + +__all__ = ['new'] + +class DssSigScheme: + def __init__(self, key: Union[DsaKey, EccKey], encoding: str, order: int) -> None: ... + def can_sign(self) -> bool: ... + def sign(self, msg_hash: Hash) -> bytes: ... + def verify(self, msg_hash: Hash, signature: bytes) -> bool: ... + +class DeterministicDsaSigScheme(DssSigScheme): + def __init__(self, key, encoding, order, private_key) -> None: ... + +class FipsDsaSigScheme(DssSigScheme): + def __init__(self, key: DsaKey, encoding: str, order: int, randfunc: Callable) -> None: ... + +class FipsEcDsaSigScheme(DssSigScheme): + def __init__(self, key: EccKey, encoding: str, order: int, randfunc: Callable) -> None: ... + +def new(key: Union[DsaKey, EccKey], mode: str, encoding: Optional[str]='binary', randfunc: Optional[Callable]=None) -> Union[DeterministicDsaSigScheme, FipsDsaSigScheme, FipsEcDsaSigScheme]: ... diff --git a/venv/Lib/site-packages/Cryptodome/Signature/PKCS1_PSS.py b/venv/Lib/site-packages/Cryptodome/Signature/PKCS1_PSS.py new file mode 100644 index 0000000..1e7e5b5 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Signature/PKCS1_PSS.py @@ -0,0 +1,55 @@ +# =================================================================== +# +# Copyright (c) 2014, Legrandin +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# =================================================================== + +""" +Legacy module for PKCS#1 PSS signatures. + +:undocumented: __package__ +""" + +import types + +from Cryptodome.Signature import pss + + +def _pycrypto_verify(self, hash_object, signature): + try: + self._verify(hash_object, signature) + except (ValueError, TypeError): + return False + return True + + +def new(rsa_key, mgfunc=None, saltLen=None, randfunc=None): + pkcs1 = pss.new(rsa_key, mask_func=mgfunc, + salt_bytes=saltLen, rand_func=randfunc) + pkcs1._verify = pkcs1.verify + pkcs1.verify = types.MethodType(_pycrypto_verify, pkcs1) + return pkcs1 diff --git a/venv/Lib/site-packages/Cryptodome/Signature/PKCS1_PSS.pyi b/venv/Lib/site-packages/Cryptodome/Signature/PKCS1_PSS.pyi new file mode 100644 index 0000000..e7424f5 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Signature/PKCS1_PSS.pyi @@ -0,0 +1,28 @@ +from typing import Union, Callable, Optional +from typing_extensions import Protocol + +from Cryptodome.PublicKey.RSA import RsaKey + + +class Hash(Protocol): + def digest(self) -> bytes: ... + def update(self, bytes) -> None: ... + + +class HashModule(Protocol): + @staticmethod + def new(data: Optional[bytes]) -> Hash: ... + + +MaskFunction = Callable[[bytes, int, Union[Hash, HashModule]], bytes] +RndFunction = Callable[[int], bytes] + +class PSS_SigScheme: + def __init__(self, key: RsaKey, mgfunc: MaskFunction, saltLen: int, randfunc: RndFunction) -> None: ... + def can_sign(self) -> bool: ... + def sign(self, msg_hash: Hash) -> bytes: ... + def verify(self, msg_hash: Hash, signature: bytes) -> bool: ... + + + +def new(rsa_key: RsaKey, mgfunc: Optional[MaskFunction]=None, saltLen: Optional[int]=None, randfunc: Optional[RndFunction]=None) -> PSS_SigScheme: ... diff --git a/venv/Lib/site-packages/Cryptodome/Signature/PKCS1_v1_5.py b/venv/Lib/site-packages/Cryptodome/Signature/PKCS1_v1_5.py new file mode 100644 index 0000000..d560663 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Signature/PKCS1_v1_5.py @@ -0,0 +1,53 @@ +# =================================================================== +# +# Copyright (c) 2014, Legrandin +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# =================================================================== + +""" +Legacy module for PKCS#1 v1.5 signatures. + +:undocumented: __package__ +""" + +import types + +from Cryptodome.Signature import pkcs1_15 + +def _pycrypto_verify(self, hash_object, signature): + try: + self._verify(hash_object, signature) + except (ValueError, TypeError): + return False + return True + +def new(rsa_key): + pkcs1 = pkcs1_15.new(rsa_key) + pkcs1._verify = pkcs1.verify + pkcs1.verify = types.MethodType(_pycrypto_verify, pkcs1) + return pkcs1 + diff --git a/venv/Lib/site-packages/Cryptodome/Signature/PKCS1_v1_5.pyi b/venv/Lib/site-packages/Cryptodome/Signature/PKCS1_v1_5.pyi new file mode 100644 index 0000000..d02555c --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Signature/PKCS1_v1_5.pyi @@ -0,0 +1,16 @@ +from typing import Optional +from typing_extensions import Protocol + +from Cryptodome.PublicKey.RSA import RsaKey + +class Hash(Protocol): + def digest(self) -> bytes: ... + +class PKCS115_SigScheme: + def __init__(self, rsa_key: RsaKey) -> None: ... + def can_sign(self) -> bool: ... + def sign(self, msg_hash: Hash) -> bytes: ... + def verify(self, msg_hash: Hash, signature: bytes) -> bool: ... + + +def new(rsa_key: RsaKey) -> PKCS115_SigScheme: ... diff --git a/venv/Lib/site-packages/Cryptodome/Signature/__init__.py b/venv/Lib/site-packages/Cryptodome/Signature/__init__.py new file mode 100644 index 0000000..11ca64c --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Signature/__init__.py @@ -0,0 +1,36 @@ +# =================================================================== +# +# Copyright (c) 2014, Legrandin +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# =================================================================== + +"""Digital signature protocols + +A collection of standardized protocols to carry out digital signatures. +""" + +__all__ = ['PKCS1_v1_5', 'PKCS1_PSS', 'DSS', 'pkcs1_15', 'pss', 'eddsa'] diff --git a/venv/Lib/site-packages/Cryptodome/Signature/__pycache__/DSS.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/Signature/__pycache__/DSS.cpython-312.pyc new file mode 100644 index 0000000..9c1befc Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Signature/__pycache__/DSS.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/Signature/__pycache__/PKCS1_PSS.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/Signature/__pycache__/PKCS1_PSS.cpython-312.pyc new file mode 100644 index 0000000..f114277 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Signature/__pycache__/PKCS1_PSS.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/Signature/__pycache__/PKCS1_v1_5.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/Signature/__pycache__/PKCS1_v1_5.cpython-312.pyc new file mode 100644 index 0000000..259d73b Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Signature/__pycache__/PKCS1_v1_5.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/Signature/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/Signature/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000..9c1e73a Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Signature/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/Signature/__pycache__/eddsa.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/Signature/__pycache__/eddsa.cpython-312.pyc new file mode 100644 index 0000000..ef0d3aa Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Signature/__pycache__/eddsa.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/Signature/__pycache__/pkcs1_15.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/Signature/__pycache__/pkcs1_15.cpython-312.pyc new file mode 100644 index 0000000..2aba546 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Signature/__pycache__/pkcs1_15.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/Signature/__pycache__/pss.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/Signature/__pycache__/pss.cpython-312.pyc new file mode 100644 index 0000000..7a68b21 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Signature/__pycache__/pss.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/Signature/eddsa.py b/venv/Lib/site-packages/Cryptodome/Signature/eddsa.py new file mode 100644 index 0000000..02e1e3e --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Signature/eddsa.py @@ -0,0 +1,343 @@ +# =================================================================== +# +# Copyright (c) 2022, Legrandin +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# =================================================================== + +from Cryptodome.Math.Numbers import Integer + +from Cryptodome.Hash import SHA512, SHAKE256 +from Cryptodome.Util.py3compat import bchr, is_bytes +from Cryptodome.PublicKey.ECC import (EccKey, + construct, + _import_ed25519_public_key, + _import_ed448_public_key) + + +def import_public_key(encoded): + """Create a new Ed25519 or Ed448 public key object, + starting from the key encoded as raw ``bytes``, + in the format described in RFC8032. + + Args: + encoded (bytes): + The EdDSA public key to import. + It must be 32 bytes for Ed25519, and 57 bytes for Ed448. + + Returns: + :class:`Cryptodome.PublicKey.EccKey` : a new ECC key object. + + Raises: + ValueError: when the given key cannot be parsed. + """ + + if len(encoded) == 32: + x, y = _import_ed25519_public_key(encoded) + curve_name = "Ed25519" + elif len(encoded) == 57: + x, y = _import_ed448_public_key(encoded) + curve_name = "Ed448" + else: + raise ValueError("Not an EdDSA key (%d bytes)" % len(encoded)) + return construct(curve=curve_name, point_x=x, point_y=y) + + +def import_private_key(encoded): + """Create a new Ed25519 or Ed448 private key object, + starting from the key encoded as raw ``bytes``, + in the format described in RFC8032. + + Args: + encoded (bytes): + The EdDSA private key to import. + It must be 32 bytes for Ed25519, and 57 bytes for Ed448. + + Returns: + :class:`Cryptodome.PublicKey.EccKey` : a new ECC key object. + + Raises: + ValueError: when the given key cannot be parsed. + """ + + if len(encoded) == 32: + curve_name = "ed25519" + elif len(encoded) == 57: + curve_name = "ed448" + else: + raise ValueError("Incorrect length. Only EdDSA private keys are supported.") + + # Note that the private key is truly a sequence of random bytes, + # so we cannot check its correctness in any way. + + return construct(seed=encoded, curve=curve_name) + + +class EdDSASigScheme(object): + """An EdDSA signature object. + Do not instantiate directly. + Use :func:`Cryptodome.Signature.eddsa.new`. + """ + + def __init__(self, key, context): + """Create a new EdDSA object. + + Do not instantiate this object directly, + use `Cryptodome.Signature.DSS.new` instead. + """ + + self._key = key + self._context = context + self._A = key._export_eddsa_public() + self._order = key._curve.order + + def can_sign(self): + """Return ``True`` if this signature object can be used + for signing messages.""" + + return self._key.has_private() + + def sign(self, msg_or_hash): + """Compute the EdDSA signature of a message. + + Args: + msg_or_hash (bytes or a hash object): + The message to sign (``bytes``, in case of *PureEdDSA*) or + the hash that was carried out over the message (hash object, for *HashEdDSA*). + + The hash object must be :class:`Cryptodome.Hash.SHA512` for Ed25519, + and :class:`Cryptodome.Hash.SHAKE256` object for Ed448. + + :return: The signature as ``bytes``. It is always 64 bytes for Ed25519, and 114 bytes for Ed448. + :raise TypeError: if the EdDSA key has no private half + """ + + if not self._key.has_private(): + raise TypeError("Private key is needed to sign") + + if self._key.curve == "Ed25519": + ph = isinstance(msg_or_hash, SHA512.SHA512Hash) + if not (ph or is_bytes(msg_or_hash)): + raise TypeError("'msg_or_hash' must be bytes of a SHA-512 hash") + eddsa_sign_method = self._sign_ed25519 + + elif self._key.curve == "Ed448": + ph = isinstance(msg_or_hash, SHAKE256.SHAKE256_XOF) + if not (ph or is_bytes(msg_or_hash)): + raise TypeError("'msg_or_hash' must be bytes of a SHAKE256 hash") + eddsa_sign_method = self._sign_ed448 + + else: + raise ValueError("Incorrect curve for EdDSA") + + return eddsa_sign_method(msg_or_hash, ph) + + def _sign_ed25519(self, msg_or_hash, ph): + + if self._context or ph: + flag = int(ph) + # dom2(flag, self._context) + dom2 = b'SigEd25519 no Ed25519 collisions' + bchr(flag) + \ + bchr(len(self._context)) + self._context + else: + dom2 = b'' + + PHM = msg_or_hash.digest() if ph else msg_or_hash + + # See RFC 8032, section 5.1.6 + + # Step 2 + r_hash = SHA512.new(dom2 + self._key._prefix + PHM).digest() + r = Integer.from_bytes(r_hash, 'little') % self._order + # Step 3 + R_pk = EccKey(point=r * self._key._curve.G)._export_eddsa_public() + # Step 4 + k_hash = SHA512.new(dom2 + R_pk + self._A + PHM).digest() + k = Integer.from_bytes(k_hash, 'little') % self._order + # Step 5 + s = (r + k * self._key.d) % self._order + + return R_pk + s.to_bytes(32, 'little') + + def _sign_ed448(self, msg_or_hash, ph): + + flag = int(ph) + # dom4(flag, self._context) + dom4 = b'SigEd448' + bchr(flag) + \ + bchr(len(self._context)) + self._context + + PHM = msg_or_hash.copy().read(64) if ph else msg_or_hash + + # See RFC 8032, section 5.2.6 + + # Step 2 + r_hash = SHAKE256.new(dom4 + self._key._prefix + PHM).read(114) + r = Integer.from_bytes(r_hash, 'little') % self._order + # Step 3 + R_pk = EccKey(point=r * self._key._curve.G)._export_eddsa_public() + # Step 4 + k_hash = SHAKE256.new(dom4 + R_pk + self._A + PHM).read(114) + k = Integer.from_bytes(k_hash, 'little') % self._order + # Step 5 + s = (r + k * self._key.d) % self._order + + return R_pk + s.to_bytes(57, 'little') + + def verify(self, msg_or_hash, signature): + """Check if an EdDSA signature is authentic. + + Args: + msg_or_hash (bytes or a hash object): + The message to verify (``bytes``, in case of *PureEdDSA*) or + the hash that was carried out over the message (hash object, for *HashEdDSA*). + + The hash object must be :class:`Cryptodome.Hash.SHA512` object for Ed25519, + and :class:`Cryptodome.Hash.SHAKE256` for Ed448. + + signature (``bytes``): + The signature that needs to be validated. + It must be 64 bytes for Ed25519, and 114 bytes for Ed448. + + :raise ValueError: if the signature is not authentic + """ + + if self._key.curve == "Ed25519": + ph = isinstance(msg_or_hash, SHA512.SHA512Hash) + if not (ph or is_bytes(msg_or_hash)): + raise TypeError("'msg_or_hash' must be bytes of a SHA-512 hash") + eddsa_verify_method = self._verify_ed25519 + + elif self._key.curve == "Ed448": + ph = isinstance(msg_or_hash, SHAKE256.SHAKE256_XOF) + if not (ph or is_bytes(msg_or_hash)): + raise TypeError("'msg_or_hash' must be bytes of a SHAKE256 hash") + eddsa_verify_method = self._verify_ed448 + + else: + raise ValueError("Incorrect curve for EdDSA") + + return eddsa_verify_method(msg_or_hash, signature, ph) + + def _verify_ed25519(self, msg_or_hash, signature, ph): + + if len(signature) != 64: + raise ValueError("The signature is not authentic (length)") + + if self._context or ph: + flag = int(ph) + dom2 = b'SigEd25519 no Ed25519 collisions' + bchr(flag) + \ + bchr(len(self._context)) + self._context + else: + dom2 = b'' + + PHM = msg_or_hash.digest() if ph else msg_or_hash + + # Section 5.1.7 + + # Step 1 + try: + R = import_public_key(signature[:32]).pointQ + except ValueError: + raise ValueError("The signature is not authentic (R)") + s = Integer.from_bytes(signature[32:], 'little') + if s > self._order: + raise ValueError("The signature is not authentic (S)") + # Step 2 + k_hash = SHA512.new(dom2 + signature[:32] + self._A + PHM).digest() + k = Integer.from_bytes(k_hash, 'little') % self._order + # Step 3 + point1 = s * 8 * self._key._curve.G + # OPTIMIZE: with double-scalar multiplication, with no SCA + # countermeasures because it is public values + point2 = 8 * R + k * 8 * self._key.pointQ + if point1 != point2: + raise ValueError("The signature is not authentic") + + def _verify_ed448(self, msg_or_hash, signature, ph): + + if len(signature) != 114: + raise ValueError("The signature is not authentic (length)") + + flag = int(ph) + # dom4(flag, self._context) + dom4 = b'SigEd448' + bchr(flag) + \ + bchr(len(self._context)) + self._context + + PHM = msg_or_hash.copy().read(64) if ph else msg_or_hash + + # Section 5.2.7 + + # Step 1 + try: + R = import_public_key(signature[:57]).pointQ + except ValueError: + raise ValueError("The signature is not authentic (R)") + s = Integer.from_bytes(signature[57:], 'little') + if s > self._order: + raise ValueError("The signature is not authentic (S)") + # Step 2 + k_hash = SHAKE256.new(dom4 + signature[:57] + self._A + PHM).read(114) + k = Integer.from_bytes(k_hash, 'little') % self._order + # Step 3 + point1 = s * 8 * self._key._curve.G + # OPTIMIZE: with double-scalar multiplication, with no SCA + # countermeasures because it is public values + point2 = 8 * R + k * 8 * self._key.pointQ + if point1 != point2: + raise ValueError("The signature is not authentic") + + +def new(key, mode, context=None): + """Create a signature object :class:`EdDSASigScheme` that + can perform or verify an EdDSA signature. + + Args: + key (:class:`Cryptodome.PublicKey.ECC` object): + The key to use for computing the signature (*private* keys only) + or for verifying one. + The key must be on the curve ``Ed25519`` or ``Ed448``. + + mode (string): + This parameter must be ``'rfc8032'``. + + context (bytes): + Up to 255 bytes of `context `_, + which is a constant byte string to segregate different protocols or + different applications of the same key. + """ + + if not isinstance(key, EccKey) or key.curve not in ("Ed25519", "Ed448"): + raise ValueError("EdDSA can only be used with EdDSA keys") + + if mode != 'rfc8032': + raise ValueError("Mode must be 'rfc8032'") + + if context is None: + context = b'' + elif len(context) > 255: + raise ValueError("Context for EdDSA must not be longer than 255 bytes") + + return EdDSASigScheme(key, context) diff --git a/venv/Lib/site-packages/Cryptodome/Signature/eddsa.pyi b/venv/Lib/site-packages/Cryptodome/Signature/eddsa.pyi new file mode 100644 index 0000000..809a7ad --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Signature/eddsa.pyi @@ -0,0 +1,21 @@ +from typing import Union, Optional +from typing_extensions import Protocol +from Cryptodome.PublicKey.ECC import EccKey + +class Hash(Protocol): + def digest(self) -> bytes: ... + +class XOF(Protocol): + def read(self, len: int) -> bytes: ... + +def import_public_key(encoded: bytes) -> EccKey: ... +def import_private_key(encoded: bytes) -> EccKey: ... + +class EdDSASigScheme(object): + + def __init__(self, key: EccKey, context: bytes) -> None: ... + def can_sign(self) -> bool: ... + def sign(self, msg_or_hash: Union[bytes, Hash, XOF]) -> bytes: ... + def verify(self, msg_or_hash: Union[bytes, Hash, XOF], signature: bytes) -> None: ... + +def new(key: EccKey, mode: str, context: Optional[bytes]=None) -> EdDSASigScheme: ... diff --git a/venv/Lib/site-packages/Cryptodome/Signature/pkcs1_15.py b/venv/Lib/site-packages/Cryptodome/Signature/pkcs1_15.py new file mode 100644 index 0000000..bdde78a --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Signature/pkcs1_15.py @@ -0,0 +1,223 @@ +# =================================================================== +# +# Copyright (c) 2014, Legrandin +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# =================================================================== + +import Cryptodome.Util.number +from Cryptodome.Util.number import ceil_div, bytes_to_long, long_to_bytes +from Cryptodome.Util.asn1 import DerSequence, DerNull, DerOctetString, DerObjectId + +class PKCS115_SigScheme: + """A signature object for ``RSASSA-PKCS1-v1_5``. + Do not instantiate directly. + Use :func:`Cryptodome.Signature.pkcs1_15.new`. + """ + + def __init__(self, rsa_key): + """Initialize this PKCS#1 v1.5 signature scheme object. + + :Parameters: + rsa_key : an RSA key object + Creation of signatures is only possible if this is a *private* + RSA key. Verification of signatures is always possible. + """ + self._key = rsa_key + + def can_sign(self): + """Return ``True`` if this object can be used to sign messages.""" + return self._key.has_private() + + def sign(self, msg_hash): + """Create the PKCS#1 v1.5 signature of a message. + + This function is also called ``RSASSA-PKCS1-V1_5-SIGN`` and + it is specified in + `section 8.2.1 of RFC8017 `_. + + :parameter msg_hash: + This is an object from the :mod:`Cryptodome.Hash` package. + It has been used to digest the message to sign. + :type msg_hash: hash object + + :return: the signature encoded as a *byte string*. + :raise ValueError: if the RSA key is not long enough for the given hash algorithm. + :raise TypeError: if the RSA key has no private half. + """ + + # See 8.2.1 in RFC3447 + modBits = Cryptodome.Util.number.size(self._key.n) + k = ceil_div(modBits,8) # Convert from bits to bytes + + # Step 1 + em = _EMSA_PKCS1_V1_5_ENCODE(msg_hash, k) + # Step 2a (OS2IP) + em_int = bytes_to_long(em) + # Step 2b (RSASP1) and Step 2c (I2OSP) + signature = self._key._decrypt_to_bytes(em_int) + # Verify no faults occurred + if em_int != pow(bytes_to_long(signature), self._key.e, self._key.n): + raise ValueError("Fault detected in RSA private key operation") + return signature + + def verify(self, msg_hash, signature): + """Check if the PKCS#1 v1.5 signature over a message is valid. + + This function is also called ``RSASSA-PKCS1-V1_5-VERIFY`` and + it is specified in + `section 8.2.2 of RFC8037 `_. + + :parameter msg_hash: + The hash that was carried out over the message. This is an object + belonging to the :mod:`Cryptodome.Hash` module. + :type parameter: hash object + + :parameter signature: + The signature that needs to be validated. + :type signature: byte string + + :raise ValueError: if the signature is not valid. + """ + + # See 8.2.2 in RFC3447 + modBits = Cryptodome.Util.number.size(self._key.n) + k = ceil_div(modBits, 8) # Convert from bits to bytes + + # Step 1 + if len(signature) != k: + raise ValueError("Invalid signature") + # Step 2a (O2SIP) + signature_int = bytes_to_long(signature) + # Step 2b (RSAVP1) + em_int = self._key._encrypt(signature_int) + # Step 2c (I2OSP) + em1 = long_to_bytes(em_int, k) + # Step 3 + try: + possible_em1 = [ _EMSA_PKCS1_V1_5_ENCODE(msg_hash, k, True) ] + # MD2/4/5 hashes always require NULL params in AlgorithmIdentifier. + # For all others, it is optional. + try: + algorithm_is_md = msg_hash.oid.startswith('1.2.840.113549.2.') + except AttributeError: + algorithm_is_md = False + if not algorithm_is_md: # MD2/MD4/MD5 + possible_em1.append(_EMSA_PKCS1_V1_5_ENCODE(msg_hash, k, False)) + except ValueError: + raise ValueError("Invalid signature") + # Step 4 + # By comparing the full encodings (as opposed to checking each + # of its components one at a time) we avoid attacks to the padding + # scheme like Bleichenbacher's (see http://www.mail-archive.com/cryptography@metzdowd.com/msg06537). + # + if em1 not in possible_em1: + raise ValueError("Invalid signature") + pass + + +def _EMSA_PKCS1_V1_5_ENCODE(msg_hash, emLen, with_hash_parameters=True): + """ + Implement the ``EMSA-PKCS1-V1_5-ENCODE`` function, as defined + in PKCS#1 v2.1 (RFC3447, 9.2). + + ``_EMSA-PKCS1-V1_5-ENCODE`` actually accepts the message ``M`` as input, + and hash it internally. Here, we expect that the message has already + been hashed instead. + + :Parameters: + msg_hash : hash object + The hash object that holds the digest of the message being signed. + emLen : int + The length the final encoding must have, in bytes. + with_hash_parameters : bool + If True (default), include NULL parameters for the hash + algorithm in the ``digestAlgorithm`` SEQUENCE. + + :attention: the early standard (RFC2313) stated that ``DigestInfo`` + had to be BER-encoded. This means that old signatures + might have length tags in indefinite form, which + is not supported in DER. Such encoding cannot be + reproduced by this function. + + :Return: An ``emLen`` byte long string that encodes the hash. + """ + + # First, build the ASN.1 DER object DigestInfo: + # + # DigestInfo ::= SEQUENCE { + # digestAlgorithm AlgorithmIdentifier, + # digest OCTET STRING + # } + # + # where digestAlgorithm identifies the hash function and shall be an + # algorithm ID with an OID in the set PKCS1-v1-5DigestAlgorithms. + # + # PKCS1-v1-5DigestAlgorithms ALGORITHM-IDENTIFIER ::= { + # { OID id-md2 PARAMETERS NULL }| + # { OID id-md5 PARAMETERS NULL }| + # { OID id-sha1 PARAMETERS NULL }| + # { OID id-sha256 PARAMETERS NULL }| + # { OID id-sha384 PARAMETERS NULL }| + # { OID id-sha512 PARAMETERS NULL } + # } + # + # Appendix B.1 also says that for SHA-1/-2 algorithms, the parameters + # should be omitted. They may be present, but when they are, they shall + # have NULL value. + + digestAlgo = DerSequence([ DerObjectId(msg_hash.oid).encode() ]) + + if with_hash_parameters: + digestAlgo.append(DerNull().encode()) + + digest = DerOctetString(msg_hash.digest()) + digestInfo = DerSequence([ + digestAlgo.encode(), + digest.encode() + ]).encode() + + # We need at least 11 bytes for the remaining data: 3 fixed bytes and + # at least 8 bytes of padding). + if emLen bytes: ... + +class PKCS115_SigScheme: + def __init__(self, rsa_key: RsaKey) -> None: ... + def can_sign(self) -> bool: ... + def sign(self, msg_hash: Hash) -> bytes: ... + def verify(self, msg_hash: Hash, signature: bytes) -> None: ... + +def _EMSA_PKCS1_V1_5_ENCODE(msg_hash: Hash, emLen: int, with_hash_parameters: Optional[bool]=True) -> bytes: ... + +def new(rsa_key: RsaKey) -> PKCS115_SigScheme: ... diff --git a/venv/Lib/site-packages/Cryptodome/Signature/pss.py b/venv/Lib/site-packages/Cryptodome/Signature/pss.py new file mode 100644 index 0000000..b929e26 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Signature/pss.py @@ -0,0 +1,387 @@ +# =================================================================== +# +# Copyright (c) 2014, Legrandin +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# =================================================================== + +from Cryptodome.Util.py3compat import bchr, bord, iter_range +import Cryptodome.Util.number +from Cryptodome.Util.number import (ceil_div, + long_to_bytes, + bytes_to_long + ) +from Cryptodome.Util.strxor import strxor +from Cryptodome import Random + + +class PSS_SigScheme: + """A signature object for ``RSASSA-PSS``. + Do not instantiate directly. + Use :func:`Cryptodome.Signature.pss.new`. + """ + + def __init__(self, key, mgfunc, saltLen, randfunc): + """Initialize this PKCS#1 PSS signature scheme object. + + :Parameters: + key : an RSA key object + If a private half is given, both signature and + verification are possible. + If a public half is given, only verification is possible. + mgfunc : callable + A mask generation function that accepts two parameters: + a string to use as seed, and the lenth of the mask to + generate, in bytes. + saltLen : integer + Length of the salt, in bytes. + randfunc : callable + A function that returns random bytes. + """ + + self._key = key + self._saltLen = saltLen + self._mgfunc = mgfunc + self._randfunc = randfunc + + def can_sign(self): + """Return ``True`` if this object can be used to sign messages.""" + return self._key.has_private() + + def sign(self, msg_hash): + """Create the PKCS#1 PSS signature of a message. + + This function is also called ``RSASSA-PSS-SIGN`` and + it is specified in + `section 8.1.1 of RFC8017 `_. + + :parameter msg_hash: + This is an object from the :mod:`Cryptodome.Hash` package. + It has been used to digest the message to sign. + :type msg_hash: hash object + + :return: the signature encoded as a *byte string*. + :raise ValueError: if the RSA key is not long enough for the given hash algorithm. + :raise TypeError: if the RSA key has no private half. + """ + + # Set defaults for salt length and mask generation function + if self._saltLen is None: + sLen = msg_hash.digest_size + else: + sLen = self._saltLen + + if self._mgfunc is None: + mgf = lambda x, y: MGF1(x, y, msg_hash) + else: + mgf = self._mgfunc + + modBits = Cryptodome.Util.number.size(self._key.n) + + # See 8.1.1 in RFC3447 + k = ceil_div(modBits, 8) # k is length in bytes of the modulus + # Step 1 + em = _EMSA_PSS_ENCODE(msg_hash, modBits-1, self._randfunc, mgf, sLen) + # Step 2a (OS2IP) + em_int = bytes_to_long(em) + # Step 2b (RSASP1) and Step 2c (I2OSP) + signature = self._key._decrypt_to_bytes(em_int) + # Verify no faults occurred + if em_int != pow(bytes_to_long(signature), self._key.e, self._key.n): + raise ValueError("Fault detected in RSA private key operation") + return signature + + def verify(self, msg_hash, signature): + """Check if the PKCS#1 PSS signature over a message is valid. + + This function is also called ``RSASSA-PSS-VERIFY`` and + it is specified in + `section 8.1.2 of RFC8037 `_. + + :parameter msg_hash: + The hash that was carried out over the message. This is an object + belonging to the :mod:`Cryptodome.Hash` module. + :type parameter: hash object + + :parameter signature: + The signature that needs to be validated. + :type signature: bytes + + :raise ValueError: if the signature is not valid. + """ + + # Set defaults for salt length and mask generation function + if self._saltLen is None: + sLen = msg_hash.digest_size + else: + sLen = self._saltLen + if self._mgfunc: + mgf = self._mgfunc + else: + mgf = lambda x, y: MGF1(x, y, msg_hash) + + modBits = Cryptodome.Util.number.size(self._key.n) + + # See 8.1.2 in RFC3447 + k = ceil_div(modBits, 8) # Convert from bits to bytes + # Step 1 + if len(signature) != k: + raise ValueError("Incorrect signature") + # Step 2a (O2SIP) + signature_int = bytes_to_long(signature) + # Step 2b (RSAVP1) + em_int = self._key._encrypt(signature_int) + # Step 2c (I2OSP) + emLen = ceil_div(modBits - 1, 8) + em = long_to_bytes(em_int, emLen) + # Step 3/4 + _EMSA_PSS_VERIFY(msg_hash, em, modBits-1, mgf, sLen) + + +def MGF1(mgfSeed, maskLen, hash_gen): + """Mask Generation Function, described in `B.2.1 of RFC8017 + `_. + + :param mfgSeed: + seed from which the mask is generated + :type mfgSeed: byte string + + :param maskLen: + intended length in bytes of the mask + :type maskLen: integer + + :param hash_gen: + A module or a hash object from :mod:`Cryptodome.Hash` + :type hash_object: + + :return: the mask, as a *byte string* + """ + + T = b"" + for counter in iter_range(ceil_div(maskLen, hash_gen.digest_size)): + c = long_to_bytes(counter, 4) + hobj = hash_gen.new() + hobj.update(mgfSeed + c) + T = T + hobj.digest() + assert(len(T) >= maskLen) + return T[:maskLen] + + +def _EMSA_PSS_ENCODE(mhash, emBits, randFunc, mgf, sLen): + r""" + Implement the ``EMSA-PSS-ENCODE`` function, as defined + in PKCS#1 v2.1 (RFC3447, 9.1.1). + + The original ``EMSA-PSS-ENCODE`` actually accepts the message ``M`` + as input, and hash it internally. Here, we expect that the message + has already been hashed instead. + + :Parameters: + mhash : hash object + The hash object that holds the digest of the message being signed. + emBits : int + Maximum length of the final encoding, in bits. + randFunc : callable + An RNG function that accepts as only parameter an int, and returns + a string of random bytes, to be used as salt. + mgf : callable + A mask generation function that accepts two parameters: a string to + use as seed, and the lenth of the mask to generate, in bytes. + sLen : int + Length of the salt, in bytes. + + :Return: An ``emLen`` byte long string that encodes the hash + (with ``emLen = \ceil(emBits/8)``). + + :Raise ValueError: + When digest or salt length are too big. + """ + + emLen = ceil_div(emBits, 8) + + # Bitmask of digits that fill up + lmask = 0 + for i in iter_range(8*emLen-emBits): + lmask = lmask >> 1 | 0x80 + + # Step 1 and 2 have been already done + # Step 3 + if emLen < mhash.digest_size+sLen+2: + raise ValueError("Digest or salt length are too long" + " for given key size.") + # Step 4 + salt = randFunc(sLen) + # Step 5 + m_prime = bchr(0)*8 + mhash.digest() + salt + # Step 6 + h = mhash.new() + h.update(m_prime) + # Step 7 + ps = bchr(0)*(emLen-sLen-mhash.digest_size-2) + # Step 8 + db = ps + bchr(1) + salt + # Step 9 + dbMask = mgf(h.digest(), emLen-mhash.digest_size-1) + # Step 10 + maskedDB = strxor(db, dbMask) + # Step 11 + maskedDB = bchr(bord(maskedDB[0]) & ~lmask) + maskedDB[1:] + # Step 12 + em = maskedDB + h.digest() + bchr(0xBC) + return em + + +def _EMSA_PSS_VERIFY(mhash, em, emBits, mgf, sLen): + """ + Implement the ``EMSA-PSS-VERIFY`` function, as defined + in PKCS#1 v2.1 (RFC3447, 9.1.2). + + ``EMSA-PSS-VERIFY`` actually accepts the message ``M`` as input, + and hash it internally. Here, we expect that the message has already + been hashed instead. + + :Parameters: + mhash : hash object + The hash object that holds the digest of the message to be verified. + em : string + The signature to verify, therefore proving that the sender really + signed the message that was received. + emBits : int + Length of the final encoding (em), in bits. + mgf : callable + A mask generation function that accepts two parameters: a string to + use as seed, and the lenth of the mask to generate, in bytes. + sLen : int + Length of the salt, in bytes. + + :Raise ValueError: + When the encoding is inconsistent, or the digest or salt lengths + are too big. + """ + + emLen = ceil_div(emBits, 8) + + # Bitmask of digits that fill up + lmask = 0 + for i in iter_range(8*emLen-emBits): + lmask = lmask >> 1 | 0x80 + + # Step 1 and 2 have been already done + # Step 3 + if emLen < mhash.digest_size+sLen+2: + raise ValueError("Incorrect signature") + # Step 4 + if ord(em[-1:]) != 0xBC: + raise ValueError("Incorrect signature") + # Step 5 + maskedDB = em[:emLen-mhash.digest_size-1] + h = em[emLen-mhash.digest_size-1:-1] + # Step 6 + if lmask & bord(em[0]): + raise ValueError("Incorrect signature") + # Step 7 + dbMask = mgf(h, emLen-mhash.digest_size-1) + # Step 8 + db = strxor(maskedDB, dbMask) + # Step 9 + db = bchr(bord(db[0]) & ~lmask) + db[1:] + # Step 10 + if not db.startswith(bchr(0)*(emLen-mhash.digest_size-sLen-2) + bchr(1)): + raise ValueError("Incorrect signature") + # Step 11 + if sLen > 0: + salt = db[-sLen:] + else: + salt = b"" + # Step 12 + m_prime = bchr(0)*8 + mhash.digest() + salt + # Step 13 + hobj = mhash.new() + hobj.update(m_prime) + hp = hobj.digest() + # Step 14 + if h != hp: + raise ValueError("Incorrect signature") + + +def new(rsa_key, **kwargs): + """Create an object for making or verifying PKCS#1 PSS signatures. + + :parameter rsa_key: + The RSA key to use for signing or verifying the message. + This is a :class:`Cryptodome.PublicKey.RSA` object. + Signing is only possible when ``rsa_key`` is a **private** RSA key. + :type rsa_key: RSA object + + :Keyword Arguments: + + * *mask_func* (``callable``) -- + A function that returns the mask (as `bytes`). + It must accept two parameters: a seed (as `bytes`) + and the length of the data to return. + + If not specified, it will be the function :func:`MGF1` defined in + `RFC8017 `_ and + combined with the same hash algorithm applied to the + message to sign or verify. + + If you want to use a different function, for instance still :func:`MGF1` + but together with another hash, you can do:: + + from Cryptodome.Hash import SHA256 + from Cryptodome.Signature.pss import MGF1 + mgf = lambda x, y: MGF1(x, y, SHA256) + + * *salt_bytes* (``integer``) -- + Length of the salt, in bytes. + It is a value between 0 and ``emLen - hLen - 2``, where ``emLen`` + is the size of the RSA modulus and ``hLen`` is the size of the digest + applied to the message to sign or verify. + + The salt is generated internally, you don't need to provide it. + + If not specified, the salt length will be ``hLen``. + If it is zero, the signature scheme becomes deterministic. + + Note that in some implementations such as OpenSSL the default + salt length is ``emLen - hLen - 2`` (even though it is not more + secure than ``hLen``). + + * *rand_func* (``callable``) -- + A function that returns random ``bytes``, of the desired length. + The default is :func:`Cryptodome.Random.get_random_bytes`. + + :return: a :class:`PSS_SigScheme` signature object + """ + + mask_func = kwargs.pop("mask_func", None) + salt_len = kwargs.pop("salt_bytes", None) + rand_func = kwargs.pop("rand_func", None) + if rand_func is None: + rand_func = Random.get_random_bytes + if kwargs: + raise ValueError("Unknown keywords: " + str(kwargs.keys())) + return PSS_SigScheme(rsa_key, mask_func, salt_len, rand_func) diff --git a/venv/Lib/site-packages/Cryptodome/Signature/pss.pyi b/venv/Lib/site-packages/Cryptodome/Signature/pss.pyi new file mode 100644 index 0000000..84a960e --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Signature/pss.pyi @@ -0,0 +1,30 @@ +from typing import Union, Callable, Optional +from typing_extensions import Protocol + +from Cryptodome.PublicKey.RSA import RsaKey + + +class Hash(Protocol): + def digest(self) -> bytes: ... + def update(self, bytes) -> None: ... + + +class HashModule(Protocol): + @staticmethod + def new(data: Optional[bytes]) -> Hash: ... + + +MaskFunction = Callable[[bytes, int, Union[Hash, HashModule]], bytes] +RndFunction = Callable[[int], bytes] + +class PSS_SigScheme: + def __init__(self, key: RsaKey, mgfunc: MaskFunction, saltLen: int, randfunc: RndFunction) -> None: ... + def can_sign(self) -> bool: ... + def sign(self, msg_hash: Hash) -> bytes: ... + def verify(self, msg_hash: Hash, signature: bytes) -> None: ... + + +MGF1 : MaskFunction +def _EMSA_PSS_ENCODE(mhash: Hash, emBits: int, randFunc: RndFunction, mgf:MaskFunction, sLen: int) -> str: ... +def _EMSA_PSS_VERIFY(mhash: Hash, em: str, emBits: int, mgf: MaskFunction, sLen: int) -> None: ... +def new(rsa_key: RsaKey, **kwargs: Union[MaskFunction, RndFunction, int]) -> PSS_SigScheme: ... diff --git a/venv/Lib/site-packages/Cryptodome/Util/Counter.py b/venv/Lib/site-packages/Cryptodome/Util/Counter.py new file mode 100644 index 0000000..e3bdcbe --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Util/Counter.py @@ -0,0 +1,79 @@ +# -*- coding: utf-8 -*- +# +# Util/Counter.py : Fast counter for use with CTR-mode ciphers +# +# Written in 2008 by Dwayne C. Litzenberger +# +# =================================================================== +# The contents of this file are dedicated to the public domain. To +# the extent that dedication to the public domain is not available, +# everyone is granted a worldwide, perpetual, royalty-free, +# non-exclusive license to exercise all rights associated with the +# contents of this file for any purpose whatsoever. +# No rights are reserved. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# =================================================================== + +def new(nbits, prefix=b"", suffix=b"", initial_value=1, little_endian=False, allow_wraparound=False): + """Create a stateful counter block function suitable for CTR encryption modes. + + Each call to the function returns the next counter block. + Each counter block is made up by three parts: + + +------+--------------+-------+ + |prefix| counter value|postfix| + +------+--------------+-------+ + + The counter value is incremented by 1 at each call. + + Args: + nbits (integer): + Length of the desired counter value, in bits. It must be a multiple of 8. + prefix (byte string): + The constant prefix of the counter block. By default, no prefix is + used. + suffix (byte string): + The constant postfix of the counter block. By default, no suffix is + used. + initial_value (integer): + The initial value of the counter. Default value is 1. + Its length in bits must not exceed the argument ``nbits``. + little_endian (boolean): + If ``True``, the counter number will be encoded in little endian format. + If ``False`` (default), in big endian format. + allow_wraparound (boolean): + This parameter is ignored. + An ``OverflowError`` exception is always raised when the counter wraps + around to zero. + Returns: + An object that can be passed with the :data:`counter` parameter to a CTR mode + cipher. + + It must hold that *len(prefix) + nbits//8 + len(suffix)* matches the + block size of the underlying block cipher. + """ + + if (nbits % 8) != 0: + raise ValueError("'nbits' must be a multiple of 8") + + iv_bl = initial_value.bit_length() + if iv_bl > nbits: + raise ValueError("Initial value takes %d bits but it is longer than " + "the counter (%d bits)" % + (iv_bl, nbits)) + + # Ignore wraparound + return {"counter_len": nbits // 8, + "prefix": prefix, + "suffix": suffix, + "initial_value": initial_value, + "little_endian": little_endian + } diff --git a/venv/Lib/site-packages/Cryptodome/Util/Counter.pyi b/venv/Lib/site-packages/Cryptodome/Util/Counter.pyi new file mode 100644 index 0000000..fa2ffdd --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Util/Counter.pyi @@ -0,0 +1,5 @@ +from typing import Optional, Union, Dict + +def new(nbits: int, prefix: Optional[bytes]=..., suffix: Optional[bytes]=..., initial_value: Optional[int]=1, + little_endian: Optional[bool]=False, allow_wraparound: Optional[bool]=False) -> \ + Dict[str, Union[int, bytes, bool]]: ... diff --git a/venv/Lib/site-packages/Cryptodome/Util/Padding.py b/venv/Lib/site-packages/Cryptodome/Util/Padding.py new file mode 100644 index 0000000..1016568 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Util/Padding.py @@ -0,0 +1,119 @@ +# +# Util/Padding.py : Functions to manage padding +# +# =================================================================== +# +# Copyright (c) 2014, Legrandin +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# =================================================================== + +__all__ = [ 'pad', 'unpad' ] + +from Cryptodome.Util.py3compat import * + + +def pad(data_to_pad, block_size, style='pkcs7'): + """Apply standard padding. + + Args: + data_to_pad (byte string): + The data that needs to be padded. + block_size (integer): + The block boundary to use for padding. The output length is guaranteed + to be a multiple of :data:`block_size`. + style (string): + Padding algorithm. It can be *'pkcs7'* (default), *'iso7816'* or *'x923'*. + + Return: + byte string : the original data with the appropriate padding added at the end. + """ + + padding_len = block_size - len(data_to_pad) % block_size + + if style == 'pkcs7': + padding = bchr(padding_len) * padding_len + elif style == 'x923': + padding = bchr(0)*(padding_len-1) + bchr(padding_len) + elif style == 'iso7816': + padding = bchr(128) + bchr(0) * (padding_len-1) + else: + raise ValueError("Unknown padding style") + + return data_to_pad + padding + + +def unpad(padded_data, block_size, style='pkcs7'): + """Remove standard padding. + + Args: + padded_data (byte string): + A piece of data with padding that needs to be stripped. + block_size (integer): + The block boundary to use for padding. The input length + must be a multiple of :data:`block_size`. + style (string): + Padding algorithm. It can be *'pkcs7'* (default), *'iso7816'* or *'x923'*. + Return: + byte string : data without padding. + Raises: + ValueError: if the padding is incorrect. + """ + + pdata_len = len(padded_data) + + if pdata_len == 0: + raise ValueError("Zero-length input cannot be unpadded") + + if pdata_len % block_size: + raise ValueError("Input data is not padded") + + if style in ('pkcs7', 'x923'): + padding_len = bord(padded_data[-1]) + + if padding_len < 1 or padding_len > min(block_size, pdata_len): + raise ValueError("Padding is incorrect.") + + if style == 'pkcs7': + if padded_data[-padding_len:] != bchr(padding_len)*padding_len: + raise ValueError("PKCS#7 padding is incorrect.") + else: + if padded_data[-padding_len:-1] != bchr(0)*(padding_len-1): + raise ValueError("ANSI X.923 padding is incorrect.") + + elif style == 'iso7816': + padding_len = pdata_len - padded_data.rfind(bchr(128)) + + if padding_len < 1 or padding_len > min(block_size, pdata_len): + raise ValueError("Padding is incorrect.") + + if padding_len > 1 and padded_data[1-padding_len:] != bchr(0)*(padding_len-1): + raise ValueError("ISO 7816-4 padding is incorrect.") + else: + raise ValueError("Unknown padding style") + + return padded_data[:-padding_len] + diff --git a/venv/Lib/site-packages/Cryptodome/Util/Padding.pyi b/venv/Lib/site-packages/Cryptodome/Util/Padding.pyi new file mode 100644 index 0000000..4d8d30d --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Util/Padding.pyi @@ -0,0 +1,6 @@ +from typing import Optional + +__all__ = [ 'pad', 'unpad' ] + +def pad(data_to_pad: bytes, block_size: int, style: Optional[str]='pkcs7') -> bytes: ... +def unpad(padded_data: bytes, block_size: int, style: Optional[str]='pkcs7') -> bytes: ... \ No newline at end of file diff --git a/venv/Lib/site-packages/Cryptodome/Util/RFC1751.py b/venv/Lib/site-packages/Cryptodome/Util/RFC1751.py new file mode 100644 index 0000000..10859c3 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Util/RFC1751.py @@ -0,0 +1,386 @@ +# rfc1751.py : Converts between 128-bit strings and a human-readable +# sequence of words, as defined in RFC1751: "A Convention for +# Human-Readable 128-bit Keys", by Daniel L. McDonald. +# +# Part of the Python Cryptography Toolkit +# +# Written by Andrew M. Kuchling and others +# +# =================================================================== +# The contents of this file are dedicated to the public domain. To +# the extent that dedication to the public domain is not available, +# everyone is granted a worldwide, perpetual, royalty-free, +# non-exclusive license to exercise all rights associated with the +# contents of this file for any purpose whatsoever. +# No rights are reserved. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# =================================================================== + +from __future__ import print_function + +import binascii + +from Cryptodome.Util.py3compat import bord, bchr + +binary = {0: '0000', 1: '0001', 2: '0010', 3: '0011', 4: '0100', 5: '0101', + 6: '0110', 7: '0111', 8: '1000', 9: '1001', 10: '1010', 11: '1011', + 12: '1100', 13: '1101', 14: '1110', 15: '1111'} + + +def _key2bin(s): + "Convert a key into a string of binary digits" + kl = map(lambda x: bord(x), s) + kl = map(lambda x: binary[x >> 4] + binary[x & 15], kl) + return ''.join(kl) + + +def _extract(key, start, length): + """Extract a bitstring(2.x)/bytestring(2.x) from a string of binary digits, and return its + numeric value.""" + + result = 0 + for y in key[start:start+length]: + result = result * 2 + ord(y) - 48 + return result + + +def key_to_english(key): + """Transform an arbitrary key into a string containing English words. + + Example:: + + >>> from Cryptodome.Util.RFC1751 import key_to_english + >>> key_to_english(b'66666666') + 'RAM LOIS GOAD CREW CARE HIT' + + Args: + key (byte string): + The key to convert. Its length must be a multiple of 8. + Return: + A string of English words. + """ + + if len(key) % 8 != 0: + raise ValueError('The length of the key must be a multiple of 8.') + + english = '' + for index in range(0, len(key), 8): # Loop over 8-byte subkeys + subkey = key[index:index + 8] + # Compute the parity of the key + skbin = _key2bin(subkey) + p = 0 + for i in range(0, 64, 2): + p = p + _extract(skbin, i, 2) + # Append parity bits to the subkey + skbin = _key2bin(subkey + bchr((p << 6) & 255)) + for i in range(0, 64, 11): + english = english + wordlist[_extract(skbin, i, 11)] + ' ' + + return english.strip() + + +def english_to_key(s): + """Transform a string into a corresponding key. + + Example:: + + >>> from Cryptodome.Util.RFC1751 import english_to_key + >>> english_to_key('RAM LOIS GOAD CREW CARE HIT') + b'66666666' + + Args: + s (string): the string with the words separated by whitespace; + the number of words must be a multiple of 6. + Return: + A byte string. + """ + + L = s.upper().split() + key = b'' + for index in range(0, len(L), 6): + sublist = L[index:index + 6] + char = 9 * [0] + bits = 0 + for i in sublist: + index = wordlist.index(i) + shift = (8 - (bits + 11) % 8) % 8 + y = index << shift + cl, cc, cr = (y >> 16), (y >> 8) & 0xff, y & 0xff + if (shift > 5): + char[bits >> 3] = char[bits >> 3] | cl + char[(bits >> 3) + 1] = char[(bits >> 3) + 1] | cc + char[(bits >> 3) + 2] = char[(bits >> 3) + 2] | cr + elif shift > -3: + char[bits >> 3] = char[bits >> 3] | cc + char[(bits >> 3) + 1] = char[(bits >> 3) + 1] | cr + else: + char[bits >> 3] = char[bits >> 3] | cr + bits = bits + 11 + + subkey = b'' + for y in char: + subkey = subkey + bchr(y) + + # Check the parity of the resulting key + skbin = _key2bin(subkey) + p = 0 + for i in range(0, 64, 2): + p = p + _extract(skbin, i, 2) + if (p & 3) != _extract(skbin, 64, 2): + raise ValueError("Parity error in resulting key") + key = key + subkey[0:8] + return key + + +wordlist = [ + "A", "ABE", "ACE", "ACT", "AD", "ADA", "ADD", + "AGO", "AID", "AIM", "AIR", "ALL", "ALP", "AM", "AMY", "AN", "ANA", + "AND", "ANN", "ANT", "ANY", "APE", "APS", "APT", "ARC", "ARE", "ARK", + "ARM", "ART", "AS", "ASH", "ASK", "AT", "ATE", "AUG", "AUK", "AVE", + "AWE", "AWK", "AWL", "AWN", "AX", "AYE", "BAD", "BAG", "BAH", "BAM", + "BAN", "BAR", "BAT", "BAY", "BE", "BED", "BEE", "BEG", "BEN", "BET", + "BEY", "BIB", "BID", "BIG", "BIN", "BIT", "BOB", "BOG", "BON", "BOO", + "BOP", "BOW", "BOY", "BUB", "BUD", "BUG", "BUM", "BUN", "BUS", "BUT", + "BUY", "BY", "BYE", "CAB", "CAL", "CAM", "CAN", "CAP", "CAR", "CAT", + "CAW", "COD", "COG", "COL", "CON", "COO", "COP", "COT", "COW", "COY", + "CRY", "CUB", "CUE", "CUP", "CUR", "CUT", "DAB", "DAD", "DAM", "DAN", + "DAR", "DAY", "DEE", "DEL", "DEN", "DES", "DEW", "DID", "DIE", "DIG", + "DIN", "DIP", "DO", "DOE", "DOG", "DON", "DOT", "DOW", "DRY", "DUB", + "DUD", "DUE", "DUG", "DUN", "EAR", "EAT", "ED", "EEL", "EGG", "EGO", + "ELI", "ELK", "ELM", "ELY", "EM", "END", "EST", "ETC", "EVA", "EVE", + "EWE", "EYE", "FAD", "FAN", "FAR", "FAT", "FAY", "FED", "FEE", "FEW", + "FIB", "FIG", "FIN", "FIR", "FIT", "FLO", "FLY", "FOE", "FOG", "FOR", + "FRY", "FUM", "FUN", "FUR", "GAB", "GAD", "GAG", "GAL", "GAM", "GAP", + "GAS", "GAY", "GEE", "GEL", "GEM", "GET", "GIG", "GIL", "GIN", "GO", + "GOT", "GUM", "GUN", "GUS", "GUT", "GUY", "GYM", "GYP", "HA", "HAD", + "HAL", "HAM", "HAN", "HAP", "HAS", "HAT", "HAW", "HAY", "HE", "HEM", + "HEN", "HER", "HEW", "HEY", "HI", "HID", "HIM", "HIP", "HIS", "HIT", + "HO", "HOB", "HOC", "HOE", "HOG", "HOP", "HOT", "HOW", "HUB", "HUE", + "HUG", "HUH", "HUM", "HUT", "I", "ICY", "IDA", "IF", "IKE", "ILL", + "INK", "INN", "IO", "ION", "IQ", "IRA", "IRE", "IRK", "IS", "IT", + "ITS", "IVY", "JAB", "JAG", "JAM", "JAN", "JAR", "JAW", "JAY", "JET", + "JIG", "JIM", "JO", "JOB", "JOE", "JOG", "JOT", "JOY", "JUG", "JUT", + "KAY", "KEG", "KEN", "KEY", "KID", "KIM", "KIN", "KIT", "LA", "LAB", + "LAC", "LAD", "LAG", "LAM", "LAP", "LAW", "LAY", "LEA", "LED", "LEE", + "LEG", "LEN", "LEO", "LET", "LEW", "LID", "LIE", "LIN", "LIP", "LIT", + "LO", "LOB", "LOG", "LOP", "LOS", "LOT", "LOU", "LOW", "LOY", "LUG", + "LYE", "MA", "MAC", "MAD", "MAE", "MAN", "MAO", "MAP", "MAT", "MAW", + "MAY", "ME", "MEG", "MEL", "MEN", "MET", "MEW", "MID", "MIN", "MIT", + "MOB", "MOD", "MOE", "MOO", "MOP", "MOS", "MOT", "MOW", "MUD", "MUG", + "MUM", "MY", "NAB", "NAG", "NAN", "NAP", "NAT", "NAY", "NE", "NED", + "NEE", "NET", "NEW", "NIB", "NIL", "NIP", "NIT", "NO", "NOB", "NOD", + "NON", "NOR", "NOT", "NOV", "NOW", "NU", "NUN", "NUT", "O", "OAF", + "OAK", "OAR", "OAT", "ODD", "ODE", "OF", "OFF", "OFT", "OH", "OIL", + "OK", "OLD", "ON", "ONE", "OR", "ORB", "ORE", "ORR", "OS", "OTT", + "OUR", "OUT", "OVA", "OW", "OWE", "OWL", "OWN", "OX", "PA", "PAD", + "PAL", "PAM", "PAN", "PAP", "PAR", "PAT", "PAW", "PAY", "PEA", "PEG", + "PEN", "PEP", "PER", "PET", "PEW", "PHI", "PI", "PIE", "PIN", "PIT", + "PLY", "PO", "POD", "POE", "POP", "POT", "POW", "PRO", "PRY", "PUB", + "PUG", "PUN", "PUP", "PUT", "QUO", "RAG", "RAM", "RAN", "RAP", "RAT", + "RAW", "RAY", "REB", "RED", "REP", "RET", "RIB", "RID", "RIG", "RIM", + "RIO", "RIP", "ROB", "ROD", "ROE", "RON", "ROT", "ROW", "ROY", "RUB", + "RUE", "RUG", "RUM", "RUN", "RYE", "SAC", "SAD", "SAG", "SAL", "SAM", + "SAN", "SAP", "SAT", "SAW", "SAY", "SEA", "SEC", "SEE", "SEN", "SET", + "SEW", "SHE", "SHY", "SIN", "SIP", "SIR", "SIS", "SIT", "SKI", "SKY", + "SLY", "SO", "SOB", "SOD", "SON", "SOP", "SOW", "SOY", "SPA", "SPY", + "SUB", "SUD", "SUE", "SUM", "SUN", "SUP", "TAB", "TAD", "TAG", "TAN", + "TAP", "TAR", "TEA", "TED", "TEE", "TEN", "THE", "THY", "TIC", "TIE", + "TIM", "TIN", "TIP", "TO", "TOE", "TOG", "TOM", "TON", "TOO", "TOP", + "TOW", "TOY", "TRY", "TUB", "TUG", "TUM", "TUN", "TWO", "UN", "UP", + "US", "USE", "VAN", "VAT", "VET", "VIE", "WAD", "WAG", "WAR", "WAS", + "WAY", "WE", "WEB", "WED", "WEE", "WET", "WHO", "WHY", "WIN", "WIT", + "WOK", "WON", "WOO", "WOW", "WRY", "WU", "YAM", "YAP", "YAW", "YE", + "YEA", "YES", "YET", "YOU", "ABED", "ABEL", "ABET", "ABLE", "ABUT", + "ACHE", "ACID", "ACME", "ACRE", "ACTA", "ACTS", "ADAM", "ADDS", + "ADEN", "AFAR", "AFRO", "AGEE", "AHEM", "AHOY", "AIDA", "AIDE", + "AIDS", "AIRY", "AJAR", "AKIN", "ALAN", "ALEC", "ALGA", "ALIA", + "ALLY", "ALMA", "ALOE", "ALSO", "ALTO", "ALUM", "ALVA", "AMEN", + "AMES", "AMID", "AMMO", "AMOK", "AMOS", "AMRA", "ANDY", "ANEW", + "ANNA", "ANNE", "ANTE", "ANTI", "AQUA", "ARAB", "ARCH", "AREA", + "ARGO", "ARID", "ARMY", "ARTS", "ARTY", "ASIA", "ASKS", "ATOM", + "AUNT", "AURA", "AUTO", "AVER", "AVID", "AVIS", "AVON", "AVOW", + "AWAY", "AWRY", "BABE", "BABY", "BACH", "BACK", "BADE", "BAIL", + "BAIT", "BAKE", "BALD", "BALE", "BALI", "BALK", "BALL", "BALM", + "BAND", "BANE", "BANG", "BANK", "BARB", "BARD", "BARE", "BARK", + "BARN", "BARR", "BASE", "BASH", "BASK", "BASS", "BATE", "BATH", + "BAWD", "BAWL", "BEAD", "BEAK", "BEAM", "BEAN", "BEAR", "BEAT", + "BEAU", "BECK", "BEEF", "BEEN", "BEER", + "BEET", "BELA", "BELL", "BELT", "BEND", "BENT", "BERG", "BERN", + "BERT", "BESS", "BEST", "BETA", "BETH", "BHOY", "BIAS", "BIDE", + "BIEN", "BILE", "BILK", "BILL", "BIND", "BING", "BIRD", "BITE", + "BITS", "BLAB", "BLAT", "BLED", "BLEW", "BLOB", "BLOC", "BLOT", + "BLOW", "BLUE", "BLUM", "BLUR", "BOAR", "BOAT", "BOCA", "BOCK", + "BODE", "BODY", "BOGY", "BOHR", "BOIL", "BOLD", "BOLO", "BOLT", + "BOMB", "BONA", "BOND", "BONE", "BONG", "BONN", "BONY", "BOOK", + "BOOM", "BOON", "BOOT", "BORE", "BORG", "BORN", "BOSE", "BOSS", + "BOTH", "BOUT", "BOWL", "BOYD", "BRAD", "BRAE", "BRAG", "BRAN", + "BRAY", "BRED", "BREW", "BRIG", "BRIM", "BROW", "BUCK", "BUDD", + "BUFF", "BULB", "BULK", "BULL", "BUNK", "BUNT", "BUOY", "BURG", + "BURL", "BURN", "BURR", "BURT", "BURY", "BUSH", "BUSS", "BUST", + "BUSY", "BYTE", "CADY", "CAFE", "CAGE", "CAIN", "CAKE", "CALF", + "CALL", "CALM", "CAME", "CANE", "CANT", "CARD", "CARE", "CARL", + "CARR", "CART", "CASE", "CASH", "CASK", "CAST", "CAVE", "CEIL", + "CELL", "CENT", "CERN", "CHAD", "CHAR", "CHAT", "CHAW", "CHEF", + "CHEN", "CHEW", "CHIC", "CHIN", "CHOU", "CHOW", "CHUB", "CHUG", + "CHUM", "CITE", "CITY", "CLAD", "CLAM", "CLAN", "CLAW", "CLAY", + "CLOD", "CLOG", "CLOT", "CLUB", "CLUE", "COAL", "COAT", "COCA", + "COCK", "COCO", "CODA", "CODE", "CODY", "COED", "COIL", "COIN", + "COKE", "COLA", "COLD", "COLT", "COMA", "COMB", "COME", "COOK", + "COOL", "COON", "COOT", "CORD", "CORE", "CORK", "CORN", "COST", + "COVE", "COWL", "CRAB", "CRAG", "CRAM", "CRAY", "CREW", "CRIB", + "CROW", "CRUD", "CUBA", "CUBE", "CUFF", "CULL", "CULT", "CUNY", + "CURB", "CURD", "CURE", "CURL", "CURT", "CUTS", "DADE", "DALE", + "DAME", "DANA", "DANE", "DANG", "DANK", "DARE", "DARK", "DARN", + "DART", "DASH", "DATA", "DATE", "DAVE", "DAVY", "DAWN", "DAYS", + "DEAD", "DEAF", "DEAL", "DEAN", "DEAR", "DEBT", "DECK", "DEED", + "DEEM", "DEER", "DEFT", "DEFY", "DELL", "DENT", "DENY", "DESK", + "DIAL", "DICE", "DIED", "DIET", "DIME", "DINE", "DING", "DINT", + "DIRE", "DIRT", "DISC", "DISH", "DISK", "DIVE", "DOCK", "DOES", + "DOLE", "DOLL", "DOLT", "DOME", "DONE", "DOOM", "DOOR", "DORA", + "DOSE", "DOTE", "DOUG", "DOUR", "DOVE", "DOWN", "DRAB", "DRAG", + "DRAM", "DRAW", "DREW", "DRUB", "DRUG", "DRUM", "DUAL", "DUCK", + "DUCT", "DUEL", "DUET", "DUKE", "DULL", "DUMB", "DUNE", "DUNK", + "DUSK", "DUST", "DUTY", "EACH", "EARL", "EARN", "EASE", "EAST", + "EASY", "EBEN", "ECHO", "EDDY", "EDEN", "EDGE", "EDGY", "EDIT", + "EDNA", "EGAN", "ELAN", "ELBA", "ELLA", "ELSE", "EMIL", "EMIT", + "EMMA", "ENDS", "ERIC", "EROS", "EVEN", "EVER", "EVIL", "EYED", + "FACE", "FACT", "FADE", "FAIL", "FAIN", "FAIR", "FAKE", "FALL", + "FAME", "FANG", "FARM", "FAST", "FATE", "FAWN", "FEAR", "FEAT", + "FEED", "FEEL", "FEET", "FELL", "FELT", "FEND", "FERN", "FEST", + "FEUD", "FIEF", "FIGS", "FILE", "FILL", "FILM", "FIND", "FINE", + "FINK", "FIRE", "FIRM", "FISH", "FISK", "FIST", "FITS", "FIVE", + "FLAG", "FLAK", "FLAM", "FLAT", "FLAW", "FLEA", "FLED", "FLEW", + "FLIT", "FLOC", "FLOG", "FLOW", "FLUB", "FLUE", "FOAL", "FOAM", + "FOGY", "FOIL", "FOLD", "FOLK", "FOND", "FONT", "FOOD", "FOOL", + "FOOT", "FORD", "FORE", "FORK", "FORM", "FORT", "FOSS", "FOUL", + "FOUR", "FOWL", "FRAU", "FRAY", "FRED", "FREE", "FRET", "FREY", + "FROG", "FROM", "FUEL", "FULL", "FUME", "FUND", "FUNK", "FURY", + "FUSE", "FUSS", "GAFF", "GAGE", "GAIL", "GAIN", "GAIT", "GALA", + "GALE", "GALL", "GALT", "GAME", "GANG", "GARB", "GARY", "GASH", + "GATE", "GAUL", "GAUR", "GAVE", "GAWK", "GEAR", "GELD", "GENE", + "GENT", "GERM", "GETS", "GIBE", "GIFT", "GILD", "GILL", "GILT", + "GINA", "GIRD", "GIRL", "GIST", "GIVE", "GLAD", "GLEE", "GLEN", + "GLIB", "GLOB", "GLOM", "GLOW", "GLUE", "GLUM", "GLUT", "GOAD", + "GOAL", "GOAT", "GOER", "GOES", "GOLD", "GOLF", "GONE", "GONG", + "GOOD", "GOOF", "GORE", "GORY", "GOSH", "GOUT", "GOWN", "GRAB", + "GRAD", "GRAY", "GREG", "GREW", "GREY", "GRID", "GRIM", "GRIN", + "GRIT", "GROW", "GRUB", "GULF", "GULL", "GUNK", "GURU", "GUSH", + "GUST", "GWEN", "GWYN", "HAAG", "HAAS", "HACK", "HAIL", "HAIR", + "HALE", "HALF", "HALL", "HALO", "HALT", "HAND", "HANG", "HANK", + "HANS", "HARD", "HARK", "HARM", "HART", "HASH", "HAST", "HATE", + "HATH", "HAUL", "HAVE", "HAWK", "HAYS", "HEAD", "HEAL", "HEAR", + "HEAT", "HEBE", "HECK", "HEED", "HEEL", "HEFT", "HELD", "HELL", + "HELM", "HERB", "HERD", "HERE", "HERO", "HERS", "HESS", "HEWN", + "HICK", "HIDE", "HIGH", "HIKE", "HILL", "HILT", "HIND", "HINT", + "HIRE", "HISS", "HIVE", "HOBO", "HOCK", "HOFF", "HOLD", "HOLE", + "HOLM", "HOLT", "HOME", "HONE", "HONK", "HOOD", "HOOF", "HOOK", + "HOOT", "HORN", "HOSE", "HOST", "HOUR", "HOVE", "HOWE", "HOWL", + "HOYT", "HUCK", "HUED", "HUFF", "HUGE", "HUGH", "HUGO", "HULK", + "HULL", "HUNK", "HUNT", "HURD", "HURL", "HURT", "HUSH", "HYDE", + "HYMN", "IBIS", "ICON", "IDEA", "IDLE", "IFFY", "INCA", "INCH", + "INTO", "IONS", "IOTA", "IOWA", "IRIS", "IRMA", "IRON", "ISLE", + "ITCH", "ITEM", "IVAN", "JACK", "JADE", "JAIL", "JAKE", "JANE", + "JAVA", "JEAN", "JEFF", "JERK", "JESS", "JEST", "JIBE", "JILL", + "JILT", "JIVE", "JOAN", "JOBS", "JOCK", "JOEL", "JOEY", "JOHN", + "JOIN", "JOKE", "JOLT", "JOVE", "JUDD", "JUDE", "JUDO", "JUDY", + "JUJU", "JUKE", "JULY", "JUNE", "JUNK", "JUNO", "JURY", "JUST", + "JUTE", "KAHN", "KALE", "KANE", "KANT", "KARL", "KATE", "KEEL", + "KEEN", "KENO", "KENT", "KERN", "KERR", "KEYS", "KICK", "KILL", + "KIND", "KING", "KIRK", "KISS", "KITE", "KLAN", "KNEE", "KNEW", + "KNIT", "KNOB", "KNOT", "KNOW", "KOCH", "KONG", "KUDO", "KURD", + "KURT", "KYLE", "LACE", "LACK", "LACY", "LADY", "LAID", "LAIN", + "LAIR", "LAKE", "LAMB", "LAME", "LAND", "LANE", "LANG", "LARD", + "LARK", "LASS", "LAST", "LATE", "LAUD", "LAVA", "LAWN", "LAWS", + "LAYS", "LEAD", "LEAF", "LEAK", "LEAN", "LEAR", "LEEK", "LEER", + "LEFT", "LEND", "LENS", "LENT", "LEON", "LESK", "LESS", "LEST", + "LETS", "LIAR", "LICE", "LICK", "LIED", "LIEN", "LIES", "LIEU", + "LIFE", "LIFT", "LIKE", "LILA", "LILT", "LILY", "LIMA", "LIMB", + "LIME", "LIND", "LINE", "LINK", "LINT", "LION", "LISA", "LIST", + "LIVE", "LOAD", "LOAF", "LOAM", "LOAN", "LOCK", "LOFT", "LOGE", + "LOIS", "LOLA", "LONE", "LONG", "LOOK", "LOON", "LOOT", "LORD", + "LORE", "LOSE", "LOSS", "LOST", "LOUD", "LOVE", "LOWE", "LUCK", + "LUCY", "LUGE", "LUKE", "LULU", "LUND", "LUNG", "LURA", "LURE", + "LURK", "LUSH", "LUST", "LYLE", "LYNN", "LYON", "LYRA", "MACE", + "MADE", "MAGI", "MAID", "MAIL", "MAIN", "MAKE", "MALE", "MALI", + "MALL", "MALT", "MANA", "MANN", "MANY", "MARC", "MARE", "MARK", + "MARS", "MART", "MARY", "MASH", "MASK", "MASS", "MAST", "MATE", + "MATH", "MAUL", "MAYO", "MEAD", "MEAL", "MEAN", "MEAT", "MEEK", + "MEET", "MELD", "MELT", "MEMO", "MEND", "MENU", "MERT", "MESH", + "MESS", "MICE", "MIKE", "MILD", "MILE", "MILK", "MILL", "MILT", + "MIMI", "MIND", "MINE", "MINI", "MINK", "MINT", "MIRE", "MISS", + "MIST", "MITE", "MITT", "MOAN", "MOAT", "MOCK", "MODE", "MOLD", + "MOLE", "MOLL", "MOLT", "MONA", "MONK", "MONT", "MOOD", "MOON", + "MOOR", "MOOT", "MORE", "MORN", "MORT", "MOSS", "MOST", "MOTH", + "MOVE", "MUCH", "MUCK", "MUDD", "MUFF", "MULE", "MULL", "MURK", + "MUSH", "MUST", "MUTE", "MUTT", "MYRA", "MYTH", "NAGY", "NAIL", + "NAIR", "NAME", "NARY", "NASH", "NAVE", "NAVY", "NEAL", "NEAR", + "NEAT", "NECK", "NEED", "NEIL", "NELL", "NEON", "NERO", "NESS", + "NEST", "NEWS", "NEWT", "NIBS", "NICE", "NICK", "NILE", "NINA", + "NINE", "NOAH", "NODE", "NOEL", "NOLL", "NONE", "NOOK", "NOON", + "NORM", "NOSE", "NOTE", "NOUN", "NOVA", "NUDE", "NULL", "NUMB", + "OATH", "OBEY", "OBOE", "ODIN", "OHIO", "OILY", "OINT", "OKAY", + "OLAF", "OLDY", "OLGA", "OLIN", "OMAN", "OMEN", "OMIT", "ONCE", + "ONES", "ONLY", "ONTO", "ONUS", "ORAL", "ORGY", "OSLO", "OTIS", + "OTTO", "OUCH", "OUST", "OUTS", "OVAL", "OVEN", "OVER", "OWLY", + "OWNS", "QUAD", "QUIT", "QUOD", "RACE", "RACK", "RACY", "RAFT", + "RAGE", "RAID", "RAIL", "RAIN", "RAKE", "RANK", "RANT", "RARE", + "RASH", "RATE", "RAVE", "RAYS", "READ", "REAL", "REAM", "REAR", + "RECK", "REED", "REEF", "REEK", "REEL", "REID", "REIN", "RENA", + "REND", "RENT", "REST", "RICE", "RICH", "RICK", "RIDE", "RIFT", + "RILL", "RIME", "RING", "RINK", "RISE", "RISK", "RITE", "ROAD", + "ROAM", "ROAR", "ROBE", "ROCK", "RODE", "ROIL", "ROLL", "ROME", + "ROOD", "ROOF", "ROOK", "ROOM", "ROOT", "ROSA", "ROSE", "ROSS", + "ROSY", "ROTH", "ROUT", "ROVE", "ROWE", "ROWS", "RUBE", "RUBY", + "RUDE", "RUDY", "RUIN", "RULE", "RUNG", "RUNS", "RUNT", "RUSE", + "RUSH", "RUSK", "RUSS", "RUST", "RUTH", "SACK", "SAFE", "SAGE", + "SAID", "SAIL", "SALE", "SALK", "SALT", "SAME", "SAND", "SANE", + "SANG", "SANK", "SARA", "SAUL", "SAVE", "SAYS", "SCAN", "SCAR", + "SCAT", "SCOT", "SEAL", "SEAM", "SEAR", "SEAT", "SEED", "SEEK", + "SEEM", "SEEN", "SEES", "SELF", "SELL", "SEND", "SENT", "SETS", + "SEWN", "SHAG", "SHAM", "SHAW", "SHAY", "SHED", "SHIM", "SHIN", + "SHOD", "SHOE", "SHOT", "SHOW", "SHUN", "SHUT", "SICK", "SIDE", + "SIFT", "SIGH", "SIGN", "SILK", "SILL", "SILO", "SILT", "SINE", + "SING", "SINK", "SIRE", "SITE", "SITS", "SITU", "SKAT", "SKEW", + "SKID", "SKIM", "SKIN", "SKIT", "SLAB", "SLAM", "SLAT", "SLAY", + "SLED", "SLEW", "SLID", "SLIM", "SLIT", "SLOB", "SLOG", "SLOT", + "SLOW", "SLUG", "SLUM", "SLUR", "SMOG", "SMUG", "SNAG", "SNOB", + "SNOW", "SNUB", "SNUG", "SOAK", "SOAR", "SOCK", "SODA", "SOFA", + "SOFT", "SOIL", "SOLD", "SOME", "SONG", "SOON", "SOOT", "SORE", + "SORT", "SOUL", "SOUR", "SOWN", "STAB", "STAG", "STAN", "STAR", + "STAY", "STEM", "STEW", "STIR", "STOW", "STUB", "STUN", "SUCH", + "SUDS", "SUIT", "SULK", "SUMS", "SUNG", "SUNK", "SURE", "SURF", + "SWAB", "SWAG", "SWAM", "SWAN", "SWAT", "SWAY", "SWIM", "SWUM", + "TACK", "TACT", "TAIL", "TAKE", "TALE", "TALK", "TALL", "TANK", + "TASK", "TATE", "TAUT", "TEAL", "TEAM", "TEAR", "TECH", "TEEM", + "TEEN", "TEET", "TELL", "TEND", "TENT", "TERM", "TERN", "TESS", + "TEST", "THAN", "THAT", "THEE", "THEM", "THEN", "THEY", "THIN", + "THIS", "THUD", "THUG", "TICK", "TIDE", "TIDY", "TIED", "TIER", + "TILE", "TILL", "TILT", "TIME", "TINA", "TINE", "TINT", "TINY", + "TIRE", "TOAD", "TOGO", "TOIL", "TOLD", "TOLL", "TONE", "TONG", + "TONY", "TOOK", "TOOL", "TOOT", "TORE", "TORN", "TOTE", "TOUR", + "TOUT", "TOWN", "TRAG", "TRAM", "TRAY", "TREE", "TREK", "TRIG", + "TRIM", "TRIO", "TROD", "TROT", "TROY", "TRUE", "TUBA", "TUBE", + "TUCK", "TUFT", "TUNA", "TUNE", "TUNG", "TURF", "TURN", "TUSK", + "TWIG", "TWIN", "TWIT", "ULAN", "UNIT", "URGE", "USED", "USER", + "USES", "UTAH", "VAIL", "VAIN", "VALE", "VARY", "VASE", "VAST", + "VEAL", "VEDA", "VEIL", "VEIN", "VEND", "VENT", "VERB", "VERY", + "VETO", "VICE", "VIEW", "VINE", "VISE", "VOID", "VOLT", "VOTE", + "WACK", "WADE", "WAGE", "WAIL", "WAIT", "WAKE", "WALE", "WALK", + "WALL", "WALT", "WAND", "WANE", "WANG", "WANT", "WARD", "WARM", + "WARN", "WART", "WASH", "WAST", "WATS", "WATT", "WAVE", "WAVY", + "WAYS", "WEAK", "WEAL", "WEAN", "WEAR", "WEED", "WEEK", "WEIR", + "WELD", "WELL", "WELT", "WENT", "WERE", "WERT", "WEST", "WHAM", + "WHAT", "WHEE", "WHEN", "WHET", "WHOA", "WHOM", "WICK", "WIFE", + "WILD", "WILL", "WIND", "WINE", "WING", "WINK", "WINO", "WIRE", + "WISE", "WISH", "WITH", "WOLF", "WONT", "WOOD", "WOOL", "WORD", + "WORE", "WORK", "WORM", "WORN", "WOVE", "WRIT", "WYNN", "YALE", + "YANG", "YANK", "YARD", "YARN", "YAWL", "YAWN", "YEAH", "YEAR", + "YELL", "YOGA", "YOKE" ] diff --git a/venv/Lib/site-packages/Cryptodome/Util/RFC1751.pyi b/venv/Lib/site-packages/Cryptodome/Util/RFC1751.pyi new file mode 100644 index 0000000..6ad07ff --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Util/RFC1751.pyi @@ -0,0 +1,7 @@ +from typing import Dict, List + +binary: Dict[int, str] +wordlist: List[str] + +def key_to_english(key: bytes) -> str: ... +def english_to_key(s: str) -> bytes: ... diff --git a/venv/Lib/site-packages/Cryptodome/Util/__init__.py b/venv/Lib/site-packages/Cryptodome/Util/__init__.py new file mode 100644 index 0000000..1862b82 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Util/__init__.py @@ -0,0 +1,41 @@ +# -*- coding: utf-8 -*- +# +# =================================================================== +# The contents of this file are dedicated to the public domain. To +# the extent that dedication to the public domain is not available, +# everyone is granted a worldwide, perpetual, royalty-free, +# non-exclusive license to exercise all rights associated with the +# contents of this file for any purpose whatsoever. +# No rights are reserved. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# =================================================================== + +"""Miscellaneous modules + +Contains useful modules that don't belong into any of the +other Cryptodome.* subpackages. + +======================== ============================================= +Module Description +======================== ============================================= +`Cryptodome.Util.number` Number-theoretic functions (primality testing, etc.) +`Cryptodome.Util.Counter` Fast counter functions for CTR cipher modes. +`Cryptodome.Util.RFC1751` Converts between 128-bit keys and human-readable + strings of words. +`Cryptodome.Util.asn1` Minimal support for ASN.1 DER encoding +`Cryptodome.Util.Padding` Set of functions for adding and removing padding. +======================== ============================================= + +:undocumented: _galois, _number_new, cpuid, py3compat, _raw_api +""" + +__all__ = ['RFC1751', 'number', 'strxor', 'asn1', 'Counter', 'Padding'] + diff --git a/venv/Lib/site-packages/Cryptodome/Util/__pycache__/Counter.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/Util/__pycache__/Counter.cpython-312.pyc new file mode 100644 index 0000000..681505d Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Util/__pycache__/Counter.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/Util/__pycache__/Padding.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/Util/__pycache__/Padding.cpython-312.pyc new file mode 100644 index 0000000..36a61bd Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Util/__pycache__/Padding.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/Util/__pycache__/RFC1751.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/Util/__pycache__/RFC1751.cpython-312.pyc new file mode 100644 index 0000000..b32a11a Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Util/__pycache__/RFC1751.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/Util/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/Util/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000..b67a6fc Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Util/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/Util/__pycache__/_cpu_features.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/Util/__pycache__/_cpu_features.cpython-312.pyc new file mode 100644 index 0000000..67a10c7 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Util/__pycache__/_cpu_features.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/Util/__pycache__/_file_system.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/Util/__pycache__/_file_system.cpython-312.pyc new file mode 100644 index 0000000..b8fa7ea Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Util/__pycache__/_file_system.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/Util/__pycache__/_raw_api.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/Util/__pycache__/_raw_api.cpython-312.pyc new file mode 100644 index 0000000..db9c8b0 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Util/__pycache__/_raw_api.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/Util/__pycache__/asn1.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/Util/__pycache__/asn1.cpython-312.pyc new file mode 100644 index 0000000..7106f19 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Util/__pycache__/asn1.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/Util/__pycache__/number.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/Util/__pycache__/number.cpython-312.pyc new file mode 100644 index 0000000..7b8ea49 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Util/__pycache__/number.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/Util/__pycache__/py3compat.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/Util/__pycache__/py3compat.cpython-312.pyc new file mode 100644 index 0000000..bbdfad5 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Util/__pycache__/py3compat.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/Util/__pycache__/strxor.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/Util/__pycache__/strxor.cpython-312.pyc new file mode 100644 index 0000000..f1ff3fd Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Util/__pycache__/strxor.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/Util/_cpu_features.py b/venv/Lib/site-packages/Cryptodome/Util/_cpu_features.py new file mode 100644 index 0000000..4794a02 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Util/_cpu_features.py @@ -0,0 +1,46 @@ +# =================================================================== +# +# Copyright (c) 2018, Helder Eijs +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# =================================================================== + +from Cryptodome.Util._raw_api import load_pycryptodome_raw_lib + + +_raw_cpuid_lib = load_pycryptodome_raw_lib("Cryptodome.Util._cpuid_c", + """ + int have_aes_ni(void); + int have_clmul(void); + """) + + +def have_aes_ni(): + return _raw_cpuid_lib.have_aes_ni() + + +def have_clmul(): + return _raw_cpuid_lib.have_clmul() diff --git a/venv/Lib/site-packages/Cryptodome/Util/_cpu_features.pyi b/venv/Lib/site-packages/Cryptodome/Util/_cpu_features.pyi new file mode 100644 index 0000000..10e669e --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Util/_cpu_features.pyi @@ -0,0 +1,2 @@ +def have_aes_ni() -> int: ... +def have_clmul() -> int: ... diff --git a/venv/Lib/site-packages/Cryptodome/Util/_cpuid_c.pyd b/venv/Lib/site-packages/Cryptodome/Util/_cpuid_c.pyd new file mode 100644 index 0000000..e197508 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Util/_cpuid_c.pyd differ diff --git a/venv/Lib/site-packages/Cryptodome/Util/_file_system.py b/venv/Lib/site-packages/Cryptodome/Util/_file_system.py new file mode 100644 index 0000000..282f0dc --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Util/_file_system.py @@ -0,0 +1,54 @@ +# =================================================================== +# +# Copyright (c) 2016, Legrandin +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# =================================================================== + +import os + + +def pycryptodome_filename(dir_comps, filename): + """Return the complete file name for the module + + dir_comps : list of string + The list of directory names in the PyCryptodome package. + The first element must be "Cryptodome". + + filename : string + The filename (inclusing extension) in the target directory. + """ + + if dir_comps[0] != "Cryptodome": + raise ValueError("Only available for modules under 'Cryptodome'") + + dir_comps = list(dir_comps[1:]) + [filename] + + util_lib, _ = os.path.split(os.path.abspath(__file__)) + root_lib = os.path.join(util_lib, "..") + + return os.path.join(root_lib, *dir_comps) + diff --git a/venv/Lib/site-packages/Cryptodome/Util/_file_system.pyi b/venv/Lib/site-packages/Cryptodome/Util/_file_system.pyi new file mode 100644 index 0000000..d54a126 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Util/_file_system.pyi @@ -0,0 +1,4 @@ +from typing import List + + +def pycryptodome_filename(dir_comps: List[str], filename: str) -> str: ... \ No newline at end of file diff --git a/venv/Lib/site-packages/Cryptodome/Util/_raw_api.py b/venv/Lib/site-packages/Cryptodome/Util/_raw_api.py new file mode 100644 index 0000000..cd64ac8 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Util/_raw_api.py @@ -0,0 +1,325 @@ +# =================================================================== +# +# Copyright (c) 2014, Legrandin +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# =================================================================== + +import os +import abc +import sys +from Cryptodome.Util.py3compat import byte_string +from Cryptodome.Util._file_system import pycryptodome_filename + +# +# List of file suffixes for Python extensions +# +if sys.version_info[0] < 3: + + import imp + extension_suffixes = [] + for ext, mod, typ in imp.get_suffixes(): + if typ == imp.C_EXTENSION: + extension_suffixes.append(ext) + +else: + + from importlib import machinery + extension_suffixes = machinery.EXTENSION_SUFFIXES + +# Which types with buffer interface we support (apart from byte strings) +_buffer_type = (bytearray, memoryview) + + +class _VoidPointer(object): + @abc.abstractmethod + def get(self): + """Return the memory location we point to""" + return + + @abc.abstractmethod + def address_of(self): + """Return a raw pointer to this pointer""" + return + + +try: + # Starting from v2.18, pycparser (used by cffi for in-line ABI mode) + # stops working correctly when PYOPTIMIZE==2 or the parameter -OO is + # passed. In that case, we fall back to ctypes. + # Note that PyPy ships with an old version of pycparser so we can keep + # using cffi there. + # See https://github.com/Legrandin/pycryptodome/issues/228 + if '__pypy__' not in sys.builtin_module_names and sys.flags.optimize == 2: + raise ImportError("CFFI with optimize=2 fails due to pycparser bug.") + + # cffi still uses PyUnicode_GetSize, which was removed in Python 3.12 + # thus leading to a crash on cffi.dlopen() + # See https://groups.google.com/u/1/g/python-cffi/c/oZkOIZ_zi5k + if sys.version_info >= (3, 12) and os.name == "nt": + raise ImportError("CFFI is not compatible with Python 3.12 on Windows") + + from cffi import FFI + + ffi = FFI() + null_pointer = ffi.NULL + uint8_t_type = ffi.typeof(ffi.new("const uint8_t*")) + + _Array = ffi.new("uint8_t[1]").__class__.__bases__ + + def load_lib(name, cdecl): + """Load a shared library and return a handle to it. + + @name, either an absolute path or the name of a library + in the system search path. + + @cdecl, the C function declarations. + """ + + if hasattr(ffi, "RTLD_DEEPBIND") and not os.getenv('PYCRYPTODOME_DISABLE_DEEPBIND'): + lib = ffi.dlopen(name, ffi.RTLD_DEEPBIND) + else: + lib = ffi.dlopen(name) + ffi.cdef(cdecl) + return lib + + def c_ulong(x): + """Convert a Python integer to unsigned long""" + return x + + c_ulonglong = c_ulong + c_uint = c_ulong + c_ubyte = c_ulong + + def c_size_t(x): + """Convert a Python integer to size_t""" + return x + + def create_string_buffer(init_or_size, size=None): + """Allocate the given amount of bytes (initially set to 0)""" + + if isinstance(init_or_size, bytes): + size = max(len(init_or_size) + 1, size) + result = ffi.new("uint8_t[]", size) + result[:] = init_or_size + else: + if size: + raise ValueError("Size must be specified once only") + result = ffi.new("uint8_t[]", init_or_size) + return result + + def get_c_string(c_string): + """Convert a C string into a Python byte sequence""" + return ffi.string(c_string) + + def get_raw_buffer(buf): + """Convert a C buffer into a Python byte sequence""" + return ffi.buffer(buf)[:] + + def c_uint8_ptr(data): + if isinstance(data, _buffer_type): + # This only works for cffi >= 1.7 + return ffi.cast(uint8_t_type, ffi.from_buffer(data)) + elif byte_string(data) or isinstance(data, _Array): + return data + else: + raise TypeError("Object type %s cannot be passed to C code" % type(data)) + + class VoidPointer_cffi(_VoidPointer): + """Model a newly allocated pointer to void""" + + def __init__(self): + self._pp = ffi.new("void *[1]") + + def get(self): + return self._pp[0] + + def address_of(self): + return self._pp + + def VoidPointer(): + return VoidPointer_cffi() + + backend = "cffi" + +except ImportError: + + import ctypes + from ctypes import (CDLL, c_void_p, byref, c_ulong, c_ulonglong, c_size_t, + create_string_buffer, c_ubyte, c_uint) + from ctypes.util import find_library + from ctypes import Array as _Array + + null_pointer = None + cached_architecture = [] + + def c_ubyte(c): + if not (0 <= c < 256): + raise OverflowError() + return ctypes.c_ubyte(c) + + def load_lib(name, cdecl): + if not cached_architecture: + # platform.architecture() creates a subprocess, so caching the + # result makes successive imports faster. + import platform + cached_architecture[:] = platform.architecture() + bits, linkage = cached_architecture + if "." not in name and not linkage.startswith("Win"): + full_name = find_library(name) + if full_name is None: + raise OSError("Cannot load library '%s'" % name) + name = full_name + return CDLL(name) + + def get_c_string(c_string): + return c_string.value + + def get_raw_buffer(buf): + return buf.raw + + # ---- Get raw pointer --- + + _c_ssize_t = ctypes.c_ssize_t + + _PyBUF_SIMPLE = 0 + _PyObject_GetBuffer = ctypes.pythonapi.PyObject_GetBuffer + _PyBuffer_Release = ctypes.pythonapi.PyBuffer_Release + _py_object = ctypes.py_object + _c_ssize_p = ctypes.POINTER(_c_ssize_t) + + # See Include/object.h for CPython + # and https://github.com/pallets/click/blob/master/src/click/_winconsole.py + class _Py_buffer(ctypes.Structure): + _fields_ = [ + ('buf', c_void_p), + ('obj', ctypes.py_object), + ('len', _c_ssize_t), + ('itemsize', _c_ssize_t), + ('readonly', ctypes.c_int), + ('ndim', ctypes.c_int), + ('format', ctypes.c_char_p), + ('shape', _c_ssize_p), + ('strides', _c_ssize_p), + ('suboffsets', _c_ssize_p), + ('internal', c_void_p) + ] + + # Extra field for CPython 2.6/2.7 + if sys.version_info[0] == 2: + _fields_.insert(-1, ('smalltable', _c_ssize_t * 2)) + + def c_uint8_ptr(data): + if byte_string(data) or isinstance(data, _Array): + return data + elif isinstance(data, _buffer_type): + obj = _py_object(data) + buf = _Py_buffer() + _PyObject_GetBuffer(obj, byref(buf), _PyBUF_SIMPLE) + try: + buffer_type = ctypes.c_ubyte * buf.len + return buffer_type.from_address(buf.buf) + finally: + _PyBuffer_Release(byref(buf)) + else: + raise TypeError("Object type %s cannot be passed to C code" % type(data)) + + # --- + + class VoidPointer_ctypes(_VoidPointer): + """Model a newly allocated pointer to void""" + + def __init__(self): + self._p = c_void_p() + + def get(self): + return self._p + + def address_of(self): + return byref(self._p) + + def VoidPointer(): + return VoidPointer_ctypes() + + backend = "ctypes" + + +class SmartPointer(object): + """Class to hold a non-managed piece of memory""" + + def __init__(self, raw_pointer, destructor): + self._raw_pointer = raw_pointer + self._destructor = destructor + + def get(self): + return self._raw_pointer + + def release(self): + rp, self._raw_pointer = self._raw_pointer, None + return rp + + def __del__(self): + try: + if self._raw_pointer is not None: + self._destructor(self._raw_pointer) + self._raw_pointer = None + except AttributeError: + pass + + +def load_pycryptodome_raw_lib(name, cdecl): + """Load a shared library and return a handle to it. + + @name, the name of the library expressed as a PyCryptodome module, + for instance Cryptodome.Cipher._raw_cbc. + + @cdecl, the C function declarations. + """ + + split = name.split(".") + dir_comps, basename = split[:-1], split[-1] + attempts = [] + for ext in extension_suffixes: + try: + filename = basename + ext + full_name = pycryptodome_filename(dir_comps, filename) + if not os.path.isfile(full_name): + attempts.append("Not found '%s'" % filename) + continue + return load_lib(full_name, cdecl) + except OSError as exp: + attempts.append("Cannot load '%s': %s" % (filename, str(exp))) + raise OSError("Cannot load native module '%s': %s" % (name, ", ".join(attempts))) + + +def is_buffer(x): + """Return True if object x supports the buffer interface""" + return isinstance(x, (bytes, bytearray, memoryview)) + + +def is_writeable_buffer(x): + return (isinstance(x, bytearray) or + (isinstance(x, memoryview) and not x.readonly)) diff --git a/venv/Lib/site-packages/Cryptodome/Util/_raw_api.pyi b/venv/Lib/site-packages/Cryptodome/Util/_raw_api.pyi new file mode 100644 index 0000000..2bc5301 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Util/_raw_api.pyi @@ -0,0 +1,27 @@ +from typing import Any, Optional, Union + +def load_lib(name: str, cdecl: str) -> Any : ... +def c_ulong(x: int ) -> Any : ... +def c_ulonglong(x: int ) -> Any : ... +def c_size_t(x: int) -> Any : ... +def create_string_buffer(init_or_size: Union[bytes,int], size: Optional[int]) -> Any : ... +def get_c_string(c_string: Any) -> bytes : ... +def get_raw_buffer(buf: Any) -> bytes : ... +def c_uint8_ptr(data: Union[bytes, memoryview, bytearray]) -> Any : ... + +class VoidPointer(object): + def get(self) -> Any : ... + def address_of(self) -> Any : ... + +class SmartPointer(object): + def __init__(self, raw_pointer: Any, destructor: Any) -> None : ... + def get(self) -> Any : ... + def release(self) -> Any : ... + +backend : str +null_pointer : Any +ffi: Any + +def load_pycryptodome_raw_lib(name: str, cdecl: str) -> Any : ... +def is_buffer(x: Any) -> bool : ... +def is_writeable_buffer(x: Any) -> bool : ... diff --git a/venv/Lib/site-packages/Cryptodome/Util/_strxor.pyd b/venv/Lib/site-packages/Cryptodome/Util/_strxor.pyd new file mode 100644 index 0000000..17eeb27 Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/Util/_strxor.pyd differ diff --git a/venv/Lib/site-packages/Cryptodome/Util/asn1.py b/venv/Lib/site-packages/Cryptodome/Util/asn1.py new file mode 100644 index 0000000..9987fda --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Util/asn1.py @@ -0,0 +1,1064 @@ +# -*- coding: utf-8 -*- +# +# Util/asn1.py : Minimal support for ASN.1 DER binary encoding. +# +# =================================================================== +# The contents of this file are dedicated to the public domain. To +# the extent that dedication to the public domain is not available, +# everyone is granted a worldwide, perpetual, royalty-free, +# non-exclusive license to exercise all rights associated with the +# contents of this file for any purpose whatsoever. +# No rights are reserved. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# =================================================================== + +import struct + +from Cryptodome.Util.py3compat import byte_string, bchr, bord + +from Cryptodome.Util.number import long_to_bytes, bytes_to_long + +__all__ = ['DerObject', 'DerInteger', 'DerBoolean', 'DerOctetString', + 'DerNull', 'DerSequence', 'DerObjectId', 'DerBitString', 'DerSetOf'] + +# Useful references: +# - https://luca.ntop.org/Teaching/Appunti/asn1.html +# - https://letsencrypt.org/docs/a-warm-welcome-to-asn1-and-der/ +# - https://www.zytrax.com/tech/survival/asn1.html +# - https://www.oss.com/asn1/resources/books-whitepapers-pubs/larmouth-asn1-book.pdf +# - https://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf +# - https://misc.daniel-marschall.de/asn.1/oid-converter/online.php + +def _is_number(x, only_non_negative=False): + test = 0 + try: + test = x + test + except TypeError: + return False + return not only_non_negative or x >= 0 + + +class BytesIO_EOF(object): + """This class differs from BytesIO in that a ValueError exception is + raised whenever EOF is reached.""" + + def __init__(self, initial_bytes): + self._buffer = initial_bytes + self._index = 0 + self._bookmark = None + + def set_bookmark(self): + self._bookmark = self._index + + def data_since_bookmark(self): + assert self._bookmark is not None + return self._buffer[self._bookmark:self._index] + + def remaining_data(self): + return len(self._buffer) - self._index + + def read(self, length): + new_index = self._index + length + if new_index > len(self._buffer): + raise ValueError("Not enough data for DER decoding: expected %d bytes and found %d" % (new_index, len(self._buffer))) + + result = self._buffer[self._index:new_index] + self._index = new_index + return result + + def read_byte(self): + return bord(self.read(1)[0]) + + +class DerObject(object): + """Base class for defining a single DER object. + + This class should never be directly instantiated. + """ + + def __init__(self, asn1Id=None, payload=b'', implicit=None, + constructed=False, explicit=None): + """Initialize the DER object according to a specific ASN.1 type. + + :Parameters: + asn1Id : integer or byte + The universal DER tag number for this object + (e.g. 0x10 for a SEQUENCE). + If None, the tag is not known yet. + + payload : byte string + The initial payload of the object (that it, + the content octets). + If not specified, the payload is empty. + + implicit : integer or byte + The IMPLICIT tag number (< 0x1F) to use for the encoded object. + It overrides the universal tag *asn1Id*. + It cannot be combined with the ``explicit`` parameter. + By default, there is no IMPLICIT tag. + + constructed : bool + True when the ASN.1 type is *constructed*. + False when it is *primitive* (default). + + explicit : integer or byte + The EXPLICIT tag number (< 0x1F) to use for the encoded object. + It cannot be combined with the ``implicit`` parameter. + By default, there is no EXPLICIT tag. + """ + + if asn1Id is None: + # The tag octet will be read in with ``decode`` + self._tag_octet = None + return + asn1Id = self._convertTag(asn1Id) + + self.payload = payload + + # In a BER/DER identifier octet: + # * bits 4-0 contain the tag value + # * bit 5 is set if the type is 'constructed' + # and unset if 'primitive' + # * bits 7-6 depend on the encoding class + # + # Class | Bit 7, Bit 6 + # ---------------------------------- + # universal | 0 0 + # application | 0 1 + # context-spec | 1 0 (default for IMPLICIT/EXPLICIT) + # private | 1 1 + # + + constructed_bit = 0x20 if constructed else 0x00 + + if None not in (explicit, implicit): + raise ValueError("Explicit and implicit tags are" + " mutually exclusive") + + if implicit is not None: + # IMPLICIT tag overrides asn1Id + self._tag_octet = 0x80 | constructed_bit | self._convertTag(implicit) + elif explicit is not None: + # 'constructed bit' is always asserted for an EXPLICIT tag + self._tag_octet = 0x80 | 0x20 | self._convertTag(explicit) + self._inner_tag_octet = constructed_bit | asn1Id + else: + # Neither IMPLICIT nor EXPLICIT + self._tag_octet = constructed_bit | asn1Id + + def _convertTag(self, tag): + """Check if *tag* is a real DER tag (5 bits). + Convert it from a character to number if necessary. + """ + if not _is_number(tag): + if len(tag) == 1: + tag = bord(tag[0]) + # Ensure that tag is a low tag + if not (_is_number(tag) and 0 <= tag < 0x1F): + raise ValueError("Wrong DER tag") + return tag + + @staticmethod + def _definite_form(length): + """Build length octets according to BER/DER + definite form. + """ + if length > 127: + encoding = long_to_bytes(length) + return bchr(len(encoding) + 128) + encoding + return bchr(length) + + def encode(self): + """Return this DER element, fully encoded as a binary byte string.""" + + # Concatenate identifier octets, length octets, + # and contents octets + + output_payload = self.payload + + # In case of an EXTERNAL tag, first encode the inner + # element. + if hasattr(self, "_inner_tag_octet"): + output_payload = (bchr(self._inner_tag_octet) + + self._definite_form(len(self.payload)) + + self.payload) + + return (bchr(self._tag_octet) + + self._definite_form(len(output_payload)) + + output_payload) + + def _decodeLen(self, s): + """Decode DER length octets from a file.""" + + length = s.read_byte() + + if length > 127: + encoded_length = s.read(length & 0x7F) + if bord(encoded_length[0]) == 0: + raise ValueError("Invalid DER: length has leading zero") + length = bytes_to_long(encoded_length) + if length <= 127: + raise ValueError("Invalid DER: length in long form but smaller than 128") + + return length + + def decode(self, der_encoded, strict=False): + """Decode a complete DER element, and re-initializes this + object with it. + + Args: + der_encoded (byte string): A complete DER element. + + Raises: + ValueError: in case of parsing errors. + """ + + if not byte_string(der_encoded): + raise ValueError("Input is not a byte string") + + s = BytesIO_EOF(der_encoded) + self._decodeFromStream(s, strict) + + # There shouldn't be other bytes left + if s.remaining_data() > 0: + raise ValueError("Unexpected extra data after the DER structure") + + return self + + def _decodeFromStream(self, s, strict): + """Decode a complete DER element from a file.""" + + idOctet = s.read_byte() + if self._tag_octet is not None: + if idOctet != self._tag_octet: + raise ValueError("Unexpected DER tag") + else: + self._tag_octet = idOctet + length = self._decodeLen(s) + self.payload = s.read(length) + + # In case of an EXTERNAL tag, further decode the inner + # element. + if hasattr(self, "_inner_tag_octet"): + p = BytesIO_EOF(self.payload) + inner_octet = p.read_byte() + if inner_octet != self._inner_tag_octet: + raise ValueError("Unexpected internal DER tag") + length = self._decodeLen(p) + self.payload = p.read(length) + + # There shouldn't be other bytes left + if p.remaining_data() > 0: + raise ValueError("Unexpected extra data after the DER structure") + + +class DerInteger(DerObject): + """Class to model a DER INTEGER. + + An example of encoding is:: + + >>> from Cryptodome.Util.asn1 import DerInteger + >>> from binascii import hexlify, unhexlify + >>> int_der = DerInteger(9) + >>> print hexlify(int_der.encode()) + + which will show ``020109``, the DER encoding of 9. + + And for decoding:: + + >>> s = unhexlify(b'020109') + >>> try: + >>> int_der = DerInteger() + >>> int_der.decode(s) + >>> print int_der.value + >>> except ValueError: + >>> print "Not a valid DER INTEGER" + + the output will be ``9``. + + :ivar value: The integer value + :vartype value: integer + """ + + def __init__(self, value=0, implicit=None, explicit=None): + """Initialize the DER object as an INTEGER. + + :Parameters: + value : integer + The value of the integer. + + implicit : integer + The IMPLICIT tag to use for the encoded object. + It overrides the universal tag for INTEGER (2). + """ + + DerObject.__init__(self, 0x02, b'', implicit, + False, explicit) + self.value = value # The integer value + + def encode(self): + """Return the DER INTEGER, fully encoded as a + binary string.""" + + number = self.value + self.payload = b'' + while True: + self.payload = bchr(int(number & 255)) + self.payload + if 128 <= number <= 255: + self.payload = bchr(0x00) + self.payload + if -128 <= number <= 255: + break + number >>= 8 + return DerObject.encode(self) + + def decode(self, der_encoded, strict=False): + """Decode a DER-encoded INTEGER, and re-initializes this + object with it. + + Args: + der_encoded (byte string): A complete INTEGER DER element. + + Raises: + ValueError: in case of parsing errors. + """ + + return DerObject.decode(self, der_encoded, strict=strict) + + def _decodeFromStream(self, s, strict): + """Decode a complete DER INTEGER from a file.""" + + # Fill up self.payload + DerObject._decodeFromStream(self, s, strict) + + if strict: + if len(self.payload) == 0: + raise ValueError("Invalid encoding for DER INTEGER: empty payload") + if len(self.payload) >= 2 and struct.unpack('>H', self.payload[:2])[0] < 0x80: + raise ValueError("Invalid encoding for DER INTEGER: leading zero") + + # Derive self.value from self.payload + self.value = 0 + bits = 1 + for i in self.payload: + self.value *= 256 + self.value += bord(i) + bits <<= 8 + if self.payload and bord(self.payload[0]) & 0x80: + self.value -= bits + + +class DerBoolean(DerObject): + """Class to model a DER-encoded BOOLEAN. + + An example of encoding is:: + + >>> from Cryptodome.Util.asn1 import DerBoolean + >>> bool_der = DerBoolean(True) + >>> print(bool_der.encode().hex()) + + which will show ``0101ff``, the DER encoding of True. + + And for decoding:: + + >>> s = bytes.fromhex('0101ff') + >>> try: + >>> bool_der = DerBoolean() + >>> bool_der.decode(s) + >>> print(bool_der.value) + >>> except ValueError: + >>> print "Not a valid DER BOOLEAN" + + the output will be ``True``. + + :ivar value: The boolean value + :vartype value: boolean + """ + def __init__(self, value=False, implicit=None, explicit=None): + """Initialize the DER object as a BOOLEAN. + + Args: + value (boolean): + The value of the boolean. Default is False. + + implicit (integer or byte): + The IMPLICIT tag number (< 0x1F) to use for the encoded object. + It overrides the universal tag for BOOLEAN (1). + It cannot be combined with the ``explicit`` parameter. + By default, there is no IMPLICIT tag. + + explicit (integer or byte): + The EXPLICIT tag number (< 0x1F) to use for the encoded object. + It cannot be combined with the ``implicit`` parameter. + By default, there is no EXPLICIT tag. + """ + + DerObject.__init__(self, 0x01, b'', implicit, False, explicit) + self.value = value # The boolean value + + def encode(self): + """Return the DER BOOLEAN, fully encoded as a binary string.""" + + self.payload = b'\xFF' if self.value else b'\x00' + return DerObject.encode(self) + + def decode(self, der_encoded, strict=False): + """Decode a DER-encoded BOOLEAN, and re-initializes this object with it. + + Args: + der_encoded (byte string): A DER-encoded BOOLEAN. + + Raises: + ValueError: in case of parsing errors. + """ + + return DerObject.decode(self, der_encoded, strict) + + def _decodeFromStream(self, s, strict): + """Decode a DER-encoded BOOLEAN from a file.""" + + # Fill up self.payload + DerObject._decodeFromStream(self, s, strict) + + if len(self.payload) != 1: + raise ValueError("Invalid encoding for DER BOOLEAN: payload is not 1 byte") + + if bord(self.payload[0]) == 0: + self.value = False + elif bord(self.payload[0]) == 0xFF: + self.value = True + else: + raise ValueError("Invalid payload for DER BOOLEAN") + + +class DerSequence(DerObject): + """Class to model a DER SEQUENCE. + + This object behaves like a dynamic Python sequence. + + Sub-elements that are INTEGERs behave like Python integers. + + Any other sub-element is a binary string encoded as a complete DER + sub-element (TLV). + + An example of encoding is: + + >>> from Cryptodome.Util.asn1 import DerSequence, DerInteger + >>> from binascii import hexlify, unhexlify + >>> obj_der = unhexlify('070102') + >>> seq_der = DerSequence([4]) + >>> seq_der.append(9) + >>> seq_der.append(obj_der.encode()) + >>> print hexlify(seq_der.encode()) + + which will show ``3009020104020109070102``, the DER encoding of the + sequence containing ``4``, ``9``, and the object with payload ``02``. + + For decoding: + + >>> s = unhexlify(b'3009020104020109070102') + >>> try: + >>> seq_der = DerSequence() + >>> seq_der.decode(s) + >>> print len(seq_der) + >>> print seq_der[0] + >>> print seq_der[:] + >>> except ValueError: + >>> print "Not a valid DER SEQUENCE" + + the output will be:: + + 3 + 4 + [4, 9, b'\x07\x01\x02'] + + """ + + def __init__(self, startSeq=None, implicit=None, explicit=None): + """Initialize the DER object as a SEQUENCE. + + :Parameters: + startSeq : Python sequence + A sequence whose element are either integers or + other DER objects. + + implicit : integer or byte + The IMPLICIT tag number (< 0x1F) to use for the encoded object. + It overrides the universal tag for SEQUENCE (16). + It cannot be combined with the ``explicit`` parameter. + By default, there is no IMPLICIT tag. + + explicit : integer or byte + The EXPLICIT tag number (< 0x1F) to use for the encoded object. + It cannot be combined with the ``implicit`` parameter. + By default, there is no EXPLICIT tag. + """ + + DerObject.__init__(self, 0x10, b'', implicit, True, explicit) + if startSeq is None: + self._seq = [] + else: + self._seq = startSeq + + # A few methods to make it behave like a python sequence + + def __delitem__(self, n): + del self._seq[n] + + def __getitem__(self, n): + return self._seq[n] + + def __setitem__(self, key, value): + self._seq[key] = value + + def __setslice__(self, i, j, sequence): + self._seq[i:j] = sequence + + def __delslice__(self, i, j): + del self._seq[i:j] + + def __getslice__(self, i, j): + return self._seq[max(0, i):max(0, j)] + + def __len__(self): + return len(self._seq) + + def __iadd__(self, item): + self._seq.append(item) + return self + + def append(self, item): + self._seq.append(item) + return self + + def insert(self, index, item): + self._seq.insert(index, item) + return self + + def hasInts(self, only_non_negative=True): + """Return the number of items in this sequence that are + integers. + + Args: + only_non_negative (boolean): + If ``True``, negative integers are not counted in. + """ + + items = [x for x in self._seq if _is_number(x, only_non_negative)] + return len(items) + + def hasOnlyInts(self, only_non_negative=True): + """Return ``True`` if all items in this sequence are integers + or non-negative integers. + + This function returns False is the sequence is empty, + or at least one member is not an integer. + + Args: + only_non_negative (boolean): + If ``True``, the presence of negative integers + causes the method to return ``False``.""" + return self._seq and self.hasInts(only_non_negative) == len(self._seq) + + def encode(self): + """Return this DER SEQUENCE, fully encoded as a + binary string. + + Raises: + ValueError: if some elements in the sequence are neither integers + nor byte strings. + """ + self.payload = b'' + for item in self._seq: + if byte_string(item): + self.payload += item + elif _is_number(item): + self.payload += DerInteger(item).encode() + else: + self.payload += item.encode() + return DerObject.encode(self) + + def decode(self, der_encoded, strict=False, nr_elements=None, only_ints_expected=False): + """Decode a complete DER SEQUENCE, and re-initializes this + object with it. + + Args: + der_encoded (byte string): + A complete SEQUENCE DER element. + nr_elements (None or integer or list of integers): + The number of members the SEQUENCE can have + only_ints_expected (boolean): + Whether the SEQUENCE is expected to contain only integers. + strict (boolean): + Whether decoding must check for strict DER compliancy. + + Raises: + ValueError: in case of parsing errors. + + DER INTEGERs are decoded into Python integers. Any other DER + element is not decoded. Its validity is not checked. + """ + + self._nr_elements = nr_elements + result = DerObject.decode(self, der_encoded, strict=strict) + + if only_ints_expected and not self.hasOnlyInts(): + raise ValueError("Some members are not INTEGERs") + + return result + + def _decodeFromStream(self, s, strict): + """Decode a complete DER SEQUENCE from a file.""" + + self._seq = [] + + # Fill up self.payload + DerObject._decodeFromStream(self, s, strict) + + # Add one item at a time to self.seq, by scanning self.payload + p = BytesIO_EOF(self.payload) + while p.remaining_data() > 0: + p.set_bookmark() + + der = DerObject() + der._decodeFromStream(p, strict) + + # Parse INTEGERs differently + if der._tag_octet != 0x02: + self._seq.append(p.data_since_bookmark()) + else: + derInt = DerInteger() + data = p.data_since_bookmark() + derInt.decode(data, strict=strict) + self._seq.append(derInt.value) + + ok = True + if self._nr_elements is not None: + try: + ok = len(self._seq) in self._nr_elements + except TypeError: + ok = len(self._seq) == self._nr_elements + + if not ok: + raise ValueError("Unexpected number of members (%d)" + " in the sequence" % len(self._seq)) + + +class DerOctetString(DerObject): + """Class to model a DER OCTET STRING. + + An example of encoding is: + + >>> from Cryptodome.Util.asn1 import DerOctetString + >>> from binascii import hexlify, unhexlify + >>> os_der = DerOctetString(b'\\xaa') + >>> os_der.payload += b'\\xbb' + >>> print hexlify(os_der.encode()) + + which will show ``0402aabb``, the DER encoding for the byte string + ``b'\\xAA\\xBB'``. + + For decoding: + + >>> s = unhexlify(b'0402aabb') + >>> try: + >>> os_der = DerOctetString() + >>> os_der.decode(s) + >>> print hexlify(os_der.payload) + >>> except ValueError: + >>> print "Not a valid DER OCTET STRING" + + the output will be ``aabb``. + + :ivar payload: The content of the string + :vartype payload: byte string + """ + + def __init__(self, value=b'', implicit=None): + """Initialize the DER object as an OCTET STRING. + + :Parameters: + value : byte string + The initial payload of the object. + If not specified, the payload is empty. + + implicit : integer + The IMPLICIT tag to use for the encoded object. + It overrides the universal tag for OCTET STRING (4). + """ + DerObject.__init__(self, 0x04, value, implicit, False) + + +class DerNull(DerObject): + """Class to model a DER NULL element.""" + + def __init__(self): + """Initialize the DER object as a NULL.""" + + DerObject.__init__(self, 0x05, b'', None, False) + + +class DerObjectId(DerObject): + """Class to model a DER OBJECT ID. + + An example of encoding is: + + >>> from Cryptodome.Util.asn1 import DerObjectId + >>> from binascii import hexlify, unhexlify + >>> oid_der = DerObjectId("1.2") + >>> oid_der.value += ".840.113549.1.1.1" + >>> print hexlify(oid_der.encode()) + + which will show ``06092a864886f70d010101``, the DER encoding for the + RSA Object Identifier ``1.2.840.113549.1.1.1``. + + For decoding: + + >>> s = unhexlify(b'06092a864886f70d010101') + >>> try: + >>> oid_der = DerObjectId() + >>> oid_der.decode(s) + >>> print oid_der.value + >>> except ValueError: + >>> print "Not a valid DER OBJECT ID" + + the output will be ``1.2.840.113549.1.1.1``. + + :ivar value: The Object ID (OID), a dot separated list of integers + :vartype value: string + """ + + def __init__(self, value='', implicit=None, explicit=None): + """Initialize the DER object as an OBJECT ID. + + :Parameters: + value : string + The initial Object Identifier (e.g. "1.2.0.0.6.2"). + implicit : integer + The IMPLICIT tag to use for the encoded object. + It overrides the universal tag for OBJECT ID (6). + explicit : integer + The EXPLICIT tag to use for the encoded object. + """ + DerObject.__init__(self, 0x06, b'', implicit, False, explicit) + self.value = value + + def encode(self): + """Return the DER OBJECT ID, fully encoded as a + binary string.""" + + comps = [int(x) for x in self.value.split(".")] + + if len(comps) < 2: + raise ValueError("Not a valid Object Identifier string") + if comps[0] > 2: + raise ValueError("First component must be 0, 1 or 2") + if comps[0] < 2 and comps[1] > 39: + raise ValueError("Second component must be 39 at most") + + subcomps = [40 * comps[0] + comps[1]] + comps[2:] + + encoding = [] + for v in reversed(subcomps): + encoding.append(v & 0x7F) + v >>= 7 + while v: + encoding.append((v & 0x7F) | 0x80) + v >>= 7 + + self.payload = b''.join([bchr(x) for x in reversed(encoding)]) + return DerObject.encode(self) + + def decode(self, der_encoded, strict=False): + """Decode a complete DER OBJECT ID, and re-initializes this + object with it. + + Args: + der_encoded (byte string): + A complete DER OBJECT ID. + strict (boolean): + Whether decoding must check for strict DER compliancy. + + Raises: + ValueError: in case of parsing errors. + """ + + return DerObject.decode(self, der_encoded, strict) + + def _decodeFromStream(self, s, strict): + """Decode a complete DER OBJECT ID from a file.""" + + # Fill up self.payload + DerObject._decodeFromStream(self, s, strict) + + # Derive self.value from self.payload + p = BytesIO_EOF(self.payload) + + subcomps = [] + v = 0 + while p.remaining_data(): + c = p.read_byte() + v = (v << 7) + (c & 0x7F) + if not (c & 0x80): + subcomps.append(v) + v = 0 + + if len(subcomps) == 0: + raise ValueError("Empty payload") + + if subcomps[0] < 40: + subcomps[:1] = [0, subcomps[0]] + elif subcomps[0] < 80: + subcomps[:1] = [1, subcomps[0] - 40] + else: + subcomps[:1] = [2, subcomps[0] - 80] + + self.value = ".".join([str(x) for x in subcomps]) + + +class DerBitString(DerObject): + """Class to model a DER BIT STRING. + + An example of encoding is: + + >>> from Cryptodome.Util.asn1 import DerBitString + >>> bs_der = DerBitString(b'\\xAA') + >>> bs_der.value += b'\\xBB' + >>> print(bs_der.encode().hex()) + + which will show ``030300aabb``, the DER encoding for the bit string + ``b'\\xAA\\xBB'``. + + For decoding: + + >>> s = bytes.fromhex('030300aabb') + >>> try: + >>> bs_der = DerBitString() + >>> bs_der.decode(s) + >>> print(bs_der.value.hex()) + >>> except ValueError: + >>> print "Not a valid DER BIT STRING" + + the output will be ``aabb``. + + :ivar value: The content of the string + :vartype value: byte string + """ + + def __init__(self, value=b'', implicit=None, explicit=None): + """Initialize the DER object as a BIT STRING. + + :Parameters: + value : byte string or DER object + The initial, packed bit string. + If not specified, the bit string is empty. + implicit : integer + The IMPLICIT tag to use for the encoded object. + It overrides the universal tag for BIT STRING (3). + explicit : integer + The EXPLICIT tag to use for the encoded object. + """ + DerObject.__init__(self, 0x03, b'', implicit, False, explicit) + + # The bitstring value (packed) + if isinstance(value, DerObject): + self.value = value.encode() + else: + self.value = value + + def encode(self): + """Return the DER BIT STRING, fully encoded as a + byte string.""" + + # Add padding count byte + self.payload = b'\x00' + self.value + return DerObject.encode(self) + + def decode(self, der_encoded, strict=False): + """Decode a complete DER BIT STRING, and re-initializes this + object with it. + + Args: + der_encoded (byte string): a complete DER BIT STRING. + strict (boolean): + Whether decoding must check for strict DER compliancy. + + Raises: + ValueError: in case of parsing errors. + """ + + return DerObject.decode(self, der_encoded, strict) + + def _decodeFromStream(self, s, strict): + """Decode a complete DER BIT STRING DER from a file.""" + + # Fill-up self.payload + DerObject._decodeFromStream(self, s, strict) + + if self.payload and bord(self.payload[0]) != 0: + raise ValueError("Not a valid BIT STRING") + + # Fill-up self.value + self.value = b'' + # Remove padding count byte + if self.payload: + self.value = self.payload[1:] + + +class DerSetOf(DerObject): + """Class to model a DER SET OF. + + An example of encoding is: + + >>> from Cryptodome.Util.asn1 import DerBitString + >>> from binascii import hexlify, unhexlify + >>> so_der = DerSetOf([4,5]) + >>> so_der.add(6) + >>> print hexlify(so_der.encode()) + + which will show ``3109020104020105020106``, the DER encoding + of a SET OF with items 4,5, and 6. + + For decoding: + + >>> s = unhexlify(b'3109020104020105020106') + >>> try: + >>> so_der = DerSetOf() + >>> so_der.decode(s) + >>> print [x for x in so_der] + >>> except ValueError: + >>> print "Not a valid DER SET OF" + + the output will be ``[4, 5, 6]``. + """ + + def __init__(self, startSet=None, implicit=None): + """Initialize the DER object as a SET OF. + + :Parameters: + startSet : container + The initial set of integers or DER encoded objects. + implicit : integer + The IMPLICIT tag to use for the encoded object. + It overrides the universal tag for SET OF (17). + """ + DerObject.__init__(self, 0x11, b'', implicit, True) + self._seq = [] + + # All elements must be of the same type (and therefore have the + # same leading octet) + self._elemOctet = None + + if startSet: + for e in startSet: + self.add(e) + + def __getitem__(self, n): + return self._seq[n] + + def __iter__(self): + return iter(self._seq) + + def __len__(self): + return len(self._seq) + + def add(self, elem): + """Add an element to the set. + + Args: + elem (byte string or integer): + An element of the same type of objects already in the set. + It can be an integer or a DER encoded object. + """ + + if _is_number(elem): + eo = 0x02 + elif isinstance(elem, DerObject): + eo = self._tag_octet + else: + eo = bord(elem[0]) + + if self._elemOctet != eo: + if self._elemOctet is not None: + raise ValueError("New element does not belong to the set") + self._elemOctet = eo + + if elem not in self._seq: + self._seq.append(elem) + + def decode(self, der_encoded, strict=False): + """Decode a complete SET OF DER element, and re-initializes this + object with it. + + DER INTEGERs are decoded into Python integers. Any other DER + element is left undecoded; its validity is not checked. + + Args: + der_encoded (byte string): a complete DER BIT SET OF. + strict (boolean): + Whether decoding must check for strict DER compliancy. + + Raises: + ValueError: in case of parsing errors. + """ + + return DerObject.decode(self, der_encoded, strict) + + def _decodeFromStream(self, s, strict): + """Decode a complete DER SET OF from a file.""" + + self._seq = [] + + # Fill up self.payload + DerObject._decodeFromStream(self, s, strict) + + # Add one item at a time to self.seq, by scanning self.payload + p = BytesIO_EOF(self.payload) + setIdOctet = -1 + while p.remaining_data() > 0: + p.set_bookmark() + + der = DerObject() + der._decodeFromStream(p, strict) + + # Verify that all members are of the same type + if setIdOctet < 0: + setIdOctet = der._tag_octet + else: + if setIdOctet != der._tag_octet: + raise ValueError("Not all elements are of the same DER type") + + # Parse INTEGERs differently + if setIdOctet != 0x02: + self._seq.append(p.data_since_bookmark()) + else: + derInt = DerInteger() + derInt.decode(p.data_since_bookmark(), strict) + self._seq.append(derInt.value) + # end + + def encode(self): + """Return this SET OF DER element, fully encoded as a + binary string. + """ + + # Elements in the set must be ordered in lexicographic order + ordered = [] + for item in self._seq: + if _is_number(item): + bys = DerInteger(item).encode() + elif isinstance(item, DerObject): + bys = item.encode() + else: + bys = item + ordered.append(bys) + ordered.sort() + self.payload = b''.join(ordered) + return DerObject.encode(self) diff --git a/venv/Lib/site-packages/Cryptodome/Util/asn1.pyi b/venv/Lib/site-packages/Cryptodome/Util/asn1.pyi new file mode 100644 index 0000000..ee4891c --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Util/asn1.pyi @@ -0,0 +1,80 @@ +from typing import Optional, Sequence, Union, Set, Iterable + +__all__ = ['DerObject', 'DerInteger', 'DerOctetString', 'DerNull', + 'DerSequence', 'DerObjectId', 'DerBitString', 'DerSetOf'] + +# TODO: Make the encoded DerObjects their own type, so that DerSequence and +# DerSetOf can check their contents better + +class BytesIO_EOF: + def __init__(self, initial_bytes: bytes) -> None: ... + def set_bookmark(self) -> None: ... + def data_since_bookmark(self) -> bytes: ... + def remaining_data(self) -> int: ... + def read(self, length: int) -> bytes: ... + def read_byte(self) -> bytes: ... + +class DerObject: + payload: bytes + def __init__(self, asn1Id: Optional[int]=None, payload: Optional[bytes]=..., implicit: Optional[int]=None, + constructed: Optional[bool]=False, explicit: Optional[int]=None) -> None: ... + def encode(self) -> bytes: ... + def decode(self, der_encoded: bytes, strict: bool=...) -> DerObject: ... + +class DerInteger(DerObject): + value: int + def __init__(self, value: Optional[int]= 0, implicit: Optional[int]=None, explicit: Optional[int]=None) -> None: ... + def encode(self) -> bytes: ... + def decode(self, der_encoded: bytes, strict: bool=...) -> DerInteger: ... + +class DerBoolean(DerObject): + value: bool + def __init__(self, value: bool=..., implicit: Optional[Union[int, bytes]]=..., explicit: Optional[Union[int, bytes]]=...) -> None: ... + def encode(self) -> bytes: ... + def decode(self, der_encoded: bytes, strict: bool=...) -> DerBoolean: ... + +class DerSequence(DerObject): + def __init__(self, startSeq: Optional[Sequence[Union[int, DerInteger, DerObject]]]=None, implicit: Optional[int]=None) -> None: ... + def __delitem__(self, n: int) -> None: ... + def __getitem__(self, n: int) -> None: ... + def __setitem__(self, key: int, value: DerObject) -> None: ... + def __setslice__(self, i: int, j: int, sequence: Sequence) -> None: ... + def __delslice__(self, i: int, j: int) -> None: ... + def __getslice__(self, i: int, j: int) -> DerSequence: ... + def __len__(self) -> int: ... + def __iadd__(self, item: DerObject) -> DerSequence: ... + def append(self, item: DerObject) -> DerSequence: ... + def hasInts(self, only_non_negative: Optional[bool]=True) -> int: ... + def hasOnlyInts(self, only_non_negative: Optional[bool]=True) -> bool: ... + def encode(self) -> bytes: ... + def decode(self, der_encoded: bytes, strict: bool=..., nr_elements: Optional[int]=None, only_ints_expected: Optional[bool]=False) -> DerSequence: ... + +class DerOctetString(DerObject): + payload: bytes + def __init__(self, value: Optional[bytes]=..., implicit: Optional[int]=None) -> None: ... + +class DerNull(DerObject): + def __init__(self) -> None: ... + +class DerObjectId(DerObject): + value: str + def __init__(self, value: Optional[str]=..., implicit: Optional[int]=None, explicit: Optional[int]=None) -> None: ... + def encode(self) -> bytes: ... + def decode(self, der_encoded: bytes, strict: bool=...) -> DerObjectId: ... + +class DerBitString(DerObject): + value: bytes + def __init__(self, value: Optional[bytes]=..., implicit: Optional[int]=None, explicit: Optional[int]=None) -> None: ... + def encode(self) -> bytes: ... + def decode(self, der_encoded: bytes, strict: bool=...) -> DerBitString: ... + +DerSetElement = Union[bytes, int] + +class DerSetOf(DerObject): + def __init__(self, startSet: Optional[Set[DerSetElement]]=None, implicit: Optional[int]=None) -> None: ... + def __getitem__(self, n: int) -> DerSetElement: ... + def __iter__(self) -> Iterable: ... + def __len__(self) -> int: ... + def add(self, elem: DerSetElement) -> None: ... + def decode(self, der_encoded: bytes, strict: bool=...) -> DerObject: ... + def encode(self) -> bytes: ... diff --git a/venv/Lib/site-packages/Cryptodome/Util/number.py b/venv/Lib/site-packages/Cryptodome/Util/number.py new file mode 100644 index 0000000..701c21c --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Util/number.py @@ -0,0 +1,1525 @@ +# +# number.py : Number-theoretic functions +# +# Part of the Python Cryptography Toolkit +# +# Written by Andrew M. Kuchling, Barry A. Warsaw, and others +# +# =================================================================== +# The contents of this file are dedicated to the public domain. To +# the extent that dedication to the public domain is not available, +# everyone is granted a worldwide, perpetual, royalty-free, +# non-exclusive license to exercise all rights associated with the +# contents of this file for any purpose whatsoever. +# No rights are reserved. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# =================================================================== +# + +import math +import sys +import struct +from Cryptodome import Random +from Cryptodome.Util.py3compat import iter_range + +# Backward compatibility +_fastmath = None + + +def ceil_div(n, d): + """Return ceil(n/d), that is, the smallest integer r such that r*d >= n""" + + if d == 0: + raise ZeroDivisionError() + if (n < 0) or (d < 0): + raise ValueError("Non positive values") + r, q = divmod(n, d) + if (n != 0) and (q != 0): + r += 1 + return r + + +def size (N): + """Returns the size of the number N in bits.""" + + if N < 0: + raise ValueError("Size in bits only available for non-negative numbers") + return N.bit_length() + + +def getRandomInteger(N, randfunc=None): + """Return a random number at most N bits long. + + If :data:`randfunc` is omitted, then :meth:`Random.get_random_bytes` is used. + + .. deprecated:: 3.0 + This function is for internal use only and may be renamed or removed in + the future. Use :func:`Cryptodome.Random.random.getrandbits` instead. + """ + + if randfunc is None: + randfunc = Random.get_random_bytes + + S = randfunc(N>>3) + odd_bits = N % 8 + if odd_bits != 0: + rand_bits = ord(randfunc(1)) >> (8-odd_bits) + S = struct.pack('B', rand_bits) + S + value = bytes_to_long(S) + return value + +def getRandomRange(a, b, randfunc=None): + """Return a random number *n* so that *a <= n < b*. + + If :data:`randfunc` is omitted, then :meth:`Random.get_random_bytes` is used. + + .. deprecated:: 3.0 + This function is for internal use only and may be renamed or removed in + the future. Use :func:`Cryptodome.Random.random.randrange` instead. + """ + + range_ = b - a - 1 + bits = size(range_) + value = getRandomInteger(bits, randfunc) + while value > range_: + value = getRandomInteger(bits, randfunc) + return a + value + +def getRandomNBitInteger(N, randfunc=None): + """Return a random number with exactly N-bits, + i.e. a random number between 2**(N-1) and (2**N)-1. + + If :data:`randfunc` is omitted, then :meth:`Random.get_random_bytes` is used. + + .. deprecated:: 3.0 + This function is for internal use only and may be renamed or removed in + the future. + """ + + value = getRandomInteger (N-1, randfunc) + value |= 2 ** (N-1) # Ensure high bit is set + assert size(value) >= N + return value + + +if sys.version_info[:2] >= (3, 5): + + GCD = math.gcd + +else: + + def GCD(x,y): + """Greatest Common Denominator of :data:`x` and :data:`y`. + """ + + x = abs(x) ; y = abs(y) + while x > 0: + x, y = y % x, x + return y + + +if sys.version_info[:2] >= (3, 8): + + def inverse(u, v): + """The inverse of :data:`u` *mod* :data:`v`.""" + + if v == 0: + raise ZeroDivisionError("Modulus cannot be zero") + if v < 0: + raise ValueError("Modulus cannot be negative") + + return pow(u, -1, v) + +else: + + def inverse(u, v): + """The inverse of :data:`u` *mod* :data:`v`.""" + + if v == 0: + raise ZeroDivisionError("Modulus cannot be zero") + if v < 0: + raise ValueError("Modulus cannot be negative") + + u3, v3 = u, v + u1, v1 = 1, 0 + while v3 > 0: + q = u3 // v3 + u1, v1 = v1, u1 - v1*q + u3, v3 = v3, u3 - v3*q + if u3 != 1: + raise ValueError("No inverse value can be computed") + while u1<0: + u1 = u1 + v + return u1 + +# Given a number of bits to generate and a random generation function, +# find a prime number of the appropriate size. + +def getPrime(N, randfunc=None): + """Return a random N-bit prime number. + + N must be an integer larger than 1. + If randfunc is omitted, then :meth:`Random.get_random_bytes` is used. + """ + if randfunc is None: + randfunc = Random.get_random_bytes + + if N < 2: + raise ValueError("N must be larger than 1") + + while True: + number = getRandomNBitInteger(N, randfunc) | 1 + if isPrime(number, randfunc=randfunc): + break + return number + + +def _rabinMillerTest(n, rounds, randfunc=None): + """_rabinMillerTest(n:long, rounds:int, randfunc:callable):int + Tests if n is prime. + Returns 0 when n is definitely composite. + Returns 1 when n is probably prime. + Returns 2 when n is definitely prime. + + If randfunc is omitted, then Random.new().read is used. + + This function is for internal use only and may be renamed or removed in + the future. + """ + # check special cases (n==2, n even, n < 2) + if n < 3 or (n & 1) == 0: + return n == 2 + # n might be very large so it might be beneficial to precalculate n-1 + n_1 = n - 1 + # determine m and b so that 2**b * m = n - 1 and b maximal + b = 0 + m = n_1 + while (m & 1) == 0: + b += 1 + m >>= 1 + + tested = [] + # we need to do at most n-2 rounds. + for i in iter_range (min (rounds, n-2)): + # randomly choose a < n and make sure it hasn't been tested yet + a = getRandomRange (2, n, randfunc) + while a in tested: + a = getRandomRange (2, n, randfunc) + tested.append (a) + # do the rabin-miller test + z = pow (a, m, n) # (a**m) % n + if z == 1 or z == n_1: + continue + composite = 1 + for r in iter_range(b): + z = (z * z) % n + if z == 1: + return 0 + elif z == n_1: + composite = 0 + break + if composite: + return 0 + return 1 + +def getStrongPrime(N, e=0, false_positive_prob=1e-6, randfunc=None): + r""" + Return a random strong *N*-bit prime number. + In this context, *p* is a strong prime if *p-1* and *p+1* have at + least one large prime factor. + + Args: + N (integer): the exact length of the strong prime. + It must be a multiple of 128 and > 512. + e (integer): if provided, the returned prime (minus 1) + will be coprime to *e* and thus suitable for RSA where + *e* is the public exponent. + false_positive_prob (float): + The statistical probability for the result not to be actually a + prime. It defaults to 10\ :sup:`-6`. + Note that the real probability of a false-positive is far less. This is + just the mathematically provable limit. + randfunc (callable): + A function that takes a parameter *N* and that returns + a random byte string of such length. + If omitted, :func:`Cryptodome.Random.get_random_bytes` is used. + Return: + The new strong prime. + + .. deprecated:: 3.0 + This function is for internal use only and may be renamed or removed in + the future. + """ + + # This function was implemented following the + # instructions found in the paper: + # "FAST GENERATION OF RANDOM, STRONG RSA PRIMES" + # by Robert D. Silverman + # RSA Laboratories + # May 17, 1997 + # which by the time of writing could be freely downloaded here: + # http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.17.2713&rep=rep1&type=pdf + + if randfunc is None: + randfunc = Random.get_random_bytes + + # Use the accelerator if available + if _fastmath is not None: + return _fastmath.getStrongPrime(long(N), long(e), false_positive_prob, + randfunc) + + if (N < 512) or ((N % 128) != 0): + raise ValueError ("bits must be multiple of 128 and > 512") + + rabin_miller_rounds = int(math.ceil(-math.log(false_positive_prob)/math.log(4))) + + # calculate range for X + # lower_bound = sqrt(2) * 2^{511 + 128*x} + # upper_bound = 2^{512 + 128*x} - 1 + x = (N - 512) >> 7 + # We need to approximate the sqrt(2) in the lower_bound by an integer + # expression because floating point math overflows with these numbers + lower_bound = (14142135623730950489 * (2 ** (511 + 128*x))) // 10000000000000000000 + upper_bound = (1 << (512 + 128*x)) - 1 + # Randomly choose X in calculated range + X = getRandomRange (lower_bound, upper_bound, randfunc) + + # generate p1 and p2 + p = [0, 0] + for i in (0, 1): + # randomly choose 101-bit y + y = getRandomNBitInteger (101, randfunc) + # initialize the field for sieving + field = [0] * 5 * len (sieve_base) + # sieve the field + for prime in sieve_base: + offset = y % prime + for j in iter_range((prime - offset) % prime, len (field), prime): + field[j] = 1 + + # look for suitable p[i] starting at y + result = 0 + for j in range(len(field)): + composite = field[j] + # look for next canidate + if composite: + continue + tmp = y + j + result = _rabinMillerTest (tmp, rabin_miller_rounds) + if result > 0: + p[i] = tmp + break + if result == 0: + raise RuntimeError ("Couln't find prime in field. " + "Developer: Increase field_size") + + # Calculate R + # R = (p2^{-1} mod p1) * p2 - (p1^{-1} mod p2) * p1 + tmp1 = inverse (p[1], p[0]) * p[1] # (p2^-1 mod p1)*p2 + tmp2 = inverse (p[0], p[1]) * p[0] # (p1^-1 mod p2)*p1 + R = tmp1 - tmp2 # (p2^-1 mod p1)*p2 - (p1^-1 mod p2)*p1 + + # search for final prime number starting by Y0 + # Y0 = X + (R - X mod p1p2) + increment = p[0] * p[1] + X = X + (R - (X % increment)) + while 1: + is_possible_prime = 1 + # first check candidate against sieve_base + for prime in sieve_base: + if (X % prime) == 0: + is_possible_prime = 0 + break + # if e is given make sure that e and X-1 are coprime + # this is not necessarily a strong prime criterion but useful when + # creating them for RSA where the p-1 and q-1 should be coprime to + # the public exponent e + if e and is_possible_prime: + if e & 1: + if GCD(e, X-1) != 1: + is_possible_prime = 0 + else: + if GCD(e, (X-1) // 2) != 1: + is_possible_prime = 0 + + # do some Rabin-Miller-Tests + if is_possible_prime: + result = _rabinMillerTest (X, rabin_miller_rounds) + if result > 0: + break + X += increment + # abort when X has more bits than requested + # TODO: maybe we shouldn't abort but rather start over. + if X >= 1 << N: + raise RuntimeError ("Couln't find prime in field. " + "Developer: Increase field_size") + return X + +def isPrime(N, false_positive_prob=1e-6, randfunc=None): + r"""Test if a number *N* is a prime. + + Args: + false_positive_prob (float): + The statistical probability for the result not to be actually a + prime. It defaults to 10\ :sup:`-6`. + Note that the real probability of a false-positive is far less. + This is just the mathematically provable limit. + randfunc (callable): + A function that takes a parameter *N* and that returns + a random byte string of such length. + If omitted, :func:`Cryptodome.Random.get_random_bytes` is used. + + Return: + `True` if the input is indeed prime. + """ + + if randfunc is None: + randfunc = Random.get_random_bytes + + if _fastmath is not None: + return _fastmath.isPrime(long(N), false_positive_prob, randfunc) + + if N < 3 or N & 1 == 0: + return N == 2 + for p in sieve_base: + if N == p: + return True + if N % p == 0: + return False + + rounds = int(math.ceil(-math.log(false_positive_prob)/math.log(4))) + return bool(_rabinMillerTest(N, rounds, randfunc)) + + +# Improved conversion functions contributed by Barry Warsaw, after +# careful benchmarking + +import struct + +def long_to_bytes(n, blocksize=0): + """Convert a positive integer to a byte string using big endian encoding. + + If :data:`blocksize` is absent or zero, the byte string will + be of minimal length. + + Otherwise, the length of the byte string is guaranteed to be a multiple + of :data:`blocksize`. If necessary, zeroes (``\\x00``) are added at the left. + + .. note:: + In Python 3, if you are sure that :data:`n` can fit into + :data:`blocksize` bytes, you can simply use the native method instead:: + + >>> n.to_bytes(blocksize, 'big') + + For instance:: + + >>> n = 80 + >>> n.to_bytes(2, 'big') + b'\\x00P' + + However, and unlike this ``long_to_bytes()`` function, + an ``OverflowError`` exception is raised if :data:`n` does not fit. + """ + + if n < 0 or blocksize < 0: + raise ValueError("Values must be non-negative") + + result = [] + pack = struct.pack + + # Fill the first block independently from the value of n + bsr = blocksize + while bsr >= 8: + result.insert(0, pack('>Q', n & 0xFFFFFFFFFFFFFFFF)) + n = n >> 64 + bsr -= 8 + + while bsr >= 4: + result.insert(0, pack('>I', n & 0xFFFFFFFF)) + n = n >> 32 + bsr -= 4 + + while bsr > 0: + result.insert(0, pack('>B', n & 0xFF)) + n = n >> 8 + bsr -= 1 + + if n == 0: + if len(result) == 0: + bresult = b'\x00' + else: + bresult = b''.join(result) + else: + # The encoded number exceeds the block size + while n > 0: + result.insert(0, pack('>Q', n & 0xFFFFFFFFFFFFFFFF)) + n = n >> 64 + result[0] = result[0].lstrip(b'\x00') + bresult = b''.join(result) + # bresult has minimum length here + if blocksize > 0: + target_len = ((len(bresult) - 1) // blocksize + 1) * blocksize + bresult = b'\x00' * (target_len - len(bresult)) + bresult + + return bresult + + +def bytes_to_long(s): + """Convert a byte string to a long integer (big endian). + + In Python 3.2+, use the native method instead:: + + >>> int.from_bytes(s, 'big') + + For instance:: + + >>> int.from_bytes(b'\x00P', 'big') + 80 + + This is (essentially) the inverse of :func:`long_to_bytes`. + """ + acc = 0 + + unpack = struct.unpack + + # Up to Python 2.7.4, struct.unpack can't work with bytearrays nor + # memoryviews + if sys.version_info[0:3] < (2, 7, 4): + if isinstance(s, bytearray): + s = bytes(s) + elif isinstance(s, memoryview): + s = s.tobytes() + + length = len(s) + if length % 4: + extra = (4 - length % 4) + s = b'\x00' * extra + s + length = length + extra + for i in range(0, length, 4): + acc = (acc << 32) + unpack('>I', s[i:i+4])[0] + return acc + + +# For backwards compatibility... +import warnings +def long2str(n, blocksize=0): + warnings.warn("long2str() has been replaced by long_to_bytes()") + return long_to_bytes(n, blocksize) +def str2long(s): + warnings.warn("str2long() has been replaced by bytes_to_long()") + return bytes_to_long(s) + + +# The first 10000 primes used for checking primality. +# This should be enough to eliminate most of the odd +# numbers before needing to do a Rabin-Miller test at all. +sieve_base = ( + 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, + 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, + 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, + 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, + 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, + 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, + 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, + 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, + 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, + 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, + 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, + 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, + 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, + 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, + 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, + 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, + 947, 953, 967, 971, 977, 983, 991, 997, 1009, 1013, + 1019, 1021, 1031, 1033, 1039, 1049, 1051, 1061, 1063, 1069, + 1087, 1091, 1093, 1097, 1103, 1109, 1117, 1123, 1129, 1151, + 1153, 1163, 1171, 1181, 1187, 1193, 1201, 1213, 1217, 1223, + 1229, 1231, 1237, 1249, 1259, 1277, 1279, 1283, 1289, 1291, + 1297, 1301, 1303, 1307, 1319, 1321, 1327, 1361, 1367, 1373, + 1381, 1399, 1409, 1423, 1427, 1429, 1433, 1439, 1447, 1451, + 1453, 1459, 1471, 1481, 1483, 1487, 1489, 1493, 1499, 1511, + 1523, 1531, 1543, 1549, 1553, 1559, 1567, 1571, 1579, 1583, + 1597, 1601, 1607, 1609, 1613, 1619, 1621, 1627, 1637, 1657, + 1663, 1667, 1669, 1693, 1697, 1699, 1709, 1721, 1723, 1733, + 1741, 1747, 1753, 1759, 1777, 1783, 1787, 1789, 1801, 1811, + 1823, 1831, 1847, 1861, 1867, 1871, 1873, 1877, 1879, 1889, + 1901, 1907, 1913, 1931, 1933, 1949, 1951, 1973, 1979, 1987, + 1993, 1997, 1999, 2003, 2011, 2017, 2027, 2029, 2039, 2053, + 2063, 2069, 2081, 2083, 2087, 2089, 2099, 2111, 2113, 2129, + 2131, 2137, 2141, 2143, 2153, 2161, 2179, 2203, 2207, 2213, + 2221, 2237, 2239, 2243, 2251, 2267, 2269, 2273, 2281, 2287, + 2293, 2297, 2309, 2311, 2333, 2339, 2341, 2347, 2351, 2357, + 2371, 2377, 2381, 2383, 2389, 2393, 2399, 2411, 2417, 2423, + 2437, 2441, 2447, 2459, 2467, 2473, 2477, 2503, 2521, 2531, + 2539, 2543, 2549, 2551, 2557, 2579, 2591, 2593, 2609, 2617, + 2621, 2633, 2647, 2657, 2659, 2663, 2671, 2677, 2683, 2687, + 2689, 2693, 2699, 2707, 2711, 2713, 2719, 2729, 2731, 2741, + 2749, 2753, 2767, 2777, 2789, 2791, 2797, 2801, 2803, 2819, + 2833, 2837, 2843, 2851, 2857, 2861, 2879, 2887, 2897, 2903, + 2909, 2917, 2927, 2939, 2953, 2957, 2963, 2969, 2971, 2999, + 3001, 3011, 3019, 3023, 3037, 3041, 3049, 3061, 3067, 3079, + 3083, 3089, 3109, 3119, 3121, 3137, 3163, 3167, 3169, 3181, + 3187, 3191, 3203, 3209, 3217, 3221, 3229, 3251, 3253, 3257, + 3259, 3271, 3299, 3301, 3307, 3313, 3319, 3323, 3329, 3331, + 3343, 3347, 3359, 3361, 3371, 3373, 3389, 3391, 3407, 3413, + 3433, 3449, 3457, 3461, 3463, 3467, 3469, 3491, 3499, 3511, + 3517, 3527, 3529, 3533, 3539, 3541, 3547, 3557, 3559, 3571, + 3581, 3583, 3593, 3607, 3613, 3617, 3623, 3631, 3637, 3643, + 3659, 3671, 3673, 3677, 3691, 3697, 3701, 3709, 3719, 3727, + 3733, 3739, 3761, 3767, 3769, 3779, 3793, 3797, 3803, 3821, + 3823, 3833, 3847, 3851, 3853, 3863, 3877, 3881, 3889, 3907, + 3911, 3917, 3919, 3923, 3929, 3931, 3943, 3947, 3967, 3989, + 4001, 4003, 4007, 4013, 4019, 4021, 4027, 4049, 4051, 4057, + 4073, 4079, 4091, 4093, 4099, 4111, 4127, 4129, 4133, 4139, + 4153, 4157, 4159, 4177, 4201, 4211, 4217, 4219, 4229, 4231, + 4241, 4243, 4253, 4259, 4261, 4271, 4273, 4283, 4289, 4297, + 4327, 4337, 4339, 4349, 4357, 4363, 4373, 4391, 4397, 4409, + 4421, 4423, 4441, 4447, 4451, 4457, 4463, 4481, 4483, 4493, + 4507, 4513, 4517, 4519, 4523, 4547, 4549, 4561, 4567, 4583, + 4591, 4597, 4603, 4621, 4637, 4639, 4643, 4649, 4651, 4657, + 4663, 4673, 4679, 4691, 4703, 4721, 4723, 4729, 4733, 4751, + 4759, 4783, 4787, 4789, 4793, 4799, 4801, 4813, 4817, 4831, + 4861, 4871, 4877, 4889, 4903, 4909, 4919, 4931, 4933, 4937, + 4943, 4951, 4957, 4967, 4969, 4973, 4987, 4993, 4999, 5003, + 5009, 5011, 5021, 5023, 5039, 5051, 5059, 5077, 5081, 5087, + 5099, 5101, 5107, 5113, 5119, 5147, 5153, 5167, 5171, 5179, + 5189, 5197, 5209, 5227, 5231, 5233, 5237, 5261, 5273, 5279, + 5281, 5297, 5303, 5309, 5323, 5333, 5347, 5351, 5381, 5387, + 5393, 5399, 5407, 5413, 5417, 5419, 5431, 5437, 5441, 5443, + 5449, 5471, 5477, 5479, 5483, 5501, 5503, 5507, 5519, 5521, + 5527, 5531, 5557, 5563, 5569, 5573, 5581, 5591, 5623, 5639, + 5641, 5647, 5651, 5653, 5657, 5659, 5669, 5683, 5689, 5693, + 5701, 5711, 5717, 5737, 5741, 5743, 5749, 5779, 5783, 5791, + 5801, 5807, 5813, 5821, 5827, 5839, 5843, 5849, 5851, 5857, + 5861, 5867, 5869, 5879, 5881, 5897, 5903, 5923, 5927, 5939, + 5953, 5981, 5987, 6007, 6011, 6029, 6037, 6043, 6047, 6053, + 6067, 6073, 6079, 6089, 6091, 6101, 6113, 6121, 6131, 6133, + 6143, 6151, 6163, 6173, 6197, 6199, 6203, 6211, 6217, 6221, + 6229, 6247, 6257, 6263, 6269, 6271, 6277, 6287, 6299, 6301, + 6311, 6317, 6323, 6329, 6337, 6343, 6353, 6359, 6361, 6367, + 6373, 6379, 6389, 6397, 6421, 6427, 6449, 6451, 6469, 6473, + 6481, 6491, 6521, 6529, 6547, 6551, 6553, 6563, 6569, 6571, + 6577, 6581, 6599, 6607, 6619, 6637, 6653, 6659, 6661, 6673, + 6679, 6689, 6691, 6701, 6703, 6709, 6719, 6733, 6737, 6761, + 6763, 6779, 6781, 6791, 6793, 6803, 6823, 6827, 6829, 6833, + 6841, 6857, 6863, 6869, 6871, 6883, 6899, 6907, 6911, 6917, + 6947, 6949, 6959, 6961, 6967, 6971, 6977, 6983, 6991, 6997, + 7001, 7013, 7019, 7027, 7039, 7043, 7057, 7069, 7079, 7103, + 7109, 7121, 7127, 7129, 7151, 7159, 7177, 7187, 7193, 7207, + 7211, 7213, 7219, 7229, 7237, 7243, 7247, 7253, 7283, 7297, + 7307, 7309, 7321, 7331, 7333, 7349, 7351, 7369, 7393, 7411, + 7417, 7433, 7451, 7457, 7459, 7477, 7481, 7487, 7489, 7499, + 7507, 7517, 7523, 7529, 7537, 7541, 7547, 7549, 7559, 7561, + 7573, 7577, 7583, 7589, 7591, 7603, 7607, 7621, 7639, 7643, + 7649, 7669, 7673, 7681, 7687, 7691, 7699, 7703, 7717, 7723, + 7727, 7741, 7753, 7757, 7759, 7789, 7793, 7817, 7823, 7829, + 7841, 7853, 7867, 7873, 7877, 7879, 7883, 7901, 7907, 7919, + 7927, 7933, 7937, 7949, 7951, 7963, 7993, 8009, 8011, 8017, + 8039, 8053, 8059, 8069, 8081, 8087, 8089, 8093, 8101, 8111, + 8117, 8123, 8147, 8161, 8167, 8171, 8179, 8191, 8209, 8219, + 8221, 8231, 8233, 8237, 8243, 8263, 8269, 8273, 8287, 8291, + 8293, 8297, 8311, 8317, 8329, 8353, 8363, 8369, 8377, 8387, + 8389, 8419, 8423, 8429, 8431, 8443, 8447, 8461, 8467, 8501, + 8513, 8521, 8527, 8537, 8539, 8543, 8563, 8573, 8581, 8597, + 8599, 8609, 8623, 8627, 8629, 8641, 8647, 8663, 8669, 8677, + 8681, 8689, 8693, 8699, 8707, 8713, 8719, 8731, 8737, 8741, + 8747, 8753, 8761, 8779, 8783, 8803, 8807, 8819, 8821, 8831, + 8837, 8839, 8849, 8861, 8863, 8867, 8887, 8893, 8923, 8929, + 8933, 8941, 8951, 8963, 8969, 8971, 8999, 9001, 9007, 9011, + 9013, 9029, 9041, 9043, 9049, 9059, 9067, 9091, 9103, 9109, + 9127, 9133, 9137, 9151, 9157, 9161, 9173, 9181, 9187, 9199, + 9203, 9209, 9221, 9227, 9239, 9241, 9257, 9277, 9281, 9283, + 9293, 9311, 9319, 9323, 9337, 9341, 9343, 9349, 9371, 9377, + 9391, 9397, 9403, 9413, 9419, 9421, 9431, 9433, 9437, 9439, + 9461, 9463, 9467, 9473, 9479, 9491, 9497, 9511, 9521, 9533, + 9539, 9547, 9551, 9587, 9601, 9613, 9619, 9623, 9629, 9631, + 9643, 9649, 9661, 9677, 9679, 9689, 9697, 9719, 9721, 9733, + 9739, 9743, 9749, 9767, 9769, 9781, 9787, 9791, 9803, 9811, + 9817, 9829, 9833, 9839, 9851, 9857, 9859, 9871, 9883, 9887, + 9901, 9907, 9923, 9929, 9931, 9941, 9949, 9967, 9973, 10007, + 10009, 10037, 10039, 10061, 10067, 10069, 10079, 10091, 10093, 10099, + 10103, 10111, 10133, 10139, 10141, 10151, 10159, 10163, 10169, 10177, + 10181, 10193, 10211, 10223, 10243, 10247, 10253, 10259, 10267, 10271, + 10273, 10289, 10301, 10303, 10313, 10321, 10331, 10333, 10337, 10343, + 10357, 10369, 10391, 10399, 10427, 10429, 10433, 10453, 10457, 10459, + 10463, 10477, 10487, 10499, 10501, 10513, 10529, 10531, 10559, 10567, + 10589, 10597, 10601, 10607, 10613, 10627, 10631, 10639, 10651, 10657, + 10663, 10667, 10687, 10691, 10709, 10711, 10723, 10729, 10733, 10739, + 10753, 10771, 10781, 10789, 10799, 10831, 10837, 10847, 10853, 10859, + 10861, 10867, 10883, 10889, 10891, 10903, 10909, 10937, 10939, 10949, + 10957, 10973, 10979, 10987, 10993, 11003, 11027, 11047, 11057, 11059, + 11069, 11071, 11083, 11087, 11093, 11113, 11117, 11119, 11131, 11149, + 11159, 11161, 11171, 11173, 11177, 11197, 11213, 11239, 11243, 11251, + 11257, 11261, 11273, 11279, 11287, 11299, 11311, 11317, 11321, 11329, + 11351, 11353, 11369, 11383, 11393, 11399, 11411, 11423, 11437, 11443, + 11447, 11467, 11471, 11483, 11489, 11491, 11497, 11503, 11519, 11527, + 11549, 11551, 11579, 11587, 11593, 11597, 11617, 11621, 11633, 11657, + 11677, 11681, 11689, 11699, 11701, 11717, 11719, 11731, 11743, 11777, + 11779, 11783, 11789, 11801, 11807, 11813, 11821, 11827, 11831, 11833, + 11839, 11863, 11867, 11887, 11897, 11903, 11909, 11923, 11927, 11933, + 11939, 11941, 11953, 11959, 11969, 11971, 11981, 11987, 12007, 12011, + 12037, 12041, 12043, 12049, 12071, 12073, 12097, 12101, 12107, 12109, + 12113, 12119, 12143, 12149, 12157, 12161, 12163, 12197, 12203, 12211, + 12227, 12239, 12241, 12251, 12253, 12263, 12269, 12277, 12281, 12289, + 12301, 12323, 12329, 12343, 12347, 12373, 12377, 12379, 12391, 12401, + 12409, 12413, 12421, 12433, 12437, 12451, 12457, 12473, 12479, 12487, + 12491, 12497, 12503, 12511, 12517, 12527, 12539, 12541, 12547, 12553, + 12569, 12577, 12583, 12589, 12601, 12611, 12613, 12619, 12637, 12641, + 12647, 12653, 12659, 12671, 12689, 12697, 12703, 12713, 12721, 12739, + 12743, 12757, 12763, 12781, 12791, 12799, 12809, 12821, 12823, 12829, + 12841, 12853, 12889, 12893, 12899, 12907, 12911, 12917, 12919, 12923, + 12941, 12953, 12959, 12967, 12973, 12979, 12983, 13001, 13003, 13007, + 13009, 13033, 13037, 13043, 13049, 13063, 13093, 13099, 13103, 13109, + 13121, 13127, 13147, 13151, 13159, 13163, 13171, 13177, 13183, 13187, + 13217, 13219, 13229, 13241, 13249, 13259, 13267, 13291, 13297, 13309, + 13313, 13327, 13331, 13337, 13339, 13367, 13381, 13397, 13399, 13411, + 13417, 13421, 13441, 13451, 13457, 13463, 13469, 13477, 13487, 13499, + 13513, 13523, 13537, 13553, 13567, 13577, 13591, 13597, 13613, 13619, + 13627, 13633, 13649, 13669, 13679, 13681, 13687, 13691, 13693, 13697, + 13709, 13711, 13721, 13723, 13729, 13751, 13757, 13759, 13763, 13781, + 13789, 13799, 13807, 13829, 13831, 13841, 13859, 13873, 13877, 13879, + 13883, 13901, 13903, 13907, 13913, 13921, 13931, 13933, 13963, 13967, + 13997, 13999, 14009, 14011, 14029, 14033, 14051, 14057, 14071, 14081, + 14083, 14087, 14107, 14143, 14149, 14153, 14159, 14173, 14177, 14197, + 14207, 14221, 14243, 14249, 14251, 14281, 14293, 14303, 14321, 14323, + 14327, 14341, 14347, 14369, 14387, 14389, 14401, 14407, 14411, 14419, + 14423, 14431, 14437, 14447, 14449, 14461, 14479, 14489, 14503, 14519, + 14533, 14537, 14543, 14549, 14551, 14557, 14561, 14563, 14591, 14593, + 14621, 14627, 14629, 14633, 14639, 14653, 14657, 14669, 14683, 14699, + 14713, 14717, 14723, 14731, 14737, 14741, 14747, 14753, 14759, 14767, + 14771, 14779, 14783, 14797, 14813, 14821, 14827, 14831, 14843, 14851, + 14867, 14869, 14879, 14887, 14891, 14897, 14923, 14929, 14939, 14947, + 14951, 14957, 14969, 14983, 15013, 15017, 15031, 15053, 15061, 15073, + 15077, 15083, 15091, 15101, 15107, 15121, 15131, 15137, 15139, 15149, + 15161, 15173, 15187, 15193, 15199, 15217, 15227, 15233, 15241, 15259, + 15263, 15269, 15271, 15277, 15287, 15289, 15299, 15307, 15313, 15319, + 15329, 15331, 15349, 15359, 15361, 15373, 15377, 15383, 15391, 15401, + 15413, 15427, 15439, 15443, 15451, 15461, 15467, 15473, 15493, 15497, + 15511, 15527, 15541, 15551, 15559, 15569, 15581, 15583, 15601, 15607, + 15619, 15629, 15641, 15643, 15647, 15649, 15661, 15667, 15671, 15679, + 15683, 15727, 15731, 15733, 15737, 15739, 15749, 15761, 15767, 15773, + 15787, 15791, 15797, 15803, 15809, 15817, 15823, 15859, 15877, 15881, + 15887, 15889, 15901, 15907, 15913, 15919, 15923, 15937, 15959, 15971, + 15973, 15991, 16001, 16007, 16033, 16057, 16061, 16063, 16067, 16069, + 16073, 16087, 16091, 16097, 16103, 16111, 16127, 16139, 16141, 16183, + 16187, 16189, 16193, 16217, 16223, 16229, 16231, 16249, 16253, 16267, + 16273, 16301, 16319, 16333, 16339, 16349, 16361, 16363, 16369, 16381, + 16411, 16417, 16421, 16427, 16433, 16447, 16451, 16453, 16477, 16481, + 16487, 16493, 16519, 16529, 16547, 16553, 16561, 16567, 16573, 16603, + 16607, 16619, 16631, 16633, 16649, 16651, 16657, 16661, 16673, 16691, + 16693, 16699, 16703, 16729, 16741, 16747, 16759, 16763, 16787, 16811, + 16823, 16829, 16831, 16843, 16871, 16879, 16883, 16889, 16901, 16903, + 16921, 16927, 16931, 16937, 16943, 16963, 16979, 16981, 16987, 16993, + 17011, 17021, 17027, 17029, 17033, 17041, 17047, 17053, 17077, 17093, + 17099, 17107, 17117, 17123, 17137, 17159, 17167, 17183, 17189, 17191, + 17203, 17207, 17209, 17231, 17239, 17257, 17291, 17293, 17299, 17317, + 17321, 17327, 17333, 17341, 17351, 17359, 17377, 17383, 17387, 17389, + 17393, 17401, 17417, 17419, 17431, 17443, 17449, 17467, 17471, 17477, + 17483, 17489, 17491, 17497, 17509, 17519, 17539, 17551, 17569, 17573, + 17579, 17581, 17597, 17599, 17609, 17623, 17627, 17657, 17659, 17669, + 17681, 17683, 17707, 17713, 17729, 17737, 17747, 17749, 17761, 17783, + 17789, 17791, 17807, 17827, 17837, 17839, 17851, 17863, 17881, 17891, + 17903, 17909, 17911, 17921, 17923, 17929, 17939, 17957, 17959, 17971, + 17977, 17981, 17987, 17989, 18013, 18041, 18043, 18047, 18049, 18059, + 18061, 18077, 18089, 18097, 18119, 18121, 18127, 18131, 18133, 18143, + 18149, 18169, 18181, 18191, 18199, 18211, 18217, 18223, 18229, 18233, + 18251, 18253, 18257, 18269, 18287, 18289, 18301, 18307, 18311, 18313, + 18329, 18341, 18353, 18367, 18371, 18379, 18397, 18401, 18413, 18427, + 18433, 18439, 18443, 18451, 18457, 18461, 18481, 18493, 18503, 18517, + 18521, 18523, 18539, 18541, 18553, 18583, 18587, 18593, 18617, 18637, + 18661, 18671, 18679, 18691, 18701, 18713, 18719, 18731, 18743, 18749, + 18757, 18773, 18787, 18793, 18797, 18803, 18839, 18859, 18869, 18899, + 18911, 18913, 18917, 18919, 18947, 18959, 18973, 18979, 19001, 19009, + 19013, 19031, 19037, 19051, 19069, 19073, 19079, 19081, 19087, 19121, + 19139, 19141, 19157, 19163, 19181, 19183, 19207, 19211, 19213, 19219, + 19231, 19237, 19249, 19259, 19267, 19273, 19289, 19301, 19309, 19319, + 19333, 19373, 19379, 19381, 19387, 19391, 19403, 19417, 19421, 19423, + 19427, 19429, 19433, 19441, 19447, 19457, 19463, 19469, 19471, 19477, + 19483, 19489, 19501, 19507, 19531, 19541, 19543, 19553, 19559, 19571, + 19577, 19583, 19597, 19603, 19609, 19661, 19681, 19687, 19697, 19699, + 19709, 19717, 19727, 19739, 19751, 19753, 19759, 19763, 19777, 19793, + 19801, 19813, 19819, 19841, 19843, 19853, 19861, 19867, 19889, 19891, + 19913, 19919, 19927, 19937, 19949, 19961, 19963, 19973, 19979, 19991, + 19993, 19997, 20011, 20021, 20023, 20029, 20047, 20051, 20063, 20071, + 20089, 20101, 20107, 20113, 20117, 20123, 20129, 20143, 20147, 20149, + 20161, 20173, 20177, 20183, 20201, 20219, 20231, 20233, 20249, 20261, + 20269, 20287, 20297, 20323, 20327, 20333, 20341, 20347, 20353, 20357, + 20359, 20369, 20389, 20393, 20399, 20407, 20411, 20431, 20441, 20443, + 20477, 20479, 20483, 20507, 20509, 20521, 20533, 20543, 20549, 20551, + 20563, 20593, 20599, 20611, 20627, 20639, 20641, 20663, 20681, 20693, + 20707, 20717, 20719, 20731, 20743, 20747, 20749, 20753, 20759, 20771, + 20773, 20789, 20807, 20809, 20849, 20857, 20873, 20879, 20887, 20897, + 20899, 20903, 20921, 20929, 20939, 20947, 20959, 20963, 20981, 20983, + 21001, 21011, 21013, 21017, 21019, 21023, 21031, 21059, 21061, 21067, + 21089, 21101, 21107, 21121, 21139, 21143, 21149, 21157, 21163, 21169, + 21179, 21187, 21191, 21193, 21211, 21221, 21227, 21247, 21269, 21277, + 21283, 21313, 21317, 21319, 21323, 21341, 21347, 21377, 21379, 21383, + 21391, 21397, 21401, 21407, 21419, 21433, 21467, 21481, 21487, 21491, + 21493, 21499, 21503, 21517, 21521, 21523, 21529, 21557, 21559, 21563, + 21569, 21577, 21587, 21589, 21599, 21601, 21611, 21613, 21617, 21647, + 21649, 21661, 21673, 21683, 21701, 21713, 21727, 21737, 21739, 21751, + 21757, 21767, 21773, 21787, 21799, 21803, 21817, 21821, 21839, 21841, + 21851, 21859, 21863, 21871, 21881, 21893, 21911, 21929, 21937, 21943, + 21961, 21977, 21991, 21997, 22003, 22013, 22027, 22031, 22037, 22039, + 22051, 22063, 22067, 22073, 22079, 22091, 22093, 22109, 22111, 22123, + 22129, 22133, 22147, 22153, 22157, 22159, 22171, 22189, 22193, 22229, + 22247, 22259, 22271, 22273, 22277, 22279, 22283, 22291, 22303, 22307, + 22343, 22349, 22367, 22369, 22381, 22391, 22397, 22409, 22433, 22441, + 22447, 22453, 22469, 22481, 22483, 22501, 22511, 22531, 22541, 22543, + 22549, 22567, 22571, 22573, 22613, 22619, 22621, 22637, 22639, 22643, + 22651, 22669, 22679, 22691, 22697, 22699, 22709, 22717, 22721, 22727, + 22739, 22741, 22751, 22769, 22777, 22783, 22787, 22807, 22811, 22817, + 22853, 22859, 22861, 22871, 22877, 22901, 22907, 22921, 22937, 22943, + 22961, 22963, 22973, 22993, 23003, 23011, 23017, 23021, 23027, 23029, + 23039, 23041, 23053, 23057, 23059, 23063, 23071, 23081, 23087, 23099, + 23117, 23131, 23143, 23159, 23167, 23173, 23189, 23197, 23201, 23203, + 23209, 23227, 23251, 23269, 23279, 23291, 23293, 23297, 23311, 23321, + 23327, 23333, 23339, 23357, 23369, 23371, 23399, 23417, 23431, 23447, + 23459, 23473, 23497, 23509, 23531, 23537, 23539, 23549, 23557, 23561, + 23563, 23567, 23581, 23593, 23599, 23603, 23609, 23623, 23627, 23629, + 23633, 23663, 23669, 23671, 23677, 23687, 23689, 23719, 23741, 23743, + 23747, 23753, 23761, 23767, 23773, 23789, 23801, 23813, 23819, 23827, + 23831, 23833, 23857, 23869, 23873, 23879, 23887, 23893, 23899, 23909, + 23911, 23917, 23929, 23957, 23971, 23977, 23981, 23993, 24001, 24007, + 24019, 24023, 24029, 24043, 24049, 24061, 24071, 24077, 24083, 24091, + 24097, 24103, 24107, 24109, 24113, 24121, 24133, 24137, 24151, 24169, + 24179, 24181, 24197, 24203, 24223, 24229, 24239, 24247, 24251, 24281, + 24317, 24329, 24337, 24359, 24371, 24373, 24379, 24391, 24407, 24413, + 24419, 24421, 24439, 24443, 24469, 24473, 24481, 24499, 24509, 24517, + 24527, 24533, 24547, 24551, 24571, 24593, 24611, 24623, 24631, 24659, + 24671, 24677, 24683, 24691, 24697, 24709, 24733, 24749, 24763, 24767, + 24781, 24793, 24799, 24809, 24821, 24841, 24847, 24851, 24859, 24877, + 24889, 24907, 24917, 24919, 24923, 24943, 24953, 24967, 24971, 24977, + 24979, 24989, 25013, 25031, 25033, 25037, 25057, 25073, 25087, 25097, + 25111, 25117, 25121, 25127, 25147, 25153, 25163, 25169, 25171, 25183, + 25189, 25219, 25229, 25237, 25243, 25247, 25253, 25261, 25301, 25303, + 25307, 25309, 25321, 25339, 25343, 25349, 25357, 25367, 25373, 25391, + 25409, 25411, 25423, 25439, 25447, 25453, 25457, 25463, 25469, 25471, + 25523, 25537, 25541, 25561, 25577, 25579, 25583, 25589, 25601, 25603, + 25609, 25621, 25633, 25639, 25643, 25657, 25667, 25673, 25679, 25693, + 25703, 25717, 25733, 25741, 25747, 25759, 25763, 25771, 25793, 25799, + 25801, 25819, 25841, 25847, 25849, 25867, 25873, 25889, 25903, 25913, + 25919, 25931, 25933, 25939, 25943, 25951, 25969, 25981, 25997, 25999, + 26003, 26017, 26021, 26029, 26041, 26053, 26083, 26099, 26107, 26111, + 26113, 26119, 26141, 26153, 26161, 26171, 26177, 26183, 26189, 26203, + 26209, 26227, 26237, 26249, 26251, 26261, 26263, 26267, 26293, 26297, + 26309, 26317, 26321, 26339, 26347, 26357, 26371, 26387, 26393, 26399, + 26407, 26417, 26423, 26431, 26437, 26449, 26459, 26479, 26489, 26497, + 26501, 26513, 26539, 26557, 26561, 26573, 26591, 26597, 26627, 26633, + 26641, 26647, 26669, 26681, 26683, 26687, 26693, 26699, 26701, 26711, + 26713, 26717, 26723, 26729, 26731, 26737, 26759, 26777, 26783, 26801, + 26813, 26821, 26833, 26839, 26849, 26861, 26863, 26879, 26881, 26891, + 26893, 26903, 26921, 26927, 26947, 26951, 26953, 26959, 26981, 26987, + 26993, 27011, 27017, 27031, 27043, 27059, 27061, 27067, 27073, 27077, + 27091, 27103, 27107, 27109, 27127, 27143, 27179, 27191, 27197, 27211, + 27239, 27241, 27253, 27259, 27271, 27277, 27281, 27283, 27299, 27329, + 27337, 27361, 27367, 27397, 27407, 27409, 27427, 27431, 27437, 27449, + 27457, 27479, 27481, 27487, 27509, 27527, 27529, 27539, 27541, 27551, + 27581, 27583, 27611, 27617, 27631, 27647, 27653, 27673, 27689, 27691, + 27697, 27701, 27733, 27737, 27739, 27743, 27749, 27751, 27763, 27767, + 27773, 27779, 27791, 27793, 27799, 27803, 27809, 27817, 27823, 27827, + 27847, 27851, 27883, 27893, 27901, 27917, 27919, 27941, 27943, 27947, + 27953, 27961, 27967, 27983, 27997, 28001, 28019, 28027, 28031, 28051, + 28057, 28069, 28081, 28087, 28097, 28099, 28109, 28111, 28123, 28151, + 28163, 28181, 28183, 28201, 28211, 28219, 28229, 28277, 28279, 28283, + 28289, 28297, 28307, 28309, 28319, 28349, 28351, 28387, 28393, 28403, + 28409, 28411, 28429, 28433, 28439, 28447, 28463, 28477, 28493, 28499, + 28513, 28517, 28537, 28541, 28547, 28549, 28559, 28571, 28573, 28579, + 28591, 28597, 28603, 28607, 28619, 28621, 28627, 28631, 28643, 28649, + 28657, 28661, 28663, 28669, 28687, 28697, 28703, 28711, 28723, 28729, + 28751, 28753, 28759, 28771, 28789, 28793, 28807, 28813, 28817, 28837, + 28843, 28859, 28867, 28871, 28879, 28901, 28909, 28921, 28927, 28933, + 28949, 28961, 28979, 29009, 29017, 29021, 29023, 29027, 29033, 29059, + 29063, 29077, 29101, 29123, 29129, 29131, 29137, 29147, 29153, 29167, + 29173, 29179, 29191, 29201, 29207, 29209, 29221, 29231, 29243, 29251, + 29269, 29287, 29297, 29303, 29311, 29327, 29333, 29339, 29347, 29363, + 29383, 29387, 29389, 29399, 29401, 29411, 29423, 29429, 29437, 29443, + 29453, 29473, 29483, 29501, 29527, 29531, 29537, 29567, 29569, 29573, + 29581, 29587, 29599, 29611, 29629, 29633, 29641, 29663, 29669, 29671, + 29683, 29717, 29723, 29741, 29753, 29759, 29761, 29789, 29803, 29819, + 29833, 29837, 29851, 29863, 29867, 29873, 29879, 29881, 29917, 29921, + 29927, 29947, 29959, 29983, 29989, 30011, 30013, 30029, 30047, 30059, + 30071, 30089, 30091, 30097, 30103, 30109, 30113, 30119, 30133, 30137, + 30139, 30161, 30169, 30181, 30187, 30197, 30203, 30211, 30223, 30241, + 30253, 30259, 30269, 30271, 30293, 30307, 30313, 30319, 30323, 30341, + 30347, 30367, 30389, 30391, 30403, 30427, 30431, 30449, 30467, 30469, + 30491, 30493, 30497, 30509, 30517, 30529, 30539, 30553, 30557, 30559, + 30577, 30593, 30631, 30637, 30643, 30649, 30661, 30671, 30677, 30689, + 30697, 30703, 30707, 30713, 30727, 30757, 30763, 30773, 30781, 30803, + 30809, 30817, 30829, 30839, 30841, 30851, 30853, 30859, 30869, 30871, + 30881, 30893, 30911, 30931, 30937, 30941, 30949, 30971, 30977, 30983, + 31013, 31019, 31033, 31039, 31051, 31063, 31069, 31079, 31081, 31091, + 31121, 31123, 31139, 31147, 31151, 31153, 31159, 31177, 31181, 31183, + 31189, 31193, 31219, 31223, 31231, 31237, 31247, 31249, 31253, 31259, + 31267, 31271, 31277, 31307, 31319, 31321, 31327, 31333, 31337, 31357, + 31379, 31387, 31391, 31393, 31397, 31469, 31477, 31481, 31489, 31511, + 31513, 31517, 31531, 31541, 31543, 31547, 31567, 31573, 31583, 31601, + 31607, 31627, 31643, 31649, 31657, 31663, 31667, 31687, 31699, 31721, + 31723, 31727, 31729, 31741, 31751, 31769, 31771, 31793, 31799, 31817, + 31847, 31849, 31859, 31873, 31883, 31891, 31907, 31957, 31963, 31973, + 31981, 31991, 32003, 32009, 32027, 32029, 32051, 32057, 32059, 32063, + 32069, 32077, 32083, 32089, 32099, 32117, 32119, 32141, 32143, 32159, + 32173, 32183, 32189, 32191, 32203, 32213, 32233, 32237, 32251, 32257, + 32261, 32297, 32299, 32303, 32309, 32321, 32323, 32327, 32341, 32353, + 32359, 32363, 32369, 32371, 32377, 32381, 32401, 32411, 32413, 32423, + 32429, 32441, 32443, 32467, 32479, 32491, 32497, 32503, 32507, 32531, + 32533, 32537, 32561, 32563, 32569, 32573, 32579, 32587, 32603, 32609, + 32611, 32621, 32633, 32647, 32653, 32687, 32693, 32707, 32713, 32717, + 32719, 32749, 32771, 32779, 32783, 32789, 32797, 32801, 32803, 32831, + 32833, 32839, 32843, 32869, 32887, 32909, 32911, 32917, 32933, 32939, + 32941, 32957, 32969, 32971, 32983, 32987, 32993, 32999, 33013, 33023, + 33029, 33037, 33049, 33053, 33071, 33073, 33083, 33091, 33107, 33113, + 33119, 33149, 33151, 33161, 33179, 33181, 33191, 33199, 33203, 33211, + 33223, 33247, 33287, 33289, 33301, 33311, 33317, 33329, 33331, 33343, + 33347, 33349, 33353, 33359, 33377, 33391, 33403, 33409, 33413, 33427, + 33457, 33461, 33469, 33479, 33487, 33493, 33503, 33521, 33529, 33533, + 33547, 33563, 33569, 33577, 33581, 33587, 33589, 33599, 33601, 33613, + 33617, 33619, 33623, 33629, 33637, 33641, 33647, 33679, 33703, 33713, + 33721, 33739, 33749, 33751, 33757, 33767, 33769, 33773, 33791, 33797, + 33809, 33811, 33827, 33829, 33851, 33857, 33863, 33871, 33889, 33893, + 33911, 33923, 33931, 33937, 33941, 33961, 33967, 33997, 34019, 34031, + 34033, 34039, 34057, 34061, 34123, 34127, 34129, 34141, 34147, 34157, + 34159, 34171, 34183, 34211, 34213, 34217, 34231, 34253, 34259, 34261, + 34267, 34273, 34283, 34297, 34301, 34303, 34313, 34319, 34327, 34337, + 34351, 34361, 34367, 34369, 34381, 34403, 34421, 34429, 34439, 34457, + 34469, 34471, 34483, 34487, 34499, 34501, 34511, 34513, 34519, 34537, + 34543, 34549, 34583, 34589, 34591, 34603, 34607, 34613, 34631, 34649, + 34651, 34667, 34673, 34679, 34687, 34693, 34703, 34721, 34729, 34739, + 34747, 34757, 34759, 34763, 34781, 34807, 34819, 34841, 34843, 34847, + 34849, 34871, 34877, 34883, 34897, 34913, 34919, 34939, 34949, 34961, + 34963, 34981, 35023, 35027, 35051, 35053, 35059, 35069, 35081, 35083, + 35089, 35099, 35107, 35111, 35117, 35129, 35141, 35149, 35153, 35159, + 35171, 35201, 35221, 35227, 35251, 35257, 35267, 35279, 35281, 35291, + 35311, 35317, 35323, 35327, 35339, 35353, 35363, 35381, 35393, 35401, + 35407, 35419, 35423, 35437, 35447, 35449, 35461, 35491, 35507, 35509, + 35521, 35527, 35531, 35533, 35537, 35543, 35569, 35573, 35591, 35593, + 35597, 35603, 35617, 35671, 35677, 35729, 35731, 35747, 35753, 35759, + 35771, 35797, 35801, 35803, 35809, 35831, 35837, 35839, 35851, 35863, + 35869, 35879, 35897, 35899, 35911, 35923, 35933, 35951, 35963, 35969, + 35977, 35983, 35993, 35999, 36007, 36011, 36013, 36017, 36037, 36061, + 36067, 36073, 36083, 36097, 36107, 36109, 36131, 36137, 36151, 36161, + 36187, 36191, 36209, 36217, 36229, 36241, 36251, 36263, 36269, 36277, + 36293, 36299, 36307, 36313, 36319, 36341, 36343, 36353, 36373, 36383, + 36389, 36433, 36451, 36457, 36467, 36469, 36473, 36479, 36493, 36497, + 36523, 36527, 36529, 36541, 36551, 36559, 36563, 36571, 36583, 36587, + 36599, 36607, 36629, 36637, 36643, 36653, 36671, 36677, 36683, 36691, + 36697, 36709, 36713, 36721, 36739, 36749, 36761, 36767, 36779, 36781, + 36787, 36791, 36793, 36809, 36821, 36833, 36847, 36857, 36871, 36877, + 36887, 36899, 36901, 36913, 36919, 36923, 36929, 36931, 36943, 36947, + 36973, 36979, 36997, 37003, 37013, 37019, 37021, 37039, 37049, 37057, + 37061, 37087, 37097, 37117, 37123, 37139, 37159, 37171, 37181, 37189, + 37199, 37201, 37217, 37223, 37243, 37253, 37273, 37277, 37307, 37309, + 37313, 37321, 37337, 37339, 37357, 37361, 37363, 37369, 37379, 37397, + 37409, 37423, 37441, 37447, 37463, 37483, 37489, 37493, 37501, 37507, + 37511, 37517, 37529, 37537, 37547, 37549, 37561, 37567, 37571, 37573, + 37579, 37589, 37591, 37607, 37619, 37633, 37643, 37649, 37657, 37663, + 37691, 37693, 37699, 37717, 37747, 37781, 37783, 37799, 37811, 37813, + 37831, 37847, 37853, 37861, 37871, 37879, 37889, 37897, 37907, 37951, + 37957, 37963, 37967, 37987, 37991, 37993, 37997, 38011, 38039, 38047, + 38053, 38069, 38083, 38113, 38119, 38149, 38153, 38167, 38177, 38183, + 38189, 38197, 38201, 38219, 38231, 38237, 38239, 38261, 38273, 38281, + 38287, 38299, 38303, 38317, 38321, 38327, 38329, 38333, 38351, 38371, + 38377, 38393, 38431, 38447, 38449, 38453, 38459, 38461, 38501, 38543, + 38557, 38561, 38567, 38569, 38593, 38603, 38609, 38611, 38629, 38639, + 38651, 38653, 38669, 38671, 38677, 38693, 38699, 38707, 38711, 38713, + 38723, 38729, 38737, 38747, 38749, 38767, 38783, 38791, 38803, 38821, + 38833, 38839, 38851, 38861, 38867, 38873, 38891, 38903, 38917, 38921, + 38923, 38933, 38953, 38959, 38971, 38977, 38993, 39019, 39023, 39041, + 39043, 39047, 39079, 39089, 39097, 39103, 39107, 39113, 39119, 39133, + 39139, 39157, 39161, 39163, 39181, 39191, 39199, 39209, 39217, 39227, + 39229, 39233, 39239, 39241, 39251, 39293, 39301, 39313, 39317, 39323, + 39341, 39343, 39359, 39367, 39371, 39373, 39383, 39397, 39409, 39419, + 39439, 39443, 39451, 39461, 39499, 39503, 39509, 39511, 39521, 39541, + 39551, 39563, 39569, 39581, 39607, 39619, 39623, 39631, 39659, 39667, + 39671, 39679, 39703, 39709, 39719, 39727, 39733, 39749, 39761, 39769, + 39779, 39791, 39799, 39821, 39827, 39829, 39839, 39841, 39847, 39857, + 39863, 39869, 39877, 39883, 39887, 39901, 39929, 39937, 39953, 39971, + 39979, 39983, 39989, 40009, 40013, 40031, 40037, 40039, 40063, 40087, + 40093, 40099, 40111, 40123, 40127, 40129, 40151, 40153, 40163, 40169, + 40177, 40189, 40193, 40213, 40231, 40237, 40241, 40253, 40277, 40283, + 40289, 40343, 40351, 40357, 40361, 40387, 40423, 40427, 40429, 40433, + 40459, 40471, 40483, 40487, 40493, 40499, 40507, 40519, 40529, 40531, + 40543, 40559, 40577, 40583, 40591, 40597, 40609, 40627, 40637, 40639, + 40693, 40697, 40699, 40709, 40739, 40751, 40759, 40763, 40771, 40787, + 40801, 40813, 40819, 40823, 40829, 40841, 40847, 40849, 40853, 40867, + 40879, 40883, 40897, 40903, 40927, 40933, 40939, 40949, 40961, 40973, + 40993, 41011, 41017, 41023, 41039, 41047, 41051, 41057, 41077, 41081, + 41113, 41117, 41131, 41141, 41143, 41149, 41161, 41177, 41179, 41183, + 41189, 41201, 41203, 41213, 41221, 41227, 41231, 41233, 41243, 41257, + 41263, 41269, 41281, 41299, 41333, 41341, 41351, 41357, 41381, 41387, + 41389, 41399, 41411, 41413, 41443, 41453, 41467, 41479, 41491, 41507, + 41513, 41519, 41521, 41539, 41543, 41549, 41579, 41593, 41597, 41603, + 41609, 41611, 41617, 41621, 41627, 41641, 41647, 41651, 41659, 41669, + 41681, 41687, 41719, 41729, 41737, 41759, 41761, 41771, 41777, 41801, + 41809, 41813, 41843, 41849, 41851, 41863, 41879, 41887, 41893, 41897, + 41903, 41911, 41927, 41941, 41947, 41953, 41957, 41959, 41969, 41981, + 41983, 41999, 42013, 42017, 42019, 42023, 42043, 42061, 42071, 42073, + 42083, 42089, 42101, 42131, 42139, 42157, 42169, 42179, 42181, 42187, + 42193, 42197, 42209, 42221, 42223, 42227, 42239, 42257, 42281, 42283, + 42293, 42299, 42307, 42323, 42331, 42337, 42349, 42359, 42373, 42379, + 42391, 42397, 42403, 42407, 42409, 42433, 42437, 42443, 42451, 42457, + 42461, 42463, 42467, 42473, 42487, 42491, 42499, 42509, 42533, 42557, + 42569, 42571, 42577, 42589, 42611, 42641, 42643, 42649, 42667, 42677, + 42683, 42689, 42697, 42701, 42703, 42709, 42719, 42727, 42737, 42743, + 42751, 42767, 42773, 42787, 42793, 42797, 42821, 42829, 42839, 42841, + 42853, 42859, 42863, 42899, 42901, 42923, 42929, 42937, 42943, 42953, + 42961, 42967, 42979, 42989, 43003, 43013, 43019, 43037, 43049, 43051, + 43063, 43067, 43093, 43103, 43117, 43133, 43151, 43159, 43177, 43189, + 43201, 43207, 43223, 43237, 43261, 43271, 43283, 43291, 43313, 43319, + 43321, 43331, 43391, 43397, 43399, 43403, 43411, 43427, 43441, 43451, + 43457, 43481, 43487, 43499, 43517, 43541, 43543, 43573, 43577, 43579, + 43591, 43597, 43607, 43609, 43613, 43627, 43633, 43649, 43651, 43661, + 43669, 43691, 43711, 43717, 43721, 43753, 43759, 43777, 43781, 43783, + 43787, 43789, 43793, 43801, 43853, 43867, 43889, 43891, 43913, 43933, + 43943, 43951, 43961, 43963, 43969, 43973, 43987, 43991, 43997, 44017, + 44021, 44027, 44029, 44041, 44053, 44059, 44071, 44087, 44089, 44101, + 44111, 44119, 44123, 44129, 44131, 44159, 44171, 44179, 44189, 44201, + 44203, 44207, 44221, 44249, 44257, 44263, 44267, 44269, 44273, 44279, + 44281, 44293, 44351, 44357, 44371, 44381, 44383, 44389, 44417, 44449, + 44453, 44483, 44491, 44497, 44501, 44507, 44519, 44531, 44533, 44537, + 44543, 44549, 44563, 44579, 44587, 44617, 44621, 44623, 44633, 44641, + 44647, 44651, 44657, 44683, 44687, 44699, 44701, 44711, 44729, 44741, + 44753, 44771, 44773, 44777, 44789, 44797, 44809, 44819, 44839, 44843, + 44851, 44867, 44879, 44887, 44893, 44909, 44917, 44927, 44939, 44953, + 44959, 44963, 44971, 44983, 44987, 45007, 45013, 45053, 45061, 45077, + 45083, 45119, 45121, 45127, 45131, 45137, 45139, 45161, 45179, 45181, + 45191, 45197, 45233, 45247, 45259, 45263, 45281, 45289, 45293, 45307, + 45317, 45319, 45329, 45337, 45341, 45343, 45361, 45377, 45389, 45403, + 45413, 45427, 45433, 45439, 45481, 45491, 45497, 45503, 45523, 45533, + 45541, 45553, 45557, 45569, 45587, 45589, 45599, 45613, 45631, 45641, + 45659, 45667, 45673, 45677, 45691, 45697, 45707, 45737, 45751, 45757, + 45763, 45767, 45779, 45817, 45821, 45823, 45827, 45833, 45841, 45853, + 45863, 45869, 45887, 45893, 45943, 45949, 45953, 45959, 45971, 45979, + 45989, 46021, 46027, 46049, 46051, 46061, 46073, 46091, 46093, 46099, + 46103, 46133, 46141, 46147, 46153, 46171, 46181, 46183, 46187, 46199, + 46219, 46229, 46237, 46261, 46271, 46273, 46279, 46301, 46307, 46309, + 46327, 46337, 46349, 46351, 46381, 46399, 46411, 46439, 46441, 46447, + 46451, 46457, 46471, 46477, 46489, 46499, 46507, 46511, 46523, 46549, + 46559, 46567, 46573, 46589, 46591, 46601, 46619, 46633, 46639, 46643, + 46649, 46663, 46679, 46681, 46687, 46691, 46703, 46723, 46727, 46747, + 46751, 46757, 46769, 46771, 46807, 46811, 46817, 46819, 46829, 46831, + 46853, 46861, 46867, 46877, 46889, 46901, 46919, 46933, 46957, 46993, + 46997, 47017, 47041, 47051, 47057, 47059, 47087, 47093, 47111, 47119, + 47123, 47129, 47137, 47143, 47147, 47149, 47161, 47189, 47207, 47221, + 47237, 47251, 47269, 47279, 47287, 47293, 47297, 47303, 47309, 47317, + 47339, 47351, 47353, 47363, 47381, 47387, 47389, 47407, 47417, 47419, + 47431, 47441, 47459, 47491, 47497, 47501, 47507, 47513, 47521, 47527, + 47533, 47543, 47563, 47569, 47581, 47591, 47599, 47609, 47623, 47629, + 47639, 47653, 47657, 47659, 47681, 47699, 47701, 47711, 47713, 47717, + 47737, 47741, 47743, 47777, 47779, 47791, 47797, 47807, 47809, 47819, + 47837, 47843, 47857, 47869, 47881, 47903, 47911, 47917, 47933, 47939, + 47947, 47951, 47963, 47969, 47977, 47981, 48017, 48023, 48029, 48049, + 48073, 48079, 48091, 48109, 48119, 48121, 48131, 48157, 48163, 48179, + 48187, 48193, 48197, 48221, 48239, 48247, 48259, 48271, 48281, 48299, + 48311, 48313, 48337, 48341, 48353, 48371, 48383, 48397, 48407, 48409, + 48413, 48437, 48449, 48463, 48473, 48479, 48481, 48487, 48491, 48497, + 48523, 48527, 48533, 48539, 48541, 48563, 48571, 48589, 48593, 48611, + 48619, 48623, 48647, 48649, 48661, 48673, 48677, 48679, 48731, 48733, + 48751, 48757, 48761, 48767, 48779, 48781, 48787, 48799, 48809, 48817, + 48821, 48823, 48847, 48857, 48859, 48869, 48871, 48883, 48889, 48907, + 48947, 48953, 48973, 48989, 48991, 49003, 49009, 49019, 49031, 49033, + 49037, 49043, 49057, 49069, 49081, 49103, 49109, 49117, 49121, 49123, + 49139, 49157, 49169, 49171, 49177, 49193, 49199, 49201, 49207, 49211, + 49223, 49253, 49261, 49277, 49279, 49297, 49307, 49331, 49333, 49339, + 49363, 49367, 49369, 49391, 49393, 49409, 49411, 49417, 49429, 49433, + 49451, 49459, 49463, 49477, 49481, 49499, 49523, 49529, 49531, 49537, + 49547, 49549, 49559, 49597, 49603, 49613, 49627, 49633, 49639, 49663, + 49667, 49669, 49681, 49697, 49711, 49727, 49739, 49741, 49747, 49757, + 49783, 49787, 49789, 49801, 49807, 49811, 49823, 49831, 49843, 49853, + 49871, 49877, 49891, 49919, 49921, 49927, 49937, 49939, 49943, 49957, + 49991, 49993, 49999, 50021, 50023, 50033, 50047, 50051, 50053, 50069, + 50077, 50087, 50093, 50101, 50111, 50119, 50123, 50129, 50131, 50147, + 50153, 50159, 50177, 50207, 50221, 50227, 50231, 50261, 50263, 50273, + 50287, 50291, 50311, 50321, 50329, 50333, 50341, 50359, 50363, 50377, + 50383, 50387, 50411, 50417, 50423, 50441, 50459, 50461, 50497, 50503, + 50513, 50527, 50539, 50543, 50549, 50551, 50581, 50587, 50591, 50593, + 50599, 50627, 50647, 50651, 50671, 50683, 50707, 50723, 50741, 50753, + 50767, 50773, 50777, 50789, 50821, 50833, 50839, 50849, 50857, 50867, + 50873, 50891, 50893, 50909, 50923, 50929, 50951, 50957, 50969, 50971, + 50989, 50993, 51001, 51031, 51043, 51047, 51059, 51061, 51071, 51109, + 51131, 51133, 51137, 51151, 51157, 51169, 51193, 51197, 51199, 51203, + 51217, 51229, 51239, 51241, 51257, 51263, 51283, 51287, 51307, 51329, + 51341, 51343, 51347, 51349, 51361, 51383, 51407, 51413, 51419, 51421, + 51427, 51431, 51437, 51439, 51449, 51461, 51473, 51479, 51481, 51487, + 51503, 51511, 51517, 51521, 51539, 51551, 51563, 51577, 51581, 51593, + 51599, 51607, 51613, 51631, 51637, 51647, 51659, 51673, 51679, 51683, + 51691, 51713, 51719, 51721, 51749, 51767, 51769, 51787, 51797, 51803, + 51817, 51827, 51829, 51839, 51853, 51859, 51869, 51871, 51893, 51899, + 51907, 51913, 51929, 51941, 51949, 51971, 51973, 51977, 51991, 52009, + 52021, 52027, 52051, 52057, 52067, 52069, 52081, 52103, 52121, 52127, + 52147, 52153, 52163, 52177, 52181, 52183, 52189, 52201, 52223, 52237, + 52249, 52253, 52259, 52267, 52289, 52291, 52301, 52313, 52321, 52361, + 52363, 52369, 52379, 52387, 52391, 52433, 52453, 52457, 52489, 52501, + 52511, 52517, 52529, 52541, 52543, 52553, 52561, 52567, 52571, 52579, + 52583, 52609, 52627, 52631, 52639, 52667, 52673, 52691, 52697, 52709, + 52711, 52721, 52727, 52733, 52747, 52757, 52769, 52783, 52807, 52813, + 52817, 52837, 52859, 52861, 52879, 52883, 52889, 52901, 52903, 52919, + 52937, 52951, 52957, 52963, 52967, 52973, 52981, 52999, 53003, 53017, + 53047, 53051, 53069, 53077, 53087, 53089, 53093, 53101, 53113, 53117, + 53129, 53147, 53149, 53161, 53171, 53173, 53189, 53197, 53201, 53231, + 53233, 53239, 53267, 53269, 53279, 53281, 53299, 53309, 53323, 53327, + 53353, 53359, 53377, 53381, 53401, 53407, 53411, 53419, 53437, 53441, + 53453, 53479, 53503, 53507, 53527, 53549, 53551, 53569, 53591, 53593, + 53597, 53609, 53611, 53617, 53623, 53629, 53633, 53639, 53653, 53657, + 53681, 53693, 53699, 53717, 53719, 53731, 53759, 53773, 53777, 53783, + 53791, 53813, 53819, 53831, 53849, 53857, 53861, 53881, 53887, 53891, + 53897, 53899, 53917, 53923, 53927, 53939, 53951, 53959, 53987, 53993, + 54001, 54011, 54013, 54037, 54049, 54059, 54083, 54091, 54101, 54121, + 54133, 54139, 54151, 54163, 54167, 54181, 54193, 54217, 54251, 54269, + 54277, 54287, 54293, 54311, 54319, 54323, 54331, 54347, 54361, 54367, + 54371, 54377, 54401, 54403, 54409, 54413, 54419, 54421, 54437, 54443, + 54449, 54469, 54493, 54497, 54499, 54503, 54517, 54521, 54539, 54541, + 54547, 54559, 54563, 54577, 54581, 54583, 54601, 54617, 54623, 54629, + 54631, 54647, 54667, 54673, 54679, 54709, 54713, 54721, 54727, 54751, + 54767, 54773, 54779, 54787, 54799, 54829, 54833, 54851, 54869, 54877, + 54881, 54907, 54917, 54919, 54941, 54949, 54959, 54973, 54979, 54983, + 55001, 55009, 55021, 55049, 55051, 55057, 55061, 55073, 55079, 55103, + 55109, 55117, 55127, 55147, 55163, 55171, 55201, 55207, 55213, 55217, + 55219, 55229, 55243, 55249, 55259, 55291, 55313, 55331, 55333, 55337, + 55339, 55343, 55351, 55373, 55381, 55399, 55411, 55439, 55441, 55457, + 55469, 55487, 55501, 55511, 55529, 55541, 55547, 55579, 55589, 55603, + 55609, 55619, 55621, 55631, 55633, 55639, 55661, 55663, 55667, 55673, + 55681, 55691, 55697, 55711, 55717, 55721, 55733, 55763, 55787, 55793, + 55799, 55807, 55813, 55817, 55819, 55823, 55829, 55837, 55843, 55849, + 55871, 55889, 55897, 55901, 55903, 55921, 55927, 55931, 55933, 55949, + 55967, 55987, 55997, 56003, 56009, 56039, 56041, 56053, 56081, 56087, + 56093, 56099, 56101, 56113, 56123, 56131, 56149, 56167, 56171, 56179, + 56197, 56207, 56209, 56237, 56239, 56249, 56263, 56267, 56269, 56299, + 56311, 56333, 56359, 56369, 56377, 56383, 56393, 56401, 56417, 56431, + 56437, 56443, 56453, 56467, 56473, 56477, 56479, 56489, 56501, 56503, + 56509, 56519, 56527, 56531, 56533, 56543, 56569, 56591, 56597, 56599, + 56611, 56629, 56633, 56659, 56663, 56671, 56681, 56687, 56701, 56711, + 56713, 56731, 56737, 56747, 56767, 56773, 56779, 56783, 56807, 56809, + 56813, 56821, 56827, 56843, 56857, 56873, 56891, 56893, 56897, 56909, + 56911, 56921, 56923, 56929, 56941, 56951, 56957, 56963, 56983, 56989, + 56993, 56999, 57037, 57041, 57047, 57059, 57073, 57077, 57089, 57097, + 57107, 57119, 57131, 57139, 57143, 57149, 57163, 57173, 57179, 57191, + 57193, 57203, 57221, 57223, 57241, 57251, 57259, 57269, 57271, 57283, + 57287, 57301, 57329, 57331, 57347, 57349, 57367, 57373, 57383, 57389, + 57397, 57413, 57427, 57457, 57467, 57487, 57493, 57503, 57527, 57529, + 57557, 57559, 57571, 57587, 57593, 57601, 57637, 57641, 57649, 57653, + 57667, 57679, 57689, 57697, 57709, 57713, 57719, 57727, 57731, 57737, + 57751, 57773, 57781, 57787, 57791, 57793, 57803, 57809, 57829, 57839, + 57847, 57853, 57859, 57881, 57899, 57901, 57917, 57923, 57943, 57947, + 57973, 57977, 57991, 58013, 58027, 58031, 58043, 58049, 58057, 58061, + 58067, 58073, 58099, 58109, 58111, 58129, 58147, 58151, 58153, 58169, + 58171, 58189, 58193, 58199, 58207, 58211, 58217, 58229, 58231, 58237, + 58243, 58271, 58309, 58313, 58321, 58337, 58363, 58367, 58369, 58379, + 58391, 58393, 58403, 58411, 58417, 58427, 58439, 58441, 58451, 58453, + 58477, 58481, 58511, 58537, 58543, 58549, 58567, 58573, 58579, 58601, + 58603, 58613, 58631, 58657, 58661, 58679, 58687, 58693, 58699, 58711, + 58727, 58733, 58741, 58757, 58763, 58771, 58787, 58789, 58831, 58889, + 58897, 58901, 58907, 58909, 58913, 58921, 58937, 58943, 58963, 58967, + 58979, 58991, 58997, 59009, 59011, 59021, 59023, 59029, 59051, 59053, + 59063, 59069, 59077, 59083, 59093, 59107, 59113, 59119, 59123, 59141, + 59149, 59159, 59167, 59183, 59197, 59207, 59209, 59219, 59221, 59233, + 59239, 59243, 59263, 59273, 59281, 59333, 59341, 59351, 59357, 59359, + 59369, 59377, 59387, 59393, 59399, 59407, 59417, 59419, 59441, 59443, + 59447, 59453, 59467, 59471, 59473, 59497, 59509, 59513, 59539, 59557, + 59561, 59567, 59581, 59611, 59617, 59621, 59627, 59629, 59651, 59659, + 59663, 59669, 59671, 59693, 59699, 59707, 59723, 59729, 59743, 59747, + 59753, 59771, 59779, 59791, 59797, 59809, 59833, 59863, 59879, 59887, + 59921, 59929, 59951, 59957, 59971, 59981, 59999, 60013, 60017, 60029, + 60037, 60041, 60077, 60083, 60089, 60091, 60101, 60103, 60107, 60127, + 60133, 60139, 60149, 60161, 60167, 60169, 60209, 60217, 60223, 60251, + 60257, 60259, 60271, 60289, 60293, 60317, 60331, 60337, 60343, 60353, + 60373, 60383, 60397, 60413, 60427, 60443, 60449, 60457, 60493, 60497, + 60509, 60521, 60527, 60539, 60589, 60601, 60607, 60611, 60617, 60623, + 60631, 60637, 60647, 60649, 60659, 60661, 60679, 60689, 60703, 60719, + 60727, 60733, 60737, 60757, 60761, 60763, 60773, 60779, 60793, 60811, + 60821, 60859, 60869, 60887, 60889, 60899, 60901, 60913, 60917, 60919, + 60923, 60937, 60943, 60953, 60961, 61001, 61007, 61027, 61031, 61043, + 61051, 61057, 61091, 61099, 61121, 61129, 61141, 61151, 61153, 61169, + 61211, 61223, 61231, 61253, 61261, 61283, 61291, 61297, 61331, 61333, + 61339, 61343, 61357, 61363, 61379, 61381, 61403, 61409, 61417, 61441, + 61463, 61469, 61471, 61483, 61487, 61493, 61507, 61511, 61519, 61543, + 61547, 61553, 61559, 61561, 61583, 61603, 61609, 61613, 61627, 61631, + 61637, 61643, 61651, 61657, 61667, 61673, 61681, 61687, 61703, 61717, + 61723, 61729, 61751, 61757, 61781, 61813, 61819, 61837, 61843, 61861, + 61871, 61879, 61909, 61927, 61933, 61949, 61961, 61967, 61979, 61981, + 61987, 61991, 62003, 62011, 62017, 62039, 62047, 62053, 62057, 62071, + 62081, 62099, 62119, 62129, 62131, 62137, 62141, 62143, 62171, 62189, + 62191, 62201, 62207, 62213, 62219, 62233, 62273, 62297, 62299, 62303, + 62311, 62323, 62327, 62347, 62351, 62383, 62401, 62417, 62423, 62459, + 62467, 62473, 62477, 62483, 62497, 62501, 62507, 62533, 62539, 62549, + 62563, 62581, 62591, 62597, 62603, 62617, 62627, 62633, 62639, 62653, + 62659, 62683, 62687, 62701, 62723, 62731, 62743, 62753, 62761, 62773, + 62791, 62801, 62819, 62827, 62851, 62861, 62869, 62873, 62897, 62903, + 62921, 62927, 62929, 62939, 62969, 62971, 62981, 62983, 62987, 62989, + 63029, 63031, 63059, 63067, 63073, 63079, 63097, 63103, 63113, 63127, + 63131, 63149, 63179, 63197, 63199, 63211, 63241, 63247, 63277, 63281, + 63299, 63311, 63313, 63317, 63331, 63337, 63347, 63353, 63361, 63367, + 63377, 63389, 63391, 63397, 63409, 63419, 63421, 63439, 63443, 63463, + 63467, 63473, 63487, 63493, 63499, 63521, 63527, 63533, 63541, 63559, + 63577, 63587, 63589, 63599, 63601, 63607, 63611, 63617, 63629, 63647, + 63649, 63659, 63667, 63671, 63689, 63691, 63697, 63703, 63709, 63719, + 63727, 63737, 63743, 63761, 63773, 63781, 63793, 63799, 63803, 63809, + 63823, 63839, 63841, 63853, 63857, 63863, 63901, 63907, 63913, 63929, + 63949, 63977, 63997, 64007, 64013, 64019, 64033, 64037, 64063, 64067, + 64081, 64091, 64109, 64123, 64151, 64153, 64157, 64171, 64187, 64189, + 64217, 64223, 64231, 64237, 64271, 64279, 64283, 64301, 64303, 64319, + 64327, 64333, 64373, 64381, 64399, 64403, 64433, 64439, 64451, 64453, + 64483, 64489, 64499, 64513, 64553, 64567, 64577, 64579, 64591, 64601, + 64609, 64613, 64621, 64627, 64633, 64661, 64663, 64667, 64679, 64693, + 64709, 64717, 64747, 64763, 64781, 64783, 64793, 64811, 64817, 64849, + 64853, 64871, 64877, 64879, 64891, 64901, 64919, 64921, 64927, 64937, + 64951, 64969, 64997, 65003, 65011, 65027, 65029, 65033, 65053, 65063, + 65071, 65089, 65099, 65101, 65111, 65119, 65123, 65129, 65141, 65147, + 65167, 65171, 65173, 65179, 65183, 65203, 65213, 65239, 65257, 65267, + 65269, 65287, 65293, 65309, 65323, 65327, 65353, 65357, 65371, 65381, + 65393, 65407, 65413, 65419, 65423, 65437, 65447, 65449, 65479, 65497, + 65519, 65521, 65537, 65539, 65543, 65551, 65557, 65563, 65579, 65581, + 65587, 65599, 65609, 65617, 65629, 65633, 65647, 65651, 65657, 65677, + 65687, 65699, 65701, 65707, 65713, 65717, 65719, 65729, 65731, 65761, + 65777, 65789, 65809, 65827, 65831, 65837, 65839, 65843, 65851, 65867, + 65881, 65899, 65921, 65927, 65929, 65951, 65957, 65963, 65981, 65983, + 65993, 66029, 66037, 66041, 66047, 66067, 66071, 66083, 66089, 66103, + 66107, 66109, 66137, 66161, 66169, 66173, 66179, 66191, 66221, 66239, + 66271, 66293, 66301, 66337, 66343, 66347, 66359, 66361, 66373, 66377, + 66383, 66403, 66413, 66431, 66449, 66457, 66463, 66467, 66491, 66499, + 66509, 66523, 66529, 66533, 66541, 66553, 66569, 66571, 66587, 66593, + 66601, 66617, 66629, 66643, 66653, 66683, 66697, 66701, 66713, 66721, + 66733, 66739, 66749, 66751, 66763, 66791, 66797, 66809, 66821, 66841, + 66851, 66853, 66863, 66877, 66883, 66889, 66919, 66923, 66931, 66943, + 66947, 66949, 66959, 66973, 66977, 67003, 67021, 67033, 67043, 67049, + 67057, 67061, 67073, 67079, 67103, 67121, 67129, 67139, 67141, 67153, + 67157, 67169, 67181, 67187, 67189, 67211, 67213, 67217, 67219, 67231, + 67247, 67261, 67271, 67273, 67289, 67307, 67339, 67343, 67349, 67369, + 67391, 67399, 67409, 67411, 67421, 67427, 67429, 67433, 67447, 67453, + 67477, 67481, 67489, 67493, 67499, 67511, 67523, 67531, 67537, 67547, + 67559, 67567, 67577, 67579, 67589, 67601, 67607, 67619, 67631, 67651, + 67679, 67699, 67709, 67723, 67733, 67741, 67751, 67757, 67759, 67763, + 67777, 67783, 67789, 67801, 67807, 67819, 67829, 67843, 67853, 67867, + 67883, 67891, 67901, 67927, 67931, 67933, 67939, 67943, 67957, 67961, + 67967, 67979, 67987, 67993, 68023, 68041, 68053, 68059, 68071, 68087, + 68099, 68111, 68113, 68141, 68147, 68161, 68171, 68207, 68209, 68213, + 68219, 68227, 68239, 68261, 68279, 68281, 68311, 68329, 68351, 68371, + 68389, 68399, 68437, 68443, 68447, 68449, 68473, 68477, 68483, 68489, + 68491, 68501, 68507, 68521, 68531, 68539, 68543, 68567, 68581, 68597, + 68611, 68633, 68639, 68659, 68669, 68683, 68687, 68699, 68711, 68713, + 68729, 68737, 68743, 68749, 68767, 68771, 68777, 68791, 68813, 68819, + 68821, 68863, 68879, 68881, 68891, 68897, 68899, 68903, 68909, 68917, + 68927, 68947, 68963, 68993, 69001, 69011, 69019, 69029, 69031, 69061, + 69067, 69073, 69109, 69119, 69127, 69143, 69149, 69151, 69163, 69191, + 69193, 69197, 69203, 69221, 69233, 69239, 69247, 69257, 69259, 69263, + 69313, 69317, 69337, 69341, 69371, 69379, 69383, 69389, 69401, 69403, + 69427, 69431, 69439, 69457, 69463, 69467, 69473, 69481, 69491, 69493, + 69497, 69499, 69539, 69557, 69593, 69623, 69653, 69661, 69677, 69691, + 69697, 69709, 69737, 69739, 69761, 69763, 69767, 69779, 69809, 69821, + 69827, 69829, 69833, 69847, 69857, 69859, 69877, 69899, 69911, 69929, + 69931, 69941, 69959, 69991, 69997, 70001, 70003, 70009, 70019, 70039, + 70051, 70061, 70067, 70079, 70099, 70111, 70117, 70121, 70123, 70139, + 70141, 70157, 70163, 70177, 70181, 70183, 70199, 70201, 70207, 70223, + 70229, 70237, 70241, 70249, 70271, 70289, 70297, 70309, 70313, 70321, + 70327, 70351, 70373, 70379, 70381, 70393, 70423, 70429, 70439, 70451, + 70457, 70459, 70481, 70487, 70489, 70501, 70507, 70529, 70537, 70549, + 70571, 70573, 70583, 70589, 70607, 70619, 70621, 70627, 70639, 70657, + 70663, 70667, 70687, 70709, 70717, 70729, 70753, 70769, 70783, 70793, + 70823, 70841, 70843, 70849, 70853, 70867, 70877, 70879, 70891, 70901, + 70913, 70919, 70921, 70937, 70949, 70951, 70957, 70969, 70979, 70981, + 70991, 70997, 70999, 71011, 71023, 71039, 71059, 71069, 71081, 71089, + 71119, 71129, 71143, 71147, 71153, 71161, 71167, 71171, 71191, 71209, + 71233, 71237, 71249, 71257, 71261, 71263, 71287, 71293, 71317, 71327, + 71329, 71333, 71339, 71341, 71347, 71353, 71359, 71363, 71387, 71389, + 71399, 71411, 71413, 71419, 71429, 71437, 71443, 71453, 71471, 71473, + 71479, 71483, 71503, 71527, 71537, 71549, 71551, 71563, 71569, 71593, + 71597, 71633, 71647, 71663, 71671, 71693, 71699, 71707, 71711, 71713, + 71719, 71741, 71761, 71777, 71789, 71807, 71809, 71821, 71837, 71843, + 71849, 71861, 71867, 71879, 71881, 71887, 71899, 71909, 71917, 71933, + 71941, 71947, 71963, 71971, 71983, 71987, 71993, 71999, 72019, 72031, + 72043, 72047, 72053, 72073, 72077, 72089, 72091, 72101, 72103, 72109, + 72139, 72161, 72167, 72169, 72173, 72211, 72221, 72223, 72227, 72229, + 72251, 72253, 72269, 72271, 72277, 72287, 72307, 72313, 72337, 72341, + 72353, 72367, 72379, 72383, 72421, 72431, 72461, 72467, 72469, 72481, + 72493, 72497, 72503, 72533, 72547, 72551, 72559, 72577, 72613, 72617, + 72623, 72643, 72647, 72649, 72661, 72671, 72673, 72679, 72689, 72701, + 72707, 72719, 72727, 72733, 72739, 72763, 72767, 72797, 72817, 72823, + 72859, 72869, 72871, 72883, 72889, 72893, 72901, 72907, 72911, 72923, + 72931, 72937, 72949, 72953, 72959, 72973, 72977, 72997, 73009, 73013, + 73019, 73037, 73039, 73043, 73061, 73063, 73079, 73091, 73121, 73127, + 73133, 73141, 73181, 73189, 73237, 73243, 73259, 73277, 73291, 73303, + 73309, 73327, 73331, 73351, 73361, 73363, 73369, 73379, 73387, 73417, + 73421, 73433, 73453, 73459, 73471, 73477, 73483, 73517, 73523, 73529, + 73547, 73553, 73561, 73571, 73583, 73589, 73597, 73607, 73609, 73613, + 73637, 73643, 73651, 73673, 73679, 73681, 73693, 73699, 73709, 73721, + 73727, 73751, 73757, 73771, 73783, 73819, 73823, 73847, 73849, 73859, + 73867, 73877, 73883, 73897, 73907, 73939, 73943, 73951, 73961, 73973, + 73999, 74017, 74021, 74027, 74047, 74051, 74071, 74077, 74093, 74099, + 74101, 74131, 74143, 74149, 74159, 74161, 74167, 74177, 74189, 74197, + 74201, 74203, 74209, 74219, 74231, 74257, 74279, 74287, 74293, 74297, + 74311, 74317, 74323, 74353, 74357, 74363, 74377, 74381, 74383, 74411, + 74413, 74419, 74441, 74449, 74453, 74471, 74489, 74507, 74509, 74521, + 74527, 74531, 74551, 74561, 74567, 74573, 74587, 74597, 74609, 74611, + 74623, 74653, 74687, 74699, 74707, 74713, 74717, 74719, 74729, 74731, + 74747, 74759, 74761, 74771, 74779, 74797, 74821, 74827, 74831, 74843, + 74857, 74861, 74869, 74873, 74887, 74891, 74897, 74903, 74923, 74929, + 74933, 74941, 74959, 75011, 75013, 75017, 75029, 75037, 75041, 75079, + 75083, 75109, 75133, 75149, 75161, 75167, 75169, 75181, 75193, 75209, + 75211, 75217, 75223, 75227, 75239, 75253, 75269, 75277, 75289, 75307, + 75323, 75329, 75337, 75347, 75353, 75367, 75377, 75389, 75391, 75401, + 75403, 75407, 75431, 75437, 75479, 75503, 75511, 75521, 75527, 75533, + 75539, 75541, 75553, 75557, 75571, 75577, 75583, 75611, 75617, 75619, + 75629, 75641, 75653, 75659, 75679, 75683, 75689, 75703, 75707, 75709, + 75721, 75731, 75743, 75767, 75773, 75781, 75787, 75793, 75797, 75821, + 75833, 75853, 75869, 75883, 75913, 75931, 75937, 75941, 75967, 75979, + 75983, 75989, 75991, 75997, 76001, 76003, 76031, 76039, 76079, 76081, + 76091, 76099, 76103, 76123, 76129, 76147, 76157, 76159, 76163, 76207, + 76213, 76231, 76243, 76249, 76253, 76259, 76261, 76283, 76289, 76303, + 76333, 76343, 76367, 76369, 76379, 76387, 76403, 76421, 76423, 76441, + 76463, 76471, 76481, 76487, 76493, 76507, 76511, 76519, 76537, 76541, + 76543, 76561, 76579, 76597, 76603, 76607, 76631, 76649, 76651, 76667, + 76673, 76679, 76697, 76717, 76733, 76753, 76757, 76771, 76777, 76781, + 76801, 76819, 76829, 76831, 76837, 76847, 76871, 76873, 76883, 76907, + 76913, 76919, 76943, 76949, 76961, 76963, 76991, 77003, 77017, 77023, + 77029, 77041, 77047, 77069, 77081, 77093, 77101, 77137, 77141, 77153, + 77167, 77171, 77191, 77201, 77213, 77237, 77239, 77243, 77249, 77261, + 77263, 77267, 77269, 77279, 77291, 77317, 77323, 77339, 77347, 77351, + 77359, 77369, 77377, 77383, 77417, 77419, 77431, 77447, 77471, 77477, + 77479, 77489, 77491, 77509, 77513, 77521, 77527, 77543, 77549, 77551, + 77557, 77563, 77569, 77573, 77587, 77591, 77611, 77617, 77621, 77641, + 77647, 77659, 77681, 77687, 77689, 77699, 77711, 77713, 77719, 77723, + 77731, 77743, 77747, 77761, 77773, 77783, 77797, 77801, 77813, 77839, + 77849, 77863, 77867, 77893, 77899, 77929, 77933, 77951, 77969, 77977, + 77983, 77999, 78007, 78017, 78031, 78041, 78049, 78059, 78079, 78101, + 78121, 78137, 78139, 78157, 78163, 78167, 78173, 78179, 78191, 78193, + 78203, 78229, 78233, 78241, 78259, 78277, 78283, 78301, 78307, 78311, + 78317, 78341, 78347, 78367, 78401, 78427, 78437, 78439, 78467, 78479, + 78487, 78497, 78509, 78511, 78517, 78539, 78541, 78553, 78569, 78571, + 78577, 78583, 78593, 78607, 78623, 78643, 78649, 78653, 78691, 78697, + 78707, 78713, 78721, 78737, 78779, 78781, 78787, 78791, 78797, 78803, + 78809, 78823, 78839, 78853, 78857, 78877, 78887, 78889, 78893, 78901, + 78919, 78929, 78941, 78977, 78979, 78989, 79031, 79039, 79043, 79063, + 79087, 79103, 79111, 79133, 79139, 79147, 79151, 79153, 79159, 79181, + 79187, 79193, 79201, 79229, 79231, 79241, 79259, 79273, 79279, 79283, + 79301, 79309, 79319, 79333, 79337, 79349, 79357, 79367, 79379, 79393, + 79397, 79399, 79411, 79423, 79427, 79433, 79451, 79481, 79493, 79531, + 79537, 79549, 79559, 79561, 79579, 79589, 79601, 79609, 79613, 79621, + 79627, 79631, 79633, 79657, 79669, 79687, 79691, 79693, 79697, 79699, + 79757, 79769, 79777, 79801, 79811, 79813, 79817, 79823, 79829, 79841, + 79843, 79847, 79861, 79867, 79873, 79889, 79901, 79903, 79907, 79939, + 79943, 79967, 79973, 79979, 79987, 79997, 79999, 80021, 80039, 80051, + 80071, 80077, 80107, 80111, 80141, 80147, 80149, 80153, 80167, 80173, + 80177, 80191, 80207, 80209, 80221, 80231, 80233, 80239, 80251, 80263, + 80273, 80279, 80287, 80309, 80317, 80329, 80341, 80347, 80363, 80369, + 80387, 80407, 80429, 80447, 80449, 80471, 80473, 80489, 80491, 80513, + 80527, 80537, 80557, 80567, 80599, 80603, 80611, 80621, 80627, 80629, + 80651, 80657, 80669, 80671, 80677, 80681, 80683, 80687, 80701, 80713, + 80737, 80747, 80749, 80761, 80777, 80779, 80783, 80789, 80803, 80809, + 80819, 80831, 80833, 80849, 80863, 80897, 80909, 80911, 80917, 80923, + 80929, 80933, 80953, 80963, 80989, 81001, 81013, 81017, 81019, 81023, + 81031, 81041, 81043, 81047, 81049, 81071, 81077, 81083, 81097, 81101, + 81119, 81131, 81157, 81163, 81173, 81181, 81197, 81199, 81203, 81223, + 81233, 81239, 81281, 81283, 81293, 81299, 81307, 81331, 81343, 81349, + 81353, 81359, 81371, 81373, 81401, 81409, 81421, 81439, 81457, 81463, + 81509, 81517, 81527, 81533, 81547, 81551, 81553, 81559, 81563, 81569, + 81611, 81619, 81629, 81637, 81647, 81649, 81667, 81671, 81677, 81689, + 81701, 81703, 81707, 81727, 81737, 81749, 81761, 81769, 81773, 81799, + 81817, 81839, 81847, 81853, 81869, 81883, 81899, 81901, 81919, 81929, + 81931, 81937, 81943, 81953, 81967, 81971, 81973, 82003, 82007, 82009, + 82013, 82021, 82031, 82037, 82039, 82051, 82067, 82073, 82129, 82139, + 82141, 82153, 82163, 82171, 82183, 82189, 82193, 82207, 82217, 82219, + 82223, 82231, 82237, 82241, 82261, 82267, 82279, 82301, 82307, 82339, + 82349, 82351, 82361, 82373, 82387, 82393, 82421, 82457, 82463, 82469, + 82471, 82483, 82487, 82493, 82499, 82507, 82529, 82531, 82549, 82559, + 82561, 82567, 82571, 82591, 82601, 82609, 82613, 82619, 82633, 82651, + 82657, 82699, 82721, 82723, 82727, 82729, 82757, 82759, 82763, 82781, + 82787, 82793, 82799, 82811, 82813, 82837, 82847, 82883, 82889, 82891, + 82903, 82913, 82939, 82963, 82981, 82997, 83003, 83009, 83023, 83047, + 83059, 83063, 83071, 83077, 83089, 83093, 83101, 83117, 83137, 83177, + 83203, 83207, 83219, 83221, 83227, 83231, 83233, 83243, 83257, 83267, + 83269, 83273, 83299, 83311, 83339, 83341, 83357, 83383, 83389, 83399, + 83401, 83407, 83417, 83423, 83431, 83437, 83443, 83449, 83459, 83471, + 83477, 83497, 83537, 83557, 83561, 83563, 83579, 83591, 83597, 83609, + 83617, 83621, 83639, 83641, 83653, 83663, 83689, 83701, 83717, 83719, + 83737, 83761, 83773, 83777, 83791, 83813, 83833, 83843, 83857, 83869, + 83873, 83891, 83903, 83911, 83921, 83933, 83939, 83969, 83983, 83987, + 84011, 84017, 84047, 84053, 84059, 84061, 84067, 84089, 84121, 84127, + 84131, 84137, 84143, 84163, 84179, 84181, 84191, 84199, 84211, 84221, + 84223, 84229, 84239, 84247, 84263, 84299, 84307, 84313, 84317, 84319, + 84347, 84349, 84377, 84389, 84391, 84401, 84407, 84421, 84431, 84437, + 84443, 84449, 84457, 84463, 84467, 84481, 84499, 84503, 84509, 84521, + 84523, 84533, 84551, 84559, 84589, 84629, 84631, 84649, 84653, 84659, + 84673, 84691, 84697, 84701, 84713, 84719, 84731, 84737, 84751, 84761, + 84787, 84793, 84809, 84811, 84827, 84857, 84859, 84869, 84871, 84913, + 84919, 84947, 84961, 84967, 84977, 84979, 84991, 85009, 85021, 85027, + 85037, 85049, 85061, 85081, 85087, 85091, 85093, 85103, 85109, 85121, + 85133, 85147, 85159, 85193, 85199, 85201, 85213, 85223, 85229, 85237, + 85243, 85247, 85259, 85297, 85303, 85313, 85331, 85333, 85361, 85363, + 85369, 85381, 85411, 85427, 85429, 85439, 85447, 85451, 85453, 85469, + 85487, 85513, 85517, 85523, 85531, 85549, 85571, 85577, 85597, 85601, + 85607, 85619, 85621, 85627, 85639, 85643, 85661, 85667, 85669, 85691, + 85703, 85711, 85717, 85733, 85751, 85781, 85793, 85817, 85819, 85829, + 85831, 85837, 85843, 85847, 85853, 85889, 85903, 85909, 85931, 85933, + 85991, 85999, 86011, 86017, 86027, 86029, 86069, 86077, 86083, 86111, + 86113, 86117, 86131, 86137, 86143, 86161, 86171, 86179, 86183, 86197, + 86201, 86209, 86239, 86243, 86249, 86257, 86263, 86269, 86287, 86291, + 86293, 86297, 86311, 86323, 86341, 86351, 86353, 86357, 86369, 86371, + 86381, 86389, 86399, 86413, 86423, 86441, 86453, 86461, 86467, 86477, + 86491, 86501, 86509, 86531, 86533, 86539, 86561, 86573, 86579, 86587, + 86599, 86627, 86629, 86677, 86689, 86693, 86711, 86719, 86729, 86743, + 86753, 86767, 86771, 86783, 86813, 86837, 86843, 86851, 86857, 86861, + 86869, 86923, 86927, 86929, 86939, 86951, 86959, 86969, 86981, 86993, + 87011, 87013, 87037, 87041, 87049, 87071, 87083, 87103, 87107, 87119, + 87121, 87133, 87149, 87151, 87179, 87181, 87187, 87211, 87221, 87223, + 87251, 87253, 87257, 87277, 87281, 87293, 87299, 87313, 87317, 87323, + 87337, 87359, 87383, 87403, 87407, 87421, 87427, 87433, 87443, 87473, + 87481, 87491, 87509, 87511, 87517, 87523, 87539, 87541, 87547, 87553, + 87557, 87559, 87583, 87587, 87589, 87613, 87623, 87629, 87631, 87641, + 87643, 87649, 87671, 87679, 87683, 87691, 87697, 87701, 87719, 87721, + 87739, 87743, 87751, 87767, 87793, 87797, 87803, 87811, 87833, 87853, + 87869, 87877, 87881, 87887, 87911, 87917, 87931, 87943, 87959, 87961, + 87973, 87977, 87991, 88001, 88003, 88007, 88019, 88037, 88069, 88079, + 88093, 88117, 88129, 88169, 88177, 88211, 88223, 88237, 88241, 88259, + 88261, 88289, 88301, 88321, 88327, 88337, 88339, 88379, 88397, 88411, + 88423, 88427, 88463, 88469, 88471, 88493, 88499, 88513, 88523, 88547, + 88589, 88591, 88607, 88609, 88643, 88651, 88657, 88661, 88663, 88667, + 88681, 88721, 88729, 88741, 88747, 88771, 88789, 88793, 88799, 88801, + 88807, 88811, 88813, 88817, 88819, 88843, 88853, 88861, 88867, 88873, + 88883, 88897, 88903, 88919, 88937, 88951, 88969, 88993, 88997, 89003, + 89009, 89017, 89021, 89041, 89051, 89057, 89069, 89071, 89083, 89087, + 89101, 89107, 89113, 89119, 89123, 89137, 89153, 89189, 89203, 89209, + 89213, 89227, 89231, 89237, 89261, 89269, 89273, 89293, 89303, 89317, + 89329, 89363, 89371, 89381, 89387, 89393, 89399, 89413, 89417, 89431, + 89443, 89449, 89459, 89477, 89491, 89501, 89513, 89519, 89521, 89527, + 89533, 89561, 89563, 89567, 89591, 89597, 89599, 89603, 89611, 89627, + 89633, 89653, 89657, 89659, 89669, 89671, 89681, 89689, 89753, 89759, + 89767, 89779, 89783, 89797, 89809, 89819, 89821, 89833, 89839, 89849, + 89867, 89891, 89897, 89899, 89909, 89917, 89923, 89939, 89959, 89963, + 89977, 89983, 89989, 90001, 90007, 90011, 90017, 90019, 90023, 90031, + 90053, 90059, 90067, 90071, 90073, 90089, 90107, 90121, 90127, 90149, + 90163, 90173, 90187, 90191, 90197, 90199, 90203, 90217, 90227, 90239, + 90247, 90263, 90271, 90281, 90289, 90313, 90353, 90359, 90371, 90373, + 90379, 90397, 90401, 90403, 90407, 90437, 90439, 90469, 90473, 90481, + 90499, 90511, 90523, 90527, 90529, 90533, 90547, 90583, 90599, 90617, + 90619, 90631, 90641, 90647, 90659, 90677, 90679, 90697, 90703, 90709, + 90731, 90749, 90787, 90793, 90803, 90821, 90823, 90833, 90841, 90847, + 90863, 90887, 90901, 90907, 90911, 90917, 90931, 90947, 90971, 90977, + 90989, 90997, 91009, 91019, 91033, 91079, 91081, 91097, 91099, 91121, + 91127, 91129, 91139, 91141, 91151, 91153, 91159, 91163, 91183, 91193, + 91199, 91229, 91237, 91243, 91249, 91253, 91283, 91291, 91297, 91303, + 91309, 91331, 91367, 91369, 91373, 91381, 91387, 91393, 91397, 91411, + 91423, 91433, 91453, 91457, 91459, 91463, 91493, 91499, 91513, 91529, + 91541, 91571, 91573, 91577, 91583, 91591, 91621, 91631, 91639, 91673, + 91691, 91703, 91711, 91733, 91753, 91757, 91771, 91781, 91801, 91807, + 91811, 91813, 91823, 91837, 91841, 91867, 91873, 91909, 91921, 91939, + 91943, 91951, 91957, 91961, 91967, 91969, 91997, 92003, 92009, 92033, + 92041, 92051, 92077, 92083, 92107, 92111, 92119, 92143, 92153, 92173, + 92177, 92179, 92189, 92203, 92219, 92221, 92227, 92233, 92237, 92243, + 92251, 92269, 92297, 92311, 92317, 92333, 92347, 92353, 92357, 92363, + 92369, 92377, 92381, 92383, 92387, 92399, 92401, 92413, 92419, 92431, + 92459, 92461, 92467, 92479, 92489, 92503, 92507, 92551, 92557, 92567, + 92569, 92581, 92593, 92623, 92627, 92639, 92641, 92647, 92657, 92669, + 92671, 92681, 92683, 92693, 92699, 92707, 92717, 92723, 92737, 92753, + 92761, 92767, 92779, 92789, 92791, 92801, 92809, 92821, 92831, 92849, + 92857, 92861, 92863, 92867, 92893, 92899, 92921, 92927, 92941, 92951, + 92957, 92959, 92987, 92993, 93001, 93047, 93053, 93059, 93077, 93083, + 93089, 93097, 93103, 93113, 93131, 93133, 93139, 93151, 93169, 93179, + 93187, 93199, 93229, 93239, 93241, 93251, 93253, 93257, 93263, 93281, + 93283, 93287, 93307, 93319, 93323, 93329, 93337, 93371, 93377, 93383, + 93407, 93419, 93427, 93463, 93479, 93481, 93487, 93491, 93493, 93497, + 93503, 93523, 93529, 93553, 93557, 93559, 93563, 93581, 93601, 93607, + 93629, 93637, 93683, 93701, 93703, 93719, 93739, 93761, 93763, 93787, + 93809, 93811, 93827, 93851, 93871, 93887, 93889, 93893, 93901, 93911, + 93913, 93923, 93937, 93941, 93949, 93967, 93971, 93979, 93983, 93997, + 94007, 94009, 94033, 94049, 94057, 94063, 94079, 94099, 94109, 94111, + 94117, 94121, 94151, 94153, 94169, 94201, 94207, 94219, 94229, 94253, + 94261, 94273, 94291, 94307, 94309, 94321, 94327, 94331, 94343, 94349, + 94351, 94379, 94397, 94399, 94421, 94427, 94433, 94439, 94441, 94447, + 94463, 94477, 94483, 94513, 94529, 94531, 94541, 94543, 94547, 94559, + 94561, 94573, 94583, 94597, 94603, 94613, 94621, 94649, 94651, 94687, + 94693, 94709, 94723, 94727, 94747, 94771, 94777, 94781, 94789, 94793, + 94811, 94819, 94823, 94837, 94841, 94847, 94849, 94873, 94889, 94903, + 94907, 94933, 94949, 94951, 94961, 94993, 94999, 95003, 95009, 95021, + 95027, 95063, 95071, 95083, 95087, 95089, 95093, 95101, 95107, 95111, + 95131, 95143, 95153, 95177, 95189, 95191, 95203, 95213, 95219, 95231, + 95233, 95239, 95257, 95261, 95267, 95273, 95279, 95287, 95311, 95317, + 95327, 95339, 95369, 95383, 95393, 95401, 95413, 95419, 95429, 95441, + 95443, 95461, 95467, 95471, 95479, 95483, 95507, 95527, 95531, 95539, + 95549, 95561, 95569, 95581, 95597, 95603, 95617, 95621, 95629, 95633, + 95651, 95701, 95707, 95713, 95717, 95723, 95731, 95737, 95747, 95773, + 95783, 95789, 95791, 95801, 95803, 95813, 95819, 95857, 95869, 95873, + 95881, 95891, 95911, 95917, 95923, 95929, 95947, 95957, 95959, 95971, + 95987, 95989, 96001, 96013, 96017, 96043, 96053, 96059, 96079, 96097, + 96137, 96149, 96157, 96167, 96179, 96181, 96199, 96211, 96221, 96223, + 96233, 96259, 96263, 96269, 96281, 96289, 96293, 96323, 96329, 96331, + 96337, 96353, 96377, 96401, 96419, 96431, 96443, 96451, 96457, 96461, + 96469, 96479, 96487, 96493, 96497, 96517, 96527, 96553, 96557, 96581, + 96587, 96589, 96601, 96643, 96661, 96667, 96671, 96697, 96703, 96731, + 96737, 96739, 96749, 96757, 96763, 96769, 96779, 96787, 96797, 96799, + 96821, 96823, 96827, 96847, 96851, 96857, 96893, 96907, 96911, 96931, + 96953, 96959, 96973, 96979, 96989, 96997, 97001, 97003, 97007, 97021, + 97039, 97073, 97081, 97103, 97117, 97127, 97151, 97157, 97159, 97169, + 97171, 97177, 97187, 97213, 97231, 97241, 97259, 97283, 97301, 97303, + 97327, 97367, 97369, 97373, 97379, 97381, 97387, 97397, 97423, 97429, + 97441, 97453, 97459, 97463, 97499, 97501, 97511, 97523, 97547, 97549, + 97553, 97561, 97571, 97577, 97579, 97583, 97607, 97609, 97613, 97649, + 97651, 97673, 97687, 97711, 97729, 97771, 97777, 97787, 97789, 97813, + 97829, 97841, 97843, 97847, 97849, 97859, 97861, 97871, 97879, 97883, + 97919, 97927, 97931, 97943, 97961, 97967, 97973, 97987, 98009, 98011, + 98017, 98041, 98047, 98057, 98081, 98101, 98123, 98129, 98143, 98179, + 98207, 98213, 98221, 98227, 98251, 98257, 98269, 98297, 98299, 98317, + 98321, 98323, 98327, 98347, 98369, 98377, 98387, 98389, 98407, 98411, + 98419, 98429, 98443, 98453, 98459, 98467, 98473, 98479, 98491, 98507, + 98519, 98533, 98543, 98561, 98563, 98573, 98597, 98621, 98627, 98639, + 98641, 98663, 98669, 98689, 98711, 98713, 98717, 98729, 98731, 98737, + 98773, 98779, 98801, 98807, 98809, 98837, 98849, 98867, 98869, 98873, + 98887, 98893, 98897, 98899, 98909, 98911, 98927, 98929, 98939, 98947, + 98953, 98963, 98981, 98993, 98999, 99013, 99017, 99023, 99041, 99053, + 99079, 99083, 99089, 99103, 99109, 99119, 99131, 99133, 99137, 99139, + 99149, 99173, 99181, 99191, 99223, 99233, 99241, 99251, 99257, 99259, + 99277, 99289, 99317, 99347, 99349, 99367, 99371, 99377, 99391, 99397, + 99401, 99409, 99431, 99439, 99469, 99487, 99497, 99523, 99527, 99529, + 99551, 99559, 99563, 99571, 99577, 99581, 99607, 99611, 99623, 99643, + 99661, 99667, 99679, 99689, 99707, 99709, 99713, 99719, 99721, 99733, + 99761, 99767, 99787, 99793, 99809, 99817, 99823, 99829, 99833, 99839, + 99859, 99871, 99877, 99881, 99901, 99907, 99923, 99929, 99961, 99971, + 99989, 99991, 100003, 100019, 100043, 100049, 100057, 100069, 100103, 100109, +100129, 100151, 100153, 100169, 100183, 100189, 100193, 100207, 100213, 100237, +100267, 100271, 100279, 100291, 100297, 100313, 100333, 100343, 100357, 100361, +100363, 100379, 100391, 100393, 100403, 100411, 100417, 100447, 100459, 100469, +100483, 100493, 100501, 100511, 100517, 100519, 100523, 100537, 100547, 100549, +100559, 100591, 100609, 100613, 100621, 100649, 100669, 100673, 100693, 100699, +100703, 100733, 100741, 100747, 100769, 100787, 100799, 100801, 100811, 100823, +100829, 100847, 100853, 100907, 100913, 100927, 100931, 100937, 100943, 100957, +100981, 100987, 100999, 101009, 101021, 101027, 101051, 101063, 101081, 101089, +101107, 101111, 101113, 101117, 101119, 101141, 101149, 101159, 101161, 101173, +101183, 101197, 101203, 101207, 101209, 101221, 101267, 101273, 101279, 101281, +101287, 101293, 101323, 101333, 101341, 101347, 101359, 101363, 101377, 101383, +101399, 101411, 101419, 101429, 101449, 101467, 101477, 101483, 101489, 101501, +101503, 101513, 101527, 101531, 101533, 101537, 101561, 101573, 101581, 101599, +101603, 101611, 101627, 101641, 101653, 101663, 101681, 101693, 101701, 101719, +101723, 101737, 101741, 101747, 101749, 101771, 101789, 101797, 101807, 101833, +101837, 101839, 101863, 101869, 101873, 101879, 101891, 101917, 101921, 101929, +101939, 101957, 101963, 101977, 101987, 101999, 102001, 102013, 102019, 102023, +102031, 102043, 102059, 102061, 102071, 102077, 102079, 102101, 102103, 102107, +102121, 102139, 102149, 102161, 102181, 102191, 102197, 102199, 102203, 102217, +102229, 102233, 102241, 102251, 102253, 102259, 102293, 102299, 102301, 102317, +102329, 102337, 102359, 102367, 102397, 102407, 102409, 102433, 102437, 102451, +102461, 102481, 102497, 102499, 102503, 102523, 102533, 102539, 102547, 102551, +102559, 102563, 102587, 102593, 102607, 102611, 102643, 102647, 102653, 102667, +102673, 102677, 102679, 102701, 102761, 102763, 102769, 102793, 102797, 102811, +102829, 102841, 102859, 102871, 102877, 102881, 102911, 102913, 102929, 102931, +102953, 102967, 102983, 103001, 103007, 103043, 103049, 103067, 103069, 103079, +103087, 103091, 103093, 103099, 103123, 103141, 103171, 103177, 103183, 103217, +103231, 103237, 103289, 103291, 103307, 103319, 103333, 103349, 103357, 103387, +103391, 103393, 103399, 103409, 103421, 103423, 103451, 103457, 103471, 103483, +103511, 103529, 103549, 103553, 103561, 103567, 103573, 103577, 103583, 103591, +103613, 103619, 103643, 103651, 103657, 103669, 103681, 103687, 103699, 103703, +103723, 103769, 103787, 103801, 103811, 103813, 103837, 103841, 103843, 103867, +103889, 103903, 103913, 103919, 103951, 103963, 103967, 103969, 103979, 103981, +103991, 103993, 103997, 104003, 104009, 104021, 104033, 104047, 104053, 104059, +104087, 104089, 104107, 104113, 104119, 104123, 104147, 104149, 104161, 104173, +104179, 104183, 104207, 104231, 104233, 104239, 104243, 104281, 104287, 104297, +104309, 104311, 104323, 104327, 104347, 104369, 104381, 104383, 104393, 104399, +104417, 104459, 104471, 104473, 104479, 104491, 104513, 104527, 104537, 104543, +104549, 104551, 104561, 104579, 104593, 104597, 104623, 104639, 104651, 104659, +104677, 104681, 104683, 104693, 104701, 104707, 104711, 104717, 104723, 104729, +) diff --git a/venv/Lib/site-packages/Cryptodome/Util/number.pyi b/venv/Lib/site-packages/Cryptodome/Util/number.pyi new file mode 100644 index 0000000..f8680bf --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Util/number.pyi @@ -0,0 +1,19 @@ +from typing import List, Optional, Callable + + +def ceil_div(n: int, d: int) -> int: ... +def size (N: int) -> int: ... +def getRandomInteger(N: int, randfunc: Optional[Callable]=None) -> int: ... +def getRandomRange(a: int, b: int, randfunc: Optional[Callable]=None) -> int: ... +def getRandomNBitInteger(N: int, randfunc: Optional[Callable]=None) -> int: ... +def GCD(x: int,y: int) -> int: ... +def inverse(u: int, v: int) -> int: ... +def getPrime(N: int, randfunc: Optional[Callable]=None) -> int: ... +def getStrongPrime(N: int, e: Optional[int]=0, false_positive_prob: Optional[float]=1e-6, randfunc: Optional[Callable]=None) -> int: ... +def isPrime(N: int, false_positive_prob: Optional[float]=1e-6, randfunc: Optional[Callable]=None) -> bool: ... +def long_to_bytes(n: int, blocksize: Optional[int]=0) -> bytes: ... +def bytes_to_long(s: bytes) -> int: ... +def long2str(n: int, blocksize: Optional[int]=0) -> bytes: ... +def str2long(s: bytes) -> int: ... + +sieve_base: List[int] diff --git a/venv/Lib/site-packages/Cryptodome/Util/py3compat.py b/venv/Lib/site-packages/Cryptodome/Util/py3compat.py new file mode 100644 index 0000000..3294b66 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Util/py3compat.py @@ -0,0 +1,185 @@ +# -*- coding: utf-8 -*- +# +# Util/py3compat.py : Compatibility code for handling Py3k / Python 2.x +# +# Written in 2010 by Thorsten Behrens +# +# =================================================================== +# The contents of this file are dedicated to the public domain. To +# the extent that dedication to the public domain is not available, +# everyone is granted a worldwide, perpetual, royalty-free, +# non-exclusive license to exercise all rights associated with the +# contents of this file for any purpose whatsoever. +# No rights are reserved. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# =================================================================== + +"""Compatibility code for handling string/bytes changes from Python 2.x to Py3k + +In Python 2.x, strings (of type ''str'') contain binary data, including encoded +Unicode text (e.g. UTF-8). The separate type ''unicode'' holds Unicode text. +Unicode literals are specified via the u'...' prefix. Indexing or slicing +either type always produces a string of the same type as the original. +Data read from a file is always of '''str'' type. + +In Python 3.x, strings (type ''str'') may only contain Unicode text. The u'...' +prefix and the ''unicode'' type are now redundant. A new type (called +''bytes'') has to be used for binary data (including any particular +''encoding'' of a string). The b'...' prefix allows one to specify a binary +literal. Indexing or slicing a string produces another string. Slicing a byte +string produces another byte string, but the indexing operation produces an +integer. Data read from a file is of '''str'' type if the file was opened in +text mode, or of ''bytes'' type otherwise. + +Since PyCryptodome aims at supporting both Python 2.x and 3.x, the following helper +functions are used to keep the rest of the library as independent as possible +from the actual Python version. + +In general, the code should always deal with binary strings, and use integers +instead of 1-byte character strings. + +b(s) + Take a text string literal (with no prefix or with u'...' prefix) and + make a byte string. +bchr(c) + Take an integer and make a 1-character byte string. +bord(c) + Take the result of indexing on a byte string and make an integer. +tobytes(s) + Take a text string, a byte string, or a sequence of character taken from + a byte string and make a byte string. +""" + +import sys +import abc + + +if sys.version_info[0] == 2: + def b(s): + return s + def bchr(s): + return chr(s) + def bstr(s): + return str(s) + def bord(s): + return ord(s) + def tobytes(s, encoding="latin-1"): + if isinstance(s, unicode): + return s.encode(encoding) + elif isinstance(s, str): + return s + elif isinstance(s, bytearray): + return bytes(s) + elif isinstance(s, memoryview): + return s.tobytes() + else: + return ''.join(s) + def tostr(bs): + return bs + def byte_string(s): + return isinstance(s, str) + + # In Python 2, a memoryview does not support concatenation + def concat_buffers(a, b): + if isinstance(a, memoryview): + a = a.tobytes() + if isinstance(b, memoryview): + b = b.tobytes() + return a + b + + from StringIO import StringIO + BytesIO = StringIO + + from sys import maxint + + iter_range = xrange + + def is_native_int(x): + return isinstance(x, (int, long)) + + def is_string(x): + return isinstance(x, basestring) + + def is_bytes(x): + return isinstance(x, str) or \ + isinstance(x, bytearray) or \ + isinstance(x, memoryview) + + ABC = abc.ABCMeta('ABC', (object,), {'__slots__': ()}) + + FileNotFoundError = IOError + +else: + def b(s): + return s.encode("latin-1") # utf-8 would cause some side-effects we don't want + def bchr(s): + return bytes([s]) + def bstr(s): + if isinstance(s,str): + return bytes(s,"latin-1") + else: + return bytes(s) + def bord(s): + return s + def tobytes(s, encoding="latin-1"): + if isinstance(s, bytes): + return s + elif isinstance(s, bytearray): + return bytes(s) + elif isinstance(s,str): + return s.encode(encoding) + elif isinstance(s, memoryview): + return s.tobytes() + else: + return bytes([s]) + def tostr(bs): + return bs.decode("latin-1") + def byte_string(s): + return isinstance(s, bytes) + + def concat_buffers(a, b): + return a + b + + from io import BytesIO + from io import StringIO + from sys import maxsize as maxint + + iter_range = range + + def is_native_int(x): + return isinstance(x, int) + + def is_string(x): + return isinstance(x, str) + + def is_bytes(x): + return isinstance(x, bytes) or \ + isinstance(x, bytearray) or \ + isinstance(x, memoryview) + + from abc import ABC + + FileNotFoundError = FileNotFoundError + + +def _copy_bytes(start, end, seq): + """Return an immutable copy of a sequence (byte string, byte array, memoryview) + in a certain interval [start:seq]""" + + if isinstance(seq, memoryview): + return seq[start:end].tobytes() + elif isinstance(seq, bytearray): + return bytes(seq[start:end]) + else: + return seq[start:end] + +del sys +del abc diff --git a/venv/Lib/site-packages/Cryptodome/Util/py3compat.pyi b/venv/Lib/site-packages/Cryptodome/Util/py3compat.pyi new file mode 100644 index 0000000..74e04a2 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Util/py3compat.pyi @@ -0,0 +1,33 @@ +from typing import Union, Any, Optional, IO + +Buffer = Union[bytes, bytearray, memoryview] + +import sys + +def b(s: str) -> bytes: ... +def bchr(s: int) -> bytes: ... +def bord(s: bytes) -> int: ... +def tobytes(s: Union[bytes, str]) -> bytes: ... +def tostr(b: bytes) -> str: ... +def bytestring(x: Any) -> bool: ... + +def is_native_int(s: Any) -> bool: ... +def is_string(x: Any) -> bool: ... +def is_bytes(x: Any) -> bool: ... + +def BytesIO(b: bytes) -> IO[bytes]: ... +def StringIO(s: str) -> IO[str]: ... + +if sys.version_info[0] == 2: + from sys import maxint + iter_range = xrange + +else: + from sys import maxsize as maxint + iter_range = range + +class FileNotFoundError: + def __init__(self, err: int, msg: str, filename: str) -> None: + pass + +def _copy_bytes(start: Optional[int], end: Optional[int], seq: Buffer) -> bytes: ... diff --git a/venv/Lib/site-packages/Cryptodome/Util/strxor.py b/venv/Lib/site-packages/Cryptodome/Util/strxor.py new file mode 100644 index 0000000..6b16155 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Util/strxor.py @@ -0,0 +1,146 @@ +# =================================================================== +# +# Copyright (c) 2014, Legrandin +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# =================================================================== + +from Cryptodome.Util._raw_api import (load_pycryptodome_raw_lib, c_size_t, + create_string_buffer, get_raw_buffer, + c_uint8_ptr, is_writeable_buffer) + +_raw_strxor = load_pycryptodome_raw_lib( + "Cryptodome.Util._strxor", + """ + void strxor(const uint8_t *in1, + const uint8_t *in2, + uint8_t *out, size_t len); + void strxor_c(const uint8_t *in, + uint8_t c, + uint8_t *out, + size_t len); + """) + + +def strxor(term1, term2, output=None): + """From two byte strings of equal length, + create a third one which is the byte-by-byte XOR of the two. + + Args: + term1 (bytes/bytearray/memoryview): + The first byte string to XOR. + term2 (bytes/bytearray/memoryview): + The second byte string to XOR. + output (bytearray/memoryview): + The location where the result will be written to. + It must have the same length as ``term1`` and ``term2``. + If ``None``, the result is returned. + :Return: + If ``output`` is ``None``, a new byte string with the result. + Otherwise ``None``. + + .. note:: + ``term1`` and ``term2`` must have the same length. + """ + + if len(term1) != len(term2): + raise ValueError("Only byte strings of equal length can be xored") + + if output is None: + result = create_string_buffer(len(term1)) + else: + # Note: output may overlap with either input + result = output + + if not is_writeable_buffer(output): + raise TypeError("output must be a bytearray or a writeable memoryview") + + if len(term1) != len(output): + raise ValueError("output must have the same length as the input" + " (%d bytes)" % len(term1)) + + _raw_strxor.strxor(c_uint8_ptr(term1), + c_uint8_ptr(term2), + c_uint8_ptr(result), + c_size_t(len(term1))) + + if output is None: + return get_raw_buffer(result) + else: + return None + + +def strxor_c(term, c, output=None): + """From a byte string, create a second one of equal length + where each byte is XOR-red with the same value. + + Args: + term(bytes/bytearray/memoryview): + The byte string to XOR. + c (int): + Every byte in the string will be XOR-ed with this value. + It must be between 0 and 255 (included). + output (None or bytearray/memoryview): + The location where the result will be written to. + It must have the same length as ``term``. + If ``None``, the result is returned. + + Return: + If ``output`` is ``None``, a new ``bytes`` string with the result. + Otherwise ``None``. + """ + + if not 0 <= c < 256: + raise ValueError("c must be in range(256)") + + if output is None: + result = create_string_buffer(len(term)) + else: + # Note: output may overlap with either input + result = output + + if not is_writeable_buffer(output): + raise TypeError("output must be a bytearray or a writeable memoryview") + + if len(term) != len(output): + raise ValueError("output must have the same length as the input" + " (%d bytes)" % len(term)) + + _raw_strxor.strxor_c(c_uint8_ptr(term), + c, + c_uint8_ptr(result), + c_size_t(len(term)) + ) + + if output is None: + return get_raw_buffer(result) + else: + return None + + +def _strxor_direct(term1, term2, result): + """Very fast XOR - check conditions!""" + _raw_strxor.strxor(term1, term2, result, c_size_t(len(term1))) diff --git a/venv/Lib/site-packages/Cryptodome/Util/strxor.pyi b/venv/Lib/site-packages/Cryptodome/Util/strxor.pyi new file mode 100644 index 0000000..ca896f3 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/Util/strxor.pyi @@ -0,0 +1,6 @@ +from typing import Union, Optional + +Buffer = Union[bytes, bytearray, memoryview] + +def strxor(term1: bytes, term2: bytes, output: Optional[Buffer]=...) -> bytes: ... +def strxor_c(term: bytes, c: int, output: Optional[Buffer]=...) -> bytes: ... diff --git a/venv/Lib/site-packages/Cryptodome/__init__.py b/venv/Lib/site-packages/Cryptodome/__init__.py new file mode 100644 index 0000000..1fc2db9 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/__init__.py @@ -0,0 +1,6 @@ +__all__ = ['Cipher', 'Hash', 'Protocol', 'PublicKey', 'Util', 'Signature', + 'IO', 'Math'] + +version_info = (3, 23, '0') + +__version__ = ".".join([str(x) for x in version_info]) diff --git a/venv/Lib/site-packages/Cryptodome/__init__.pyi b/venv/Lib/site-packages/Cryptodome/__init__.pyi new file mode 100644 index 0000000..bc73446 --- /dev/null +++ b/venv/Lib/site-packages/Cryptodome/__init__.pyi @@ -0,0 +1,4 @@ +from typing import Tuple, Union + +version_info : Tuple[int, int, Union[int, str]] +__version__ : str diff --git a/venv/Lib/site-packages/Cryptodome/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/Cryptodome/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000..950424e Binary files /dev/null and b/venv/Lib/site-packages/Cryptodome/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Cryptodome/py.typed b/venv/Lib/site-packages/Cryptodome/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/venv/Lib/site-packages/OpenSSL/SSL.py b/venv/Lib/site-packages/OpenSSL/SSL.py new file mode 100644 index 0000000..51c60d5 --- /dev/null +++ b/venv/Lib/site-packages/OpenSSL/SSL.py @@ -0,0 +1,3239 @@ +from __future__ import annotations + +import os +import socket +import typing +import warnings +from collections.abc import Sequence +from errno import errorcode +from functools import partial, wraps +from itertools import chain, count +from sys import platform +from typing import Any, Callable, Optional, TypeVar +from weakref import WeakValueDictionary + +from cryptography import x509 +from cryptography.hazmat.primitives.asymmetric import ec + +from OpenSSL._util import ( + StrOrBytesPath as _StrOrBytesPath, +) +from OpenSSL._util import ( + exception_from_error_queue as _exception_from_error_queue, +) +from OpenSSL._util import ( + ffi as _ffi, +) +from OpenSSL._util import ( + lib as _lib, +) +from OpenSSL._util import ( + make_assert as _make_assert, +) +from OpenSSL._util import ( + no_zero_allocator as _no_zero_allocator, +) +from OpenSSL._util import ( + path_bytes as _path_bytes, +) +from OpenSSL._util import ( + text_to_bytes_and_warn as _text_to_bytes_and_warn, +) +from OpenSSL.crypto import ( + FILETYPE_PEM, + X509, + PKey, + X509Name, + X509Store, + _EllipticCurve, + _PassphraseHelper, + _PrivateKey, +) + +__all__ = [ + "DTLS_CLIENT_METHOD", + "DTLS_METHOD", + "DTLS_SERVER_METHOD", + "MODE_RELEASE_BUFFERS", + "NO_OVERLAPPING_PROTOCOLS", + "OPENSSL_BUILT_ON", + "OPENSSL_CFLAGS", + "OPENSSL_DIR", + "OPENSSL_PLATFORM", + "OPENSSL_VERSION", + "OPENSSL_VERSION_NUMBER", + "OP_ALL", + "OP_CIPHER_SERVER_PREFERENCE", + "OP_COOKIE_EXCHANGE", + "OP_DONT_INSERT_EMPTY_FRAGMENTS", + "OP_EPHEMERAL_RSA", + "OP_MICROSOFT_BIG_SSLV3_BUFFER", + "OP_MICROSOFT_SESS_ID_BUG", + "OP_MSIE_SSLV2_RSA_PADDING", + "OP_NETSCAPE_CA_DN_BUG", + "OP_NETSCAPE_CHALLENGE_BUG", + "OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG", + "OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG", + "OP_NO_COMPRESSION", + "OP_NO_QUERY_MTU", + "OP_NO_TICKET", + "OP_PKCS1_CHECK_1", + "OP_PKCS1_CHECK_2", + "OP_SINGLE_DH_USE", + "OP_SINGLE_ECDH_USE", + "OP_SSLEAY_080_CLIENT_DH_BUG", + "OP_SSLREF2_REUSE_CERT_TYPE_BUG", + "OP_TLS_BLOCK_PADDING_BUG", + "OP_TLS_D5_BUG", + "OP_TLS_ROLLBACK_BUG", + "RECEIVED_SHUTDOWN", + "SENT_SHUTDOWN", + "SESS_CACHE_BOTH", + "SESS_CACHE_CLIENT", + "SESS_CACHE_NO_AUTO_CLEAR", + "SESS_CACHE_NO_INTERNAL", + "SESS_CACHE_NO_INTERNAL_LOOKUP", + "SESS_CACHE_NO_INTERNAL_STORE", + "SESS_CACHE_OFF", + "SESS_CACHE_SERVER", + "SSL3_VERSION", + "SSLEAY_BUILT_ON", + "SSLEAY_CFLAGS", + "SSLEAY_DIR", + "SSLEAY_PLATFORM", + "SSLEAY_VERSION", + "SSL_CB_ACCEPT_EXIT", + "SSL_CB_ACCEPT_LOOP", + "SSL_CB_ALERT", + "SSL_CB_CONNECT_EXIT", + "SSL_CB_CONNECT_LOOP", + "SSL_CB_EXIT", + "SSL_CB_HANDSHAKE_DONE", + "SSL_CB_HANDSHAKE_START", + "SSL_CB_LOOP", + "SSL_CB_READ", + "SSL_CB_READ_ALERT", + "SSL_CB_WRITE", + "SSL_CB_WRITE_ALERT", + "SSL_ST_ACCEPT", + "SSL_ST_CONNECT", + "SSL_ST_MASK", + "TLS1_1_VERSION", + "TLS1_2_VERSION", + "TLS1_3_VERSION", + "TLS1_VERSION", + "TLS_CLIENT_METHOD", + "TLS_METHOD", + "TLS_SERVER_METHOD", + "VERIFY_CLIENT_ONCE", + "VERIFY_FAIL_IF_NO_PEER_CERT", + "VERIFY_NONE", + "VERIFY_PEER", + "Connection", + "Context", + "Error", + "OP_NO_SSLv2", + "OP_NO_SSLv3", + "OP_NO_TLSv1", + "OP_NO_TLSv1_1", + "OP_NO_TLSv1_2", + "OP_NO_TLSv1_3", + "SSLeay_version", + "SSLv23_METHOD", + "Session", + "SysCallError", + "TLSv1_1_METHOD", + "TLSv1_2_METHOD", + "TLSv1_METHOD", + "WantReadError", + "WantWriteError", + "WantX509LookupError", + "X509VerificationCodes", + "ZeroReturnError", +] + + +OPENSSL_VERSION_NUMBER: int = _lib.OPENSSL_VERSION_NUMBER +OPENSSL_VERSION: int = _lib.OPENSSL_VERSION +OPENSSL_CFLAGS: int = _lib.OPENSSL_CFLAGS +OPENSSL_PLATFORM: int = _lib.OPENSSL_PLATFORM +OPENSSL_DIR: int = _lib.OPENSSL_DIR +OPENSSL_BUILT_ON: int = _lib.OPENSSL_BUILT_ON + +SSLEAY_VERSION = OPENSSL_VERSION +SSLEAY_CFLAGS = OPENSSL_CFLAGS +SSLEAY_PLATFORM = OPENSSL_PLATFORM +SSLEAY_DIR = OPENSSL_DIR +SSLEAY_BUILT_ON = OPENSSL_BUILT_ON + +SENT_SHUTDOWN = _lib.SSL_SENT_SHUTDOWN +RECEIVED_SHUTDOWN = _lib.SSL_RECEIVED_SHUTDOWN + +SSLv23_METHOD = 3 +TLSv1_METHOD = 4 +TLSv1_1_METHOD = 5 +TLSv1_2_METHOD = 6 +TLS_METHOD = 7 +TLS_SERVER_METHOD = 8 +TLS_CLIENT_METHOD = 9 +DTLS_METHOD = 10 +DTLS_SERVER_METHOD = 11 +DTLS_CLIENT_METHOD = 12 + +SSL3_VERSION: int = _lib.SSL3_VERSION +TLS1_VERSION: int = _lib.TLS1_VERSION +TLS1_1_VERSION: int = _lib.TLS1_1_VERSION +TLS1_2_VERSION: int = _lib.TLS1_2_VERSION +TLS1_3_VERSION: int = _lib.TLS1_3_VERSION + +OP_NO_SSLv2: int = _lib.SSL_OP_NO_SSLv2 +OP_NO_SSLv3: int = _lib.SSL_OP_NO_SSLv3 +OP_NO_TLSv1: int = _lib.SSL_OP_NO_TLSv1 +OP_NO_TLSv1_1: int = _lib.SSL_OP_NO_TLSv1_1 +OP_NO_TLSv1_2: int = _lib.SSL_OP_NO_TLSv1_2 +OP_NO_TLSv1_3: int = _lib.SSL_OP_NO_TLSv1_3 + +MODE_RELEASE_BUFFERS: int = _lib.SSL_MODE_RELEASE_BUFFERS + +OP_SINGLE_DH_USE: int = _lib.SSL_OP_SINGLE_DH_USE +OP_SINGLE_ECDH_USE: int = _lib.SSL_OP_SINGLE_ECDH_USE +OP_EPHEMERAL_RSA: int = _lib.SSL_OP_EPHEMERAL_RSA +OP_MICROSOFT_SESS_ID_BUG: int = _lib.SSL_OP_MICROSOFT_SESS_ID_BUG +OP_NETSCAPE_CHALLENGE_BUG: int = _lib.SSL_OP_NETSCAPE_CHALLENGE_BUG +OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG: int = ( + _lib.SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG +) +OP_SSLREF2_REUSE_CERT_TYPE_BUG: int = _lib.SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG +OP_MICROSOFT_BIG_SSLV3_BUFFER: int = _lib.SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER +OP_MSIE_SSLV2_RSA_PADDING: int = _lib.SSL_OP_MSIE_SSLV2_RSA_PADDING +OP_SSLEAY_080_CLIENT_DH_BUG: int = _lib.SSL_OP_SSLEAY_080_CLIENT_DH_BUG +OP_TLS_D5_BUG: int = _lib.SSL_OP_TLS_D5_BUG +OP_TLS_BLOCK_PADDING_BUG: int = _lib.SSL_OP_TLS_BLOCK_PADDING_BUG +OP_DONT_INSERT_EMPTY_FRAGMENTS: int = _lib.SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS +OP_CIPHER_SERVER_PREFERENCE: int = _lib.SSL_OP_CIPHER_SERVER_PREFERENCE +OP_TLS_ROLLBACK_BUG: int = _lib.SSL_OP_TLS_ROLLBACK_BUG +OP_PKCS1_CHECK_1 = _lib.SSL_OP_PKCS1_CHECK_1 +OP_PKCS1_CHECK_2: int = _lib.SSL_OP_PKCS1_CHECK_2 +OP_NETSCAPE_CA_DN_BUG: int = _lib.SSL_OP_NETSCAPE_CA_DN_BUG +OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG: int = ( + _lib.SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG +) +OP_NO_COMPRESSION: int = _lib.SSL_OP_NO_COMPRESSION + +OP_NO_QUERY_MTU: int = _lib.SSL_OP_NO_QUERY_MTU +OP_COOKIE_EXCHANGE: int = _lib.SSL_OP_COOKIE_EXCHANGE +OP_NO_TICKET: int = _lib.SSL_OP_NO_TICKET + +try: + OP_NO_RENEGOTIATION: int = _lib.SSL_OP_NO_RENEGOTIATION + __all__.append("OP_NO_RENEGOTIATION") +except AttributeError: + pass + +try: + OP_IGNORE_UNEXPECTED_EOF: int = _lib.SSL_OP_IGNORE_UNEXPECTED_EOF + __all__.append("OP_IGNORE_UNEXPECTED_EOF") +except AttributeError: + pass + +try: + OP_LEGACY_SERVER_CONNECT: int = _lib.SSL_OP_LEGACY_SERVER_CONNECT + __all__.append("OP_LEGACY_SERVER_CONNECT") +except AttributeError: + pass + +OP_ALL: int = _lib.SSL_OP_ALL + +VERIFY_PEER: int = _lib.SSL_VERIFY_PEER +VERIFY_FAIL_IF_NO_PEER_CERT: int = _lib.SSL_VERIFY_FAIL_IF_NO_PEER_CERT +VERIFY_CLIENT_ONCE: int = _lib.SSL_VERIFY_CLIENT_ONCE +VERIFY_NONE: int = _lib.SSL_VERIFY_NONE + +SESS_CACHE_OFF: int = _lib.SSL_SESS_CACHE_OFF +SESS_CACHE_CLIENT: int = _lib.SSL_SESS_CACHE_CLIENT +SESS_CACHE_SERVER: int = _lib.SSL_SESS_CACHE_SERVER +SESS_CACHE_BOTH: int = _lib.SSL_SESS_CACHE_BOTH +SESS_CACHE_NO_AUTO_CLEAR: int = _lib.SSL_SESS_CACHE_NO_AUTO_CLEAR +SESS_CACHE_NO_INTERNAL_LOOKUP: int = _lib.SSL_SESS_CACHE_NO_INTERNAL_LOOKUP +SESS_CACHE_NO_INTERNAL_STORE: int = _lib.SSL_SESS_CACHE_NO_INTERNAL_STORE +SESS_CACHE_NO_INTERNAL: int = _lib.SSL_SESS_CACHE_NO_INTERNAL + +SSL_ST_CONNECT: int = _lib.SSL_ST_CONNECT +SSL_ST_ACCEPT: int = _lib.SSL_ST_ACCEPT +SSL_ST_MASK: int = _lib.SSL_ST_MASK + +SSL_CB_LOOP: int = _lib.SSL_CB_LOOP +SSL_CB_EXIT: int = _lib.SSL_CB_EXIT +SSL_CB_READ: int = _lib.SSL_CB_READ +SSL_CB_WRITE: int = _lib.SSL_CB_WRITE +SSL_CB_ALERT: int = _lib.SSL_CB_ALERT +SSL_CB_READ_ALERT: int = _lib.SSL_CB_READ_ALERT +SSL_CB_WRITE_ALERT: int = _lib.SSL_CB_WRITE_ALERT +SSL_CB_ACCEPT_LOOP: int = _lib.SSL_CB_ACCEPT_LOOP +SSL_CB_ACCEPT_EXIT: int = _lib.SSL_CB_ACCEPT_EXIT +SSL_CB_CONNECT_LOOP: int = _lib.SSL_CB_CONNECT_LOOP +SSL_CB_CONNECT_EXIT: int = _lib.SSL_CB_CONNECT_EXIT +SSL_CB_HANDSHAKE_START: int = _lib.SSL_CB_HANDSHAKE_START +SSL_CB_HANDSHAKE_DONE: int = _lib.SSL_CB_HANDSHAKE_DONE + +_Buffer = typing.Union[bytes, bytearray, memoryview] +_T = TypeVar("_T") + + +class _NoOverlappingProtocols: + pass + + +NO_OVERLAPPING_PROTOCOLS = _NoOverlappingProtocols() + +# Callback types. +_ALPNSelectCallback = Callable[ + [ + "Connection", + typing.List[bytes], + ], + typing.Union[bytes, _NoOverlappingProtocols], +] +_CookieGenerateCallback = Callable[["Connection"], bytes] +_CookieVerifyCallback = Callable[["Connection", bytes], bool] +_OCSPClientCallback = Callable[["Connection", bytes, Optional[_T]], bool] +_OCSPServerCallback = Callable[["Connection", Optional[_T]], bytes] +_PassphraseCallback = Callable[[int, bool, Optional[_T]], bytes] +_VerifyCallback = Callable[["Connection", X509, int, int, int], bool] + + +class X509VerificationCodes: + """ + Success and error codes for X509 verification, as returned by the + underlying ``X509_STORE_CTX_get_error()`` function and passed by pyOpenSSL + to verification callback functions. + + See `OpenSSL Verification Errors + `_ + for details. + """ + + OK = _lib.X509_V_OK + ERR_UNABLE_TO_GET_ISSUER_CERT = _lib.X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT + ERR_UNABLE_TO_GET_CRL = _lib.X509_V_ERR_UNABLE_TO_GET_CRL + ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE = ( + _lib.X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE + ) + ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE = ( + _lib.X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE + ) + ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY = ( + _lib.X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY + ) + ERR_CERT_SIGNATURE_FAILURE = _lib.X509_V_ERR_CERT_SIGNATURE_FAILURE + ERR_CRL_SIGNATURE_FAILURE = _lib.X509_V_ERR_CRL_SIGNATURE_FAILURE + ERR_CERT_NOT_YET_VALID = _lib.X509_V_ERR_CERT_NOT_YET_VALID + ERR_CERT_HAS_EXPIRED = _lib.X509_V_ERR_CERT_HAS_EXPIRED + ERR_CRL_NOT_YET_VALID = _lib.X509_V_ERR_CRL_NOT_YET_VALID + ERR_CRL_HAS_EXPIRED = _lib.X509_V_ERR_CRL_HAS_EXPIRED + ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD = ( + _lib.X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD + ) + ERR_ERROR_IN_CERT_NOT_AFTER_FIELD = ( + _lib.X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD + ) + ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD = ( + _lib.X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD + ) + ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD = ( + _lib.X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD + ) + ERR_OUT_OF_MEM = _lib.X509_V_ERR_OUT_OF_MEM + ERR_DEPTH_ZERO_SELF_SIGNED_CERT = ( + _lib.X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT + ) + ERR_SELF_SIGNED_CERT_IN_CHAIN = _lib.X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN + ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY = ( + _lib.X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY + ) + ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE = ( + _lib.X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE + ) + ERR_CERT_CHAIN_TOO_LONG = _lib.X509_V_ERR_CERT_CHAIN_TOO_LONG + ERR_CERT_REVOKED = _lib.X509_V_ERR_CERT_REVOKED + ERR_INVALID_CA = _lib.X509_V_ERR_INVALID_CA + ERR_PATH_LENGTH_EXCEEDED = _lib.X509_V_ERR_PATH_LENGTH_EXCEEDED + ERR_INVALID_PURPOSE = _lib.X509_V_ERR_INVALID_PURPOSE + ERR_CERT_UNTRUSTED = _lib.X509_V_ERR_CERT_UNTRUSTED + ERR_CERT_REJECTED = _lib.X509_V_ERR_CERT_REJECTED + ERR_SUBJECT_ISSUER_MISMATCH = _lib.X509_V_ERR_SUBJECT_ISSUER_MISMATCH + ERR_AKID_SKID_MISMATCH = _lib.X509_V_ERR_AKID_SKID_MISMATCH + ERR_AKID_ISSUER_SERIAL_MISMATCH = ( + _lib.X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH + ) + ERR_KEYUSAGE_NO_CERTSIGN = _lib.X509_V_ERR_KEYUSAGE_NO_CERTSIGN + ERR_UNABLE_TO_GET_CRL_ISSUER = _lib.X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER + ERR_UNHANDLED_CRITICAL_EXTENSION = ( + _lib.X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION + ) + ERR_KEYUSAGE_NO_CRL_SIGN = _lib.X509_V_ERR_KEYUSAGE_NO_CRL_SIGN + ERR_UNHANDLED_CRITICAL_CRL_EXTENSION = ( + _lib.X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION + ) + ERR_INVALID_NON_CA = _lib.X509_V_ERR_INVALID_NON_CA + ERR_PROXY_PATH_LENGTH_EXCEEDED = _lib.X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED + ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE = ( + _lib.X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE + ) + ERR_PROXY_CERTIFICATES_NOT_ALLOWED = ( + _lib.X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED + ) + ERR_INVALID_EXTENSION = _lib.X509_V_ERR_INVALID_EXTENSION + ERR_INVALID_POLICY_EXTENSION = _lib.X509_V_ERR_INVALID_POLICY_EXTENSION + ERR_NO_EXPLICIT_POLICY = _lib.X509_V_ERR_NO_EXPLICIT_POLICY + ERR_DIFFERENT_CRL_SCOPE = _lib.X509_V_ERR_DIFFERENT_CRL_SCOPE + ERR_UNSUPPORTED_EXTENSION_FEATURE = ( + _lib.X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE + ) + ERR_UNNESTED_RESOURCE = _lib.X509_V_ERR_UNNESTED_RESOURCE + ERR_PERMITTED_VIOLATION = _lib.X509_V_ERR_PERMITTED_VIOLATION + ERR_EXCLUDED_VIOLATION = _lib.X509_V_ERR_EXCLUDED_VIOLATION + ERR_SUBTREE_MINMAX = _lib.X509_V_ERR_SUBTREE_MINMAX + ERR_UNSUPPORTED_CONSTRAINT_TYPE = ( + _lib.X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE + ) + ERR_UNSUPPORTED_CONSTRAINT_SYNTAX = ( + _lib.X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX + ) + ERR_UNSUPPORTED_NAME_SYNTAX = _lib.X509_V_ERR_UNSUPPORTED_NAME_SYNTAX + ERR_CRL_PATH_VALIDATION_ERROR = _lib.X509_V_ERR_CRL_PATH_VALIDATION_ERROR + ERR_HOSTNAME_MISMATCH = _lib.X509_V_ERR_HOSTNAME_MISMATCH + ERR_EMAIL_MISMATCH = _lib.X509_V_ERR_EMAIL_MISMATCH + ERR_IP_ADDRESS_MISMATCH = _lib.X509_V_ERR_IP_ADDRESS_MISMATCH + ERR_APPLICATION_VERIFICATION = _lib.X509_V_ERR_APPLICATION_VERIFICATION + + +# Taken from https://golang.org/src/crypto/x509/root_linux.go +_CERTIFICATE_FILE_LOCATIONS = [ + "/etc/ssl/certs/ca-certificates.crt", # Debian/Ubuntu/Gentoo etc. + "/etc/pki/tls/certs/ca-bundle.crt", # Fedora/RHEL 6 + "/etc/ssl/ca-bundle.pem", # OpenSUSE + "/etc/pki/tls/cacert.pem", # OpenELEC + "/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem", # CentOS/RHEL 7 +] + +_CERTIFICATE_PATH_LOCATIONS = [ + "/etc/ssl/certs", # SLES10/SLES11 +] + +# These values are compared to output from cffi's ffi.string so they must be +# byte strings. +_CRYPTOGRAPHY_MANYLINUX_CA_DIR = b"/opt/pyca/cryptography/openssl/certs" +_CRYPTOGRAPHY_MANYLINUX_CA_FILE = b"/opt/pyca/cryptography/openssl/cert.pem" + + +class Error(Exception): + """ + An error occurred in an `OpenSSL.SSL` API. + """ + + +_raise_current_error = partial(_exception_from_error_queue, Error) +_openssl_assert = _make_assert(Error) + + +class WantReadError(Error): + pass + + +class WantWriteError(Error): + pass + + +class WantX509LookupError(Error): + pass + + +class ZeroReturnError(Error): + pass + + +class SysCallError(Error): + pass + + +class _CallbackExceptionHelper: + """ + A base class for wrapper classes that allow for intelligent exception + handling in OpenSSL callbacks. + + :ivar list _problems: Any exceptions that occurred while executing in a + context where they could not be raised in the normal way. Typically + this is because OpenSSL has called into some Python code and requires a + return value. The exceptions are saved to be raised later when it is + possible to do so. + """ + + def __init__(self) -> None: + self._problems: list[Exception] = [] + + def raise_if_problem(self) -> None: + """ + Raise an exception from the OpenSSL error queue or that was previously + captured whe running a callback. + """ + if self._problems: + try: + _raise_current_error() + except Error: + pass + raise self._problems.pop(0) + + +class _VerifyHelper(_CallbackExceptionHelper): + """ + Wrap a callback such that it can be used as a certificate verification + callback. + """ + + def __init__(self, callback: _VerifyCallback) -> None: + _CallbackExceptionHelper.__init__(self) + + @wraps(callback) + def wrapper(ok, store_ctx): # type: ignore[no-untyped-def] + x509 = _lib.X509_STORE_CTX_get_current_cert(store_ctx) + _lib.X509_up_ref(x509) + cert = X509._from_raw_x509_ptr(x509) + error_number = _lib.X509_STORE_CTX_get_error(store_ctx) + error_depth = _lib.X509_STORE_CTX_get_error_depth(store_ctx) + + index = _lib.SSL_get_ex_data_X509_STORE_CTX_idx() + ssl = _lib.X509_STORE_CTX_get_ex_data(store_ctx, index) + connection = Connection._reverse_mapping[ssl] + + try: + result = callback( + connection, cert, error_number, error_depth, ok + ) + except Exception as e: + self._problems.append(e) + return 0 + else: + if result: + _lib.X509_STORE_CTX_set_error(store_ctx, _lib.X509_V_OK) + return 1 + else: + return 0 + + self.callback = _ffi.callback( + "int (*)(int, X509_STORE_CTX *)", wrapper + ) + + +class _ALPNSelectHelper(_CallbackExceptionHelper): + """ + Wrap a callback such that it can be used as an ALPN selection callback. + """ + + def __init__(self, callback: _ALPNSelectCallback) -> None: + _CallbackExceptionHelper.__init__(self) + + @wraps(callback) + def wrapper(ssl, out, outlen, in_, inlen, arg): # type: ignore[no-untyped-def] + try: + conn = Connection._reverse_mapping[ssl] + + # The string passed to us is made up of multiple + # length-prefixed bytestrings. We need to split that into a + # list. + instr = _ffi.buffer(in_, inlen)[:] + protolist = [] + while instr: + encoded_len = instr[0] + proto = instr[1 : encoded_len + 1] + protolist.append(proto) + instr = instr[encoded_len + 1 :] + + # Call the callback + outbytes = callback(conn, protolist) + any_accepted = True + if outbytes is NO_OVERLAPPING_PROTOCOLS: + outbytes = b"" + any_accepted = False + elif not isinstance(outbytes, bytes): + raise TypeError( + "ALPN callback must return a bytestring or the " + "special NO_OVERLAPPING_PROTOCOLS sentinel value." + ) + + # Save our callback arguments on the connection object to make + # sure that they don't get freed before OpenSSL can use them. + # Then, return them in the appropriate output parameters. + conn._alpn_select_callback_args = [ + _ffi.new("unsigned char *", len(outbytes)), + _ffi.new("unsigned char[]", outbytes), + ] + outlen[0] = conn._alpn_select_callback_args[0][0] + out[0] = conn._alpn_select_callback_args[1] + if not any_accepted: + return _lib.SSL_TLSEXT_ERR_NOACK + return _lib.SSL_TLSEXT_ERR_OK + except Exception as e: + self._problems.append(e) + return _lib.SSL_TLSEXT_ERR_ALERT_FATAL + + self.callback = _ffi.callback( + ( + "int (*)(SSL *, unsigned char **, unsigned char *, " + "const unsigned char *, unsigned int, void *)" + ), + wrapper, + ) + + +class _OCSPServerCallbackHelper(_CallbackExceptionHelper): + """ + Wrap a callback such that it can be used as an OCSP callback for the server + side. + + Annoyingly, OpenSSL defines one OCSP callback but uses it in two different + ways. For servers, that callback is expected to retrieve some OCSP data and + hand it to OpenSSL, and may return only SSL_TLSEXT_ERR_OK, + SSL_TLSEXT_ERR_FATAL, and SSL_TLSEXT_ERR_NOACK. For clients, that callback + is expected to check the OCSP data, and returns a negative value on error, + 0 if the response is not acceptable, or positive if it is. These are + mutually exclusive return code behaviours, and they mean that we need two + helpers so that we always return an appropriate error code if the user's + code throws an exception. + + Given that we have to have two helpers anyway, these helpers are a bit more + helpery than most: specifically, they hide a few more of the OpenSSL + functions so that the user has an easier time writing these callbacks. + + This helper implements the server side. + """ + + def __init__(self, callback: _OCSPServerCallback[Any]) -> None: + _CallbackExceptionHelper.__init__(self) + + @wraps(callback) + def wrapper(ssl, cdata): # type: ignore[no-untyped-def] + try: + conn = Connection._reverse_mapping[ssl] + + # Extract the data if any was provided. + if cdata != _ffi.NULL: + data = _ffi.from_handle(cdata) + else: + data = None + + # Call the callback. + ocsp_data = callback(conn, data) + + if not isinstance(ocsp_data, bytes): + raise TypeError("OCSP callback must return a bytestring.") + + # If the OCSP data was provided, we will pass it to OpenSSL. + # However, we have an early exit here: if no OCSP data was + # provided we will just exit out and tell OpenSSL that there + # is nothing to do. + if not ocsp_data: + return 3 # SSL_TLSEXT_ERR_NOACK + + # OpenSSL takes ownership of this data and expects it to have + # been allocated by OPENSSL_malloc. + ocsp_data_length = len(ocsp_data) + data_ptr = _lib.OPENSSL_malloc(ocsp_data_length) + _ffi.buffer(data_ptr, ocsp_data_length)[:] = ocsp_data + + _lib.SSL_set_tlsext_status_ocsp_resp( + ssl, data_ptr, ocsp_data_length + ) + + return 0 + except Exception as e: + self._problems.append(e) + return 2 # SSL_TLSEXT_ERR_ALERT_FATAL + + self.callback = _ffi.callback("int (*)(SSL *, void *)", wrapper) + + +class _OCSPClientCallbackHelper(_CallbackExceptionHelper): + """ + Wrap a callback such that it can be used as an OCSP callback for the client + side. + + Annoyingly, OpenSSL defines one OCSP callback but uses it in two different + ways. For servers, that callback is expected to retrieve some OCSP data and + hand it to OpenSSL, and may return only SSL_TLSEXT_ERR_OK, + SSL_TLSEXT_ERR_FATAL, and SSL_TLSEXT_ERR_NOACK. For clients, that callback + is expected to check the OCSP data, and returns a negative value on error, + 0 if the response is not acceptable, or positive if it is. These are + mutually exclusive return code behaviours, and they mean that we need two + helpers so that we always return an appropriate error code if the user's + code throws an exception. + + Given that we have to have two helpers anyway, these helpers are a bit more + helpery than most: specifically, they hide a few more of the OpenSSL + functions so that the user has an easier time writing these callbacks. + + This helper implements the client side. + """ + + def __init__(self, callback: _OCSPClientCallback[Any]) -> None: + _CallbackExceptionHelper.__init__(self) + + @wraps(callback) + def wrapper(ssl, cdata): # type: ignore[no-untyped-def] + try: + conn = Connection._reverse_mapping[ssl] + + # Extract the data if any was provided. + if cdata != _ffi.NULL: + data = _ffi.from_handle(cdata) + else: + data = None + + # Get the OCSP data. + ocsp_ptr = _ffi.new("unsigned char **") + ocsp_len = _lib.SSL_get_tlsext_status_ocsp_resp(ssl, ocsp_ptr) + if ocsp_len < 0: + # No OCSP data. + ocsp_data = b"" + else: + # Copy the OCSP data, then pass it to the callback. + ocsp_data = _ffi.buffer(ocsp_ptr[0], ocsp_len)[:] + + valid = callback(conn, ocsp_data, data) + + # Return 1 on success or 0 on error. + return int(bool(valid)) + + except Exception as e: + self._problems.append(e) + # Return negative value if an exception is hit. + return -1 + + self.callback = _ffi.callback("int (*)(SSL *, void *)", wrapper) + + +class _CookieGenerateCallbackHelper(_CallbackExceptionHelper): + def __init__(self, callback: _CookieGenerateCallback) -> None: + _CallbackExceptionHelper.__init__(self) + + @wraps(callback) + def wrapper(ssl, out, outlen): # type: ignore[no-untyped-def] + try: + conn = Connection._reverse_mapping[ssl] + cookie = callback(conn) + out[0 : len(cookie)] = cookie + outlen[0] = len(cookie) + return 1 + except Exception as e: + self._problems.append(e) + # "a zero return value can be used to abort the handshake" + return 0 + + self.callback = _ffi.callback( + "int (*)(SSL *, unsigned char *, unsigned int *)", + wrapper, + ) + + +class _CookieVerifyCallbackHelper(_CallbackExceptionHelper): + def __init__(self, callback: _CookieVerifyCallback) -> None: + _CallbackExceptionHelper.__init__(self) + + @wraps(callback) + def wrapper(ssl, c_cookie, cookie_len): # type: ignore[no-untyped-def] + try: + conn = Connection._reverse_mapping[ssl] + return callback(conn, bytes(c_cookie[0:cookie_len])) + except Exception as e: + self._problems.append(e) + return 0 + + self.callback = _ffi.callback( + "int (*)(SSL *, unsigned char *, unsigned int)", + wrapper, + ) + + +def _asFileDescriptor(obj: Any) -> int: + fd = None + if not isinstance(obj, int): + meth = getattr(obj, "fileno", None) + if meth is not None: + obj = meth() + + if isinstance(obj, int): + fd = obj + + if not isinstance(fd, int): + raise TypeError("argument must be an int, or have a fileno() method.") + elif fd < 0: + raise ValueError( + f"file descriptor cannot be a negative integer ({fd:i})" + ) + + return fd + + +def OpenSSL_version(type: int) -> bytes: + """ + Return a string describing the version of OpenSSL in use. + + :param type: One of the :const:`OPENSSL_` constants defined in this module. + """ + return _ffi.string(_lib.OpenSSL_version(type)) + + +SSLeay_version = OpenSSL_version + + +def _make_requires(flag: int, error: str) -> Callable[[_T], _T]: + """ + Builds a decorator that ensures that functions that rely on OpenSSL + functions that are not present in this build raise NotImplementedError, + rather than AttributeError coming out of cryptography. + + :param flag: A cryptography flag that guards the functions, e.g. + ``Cryptography_HAS_NEXTPROTONEG``. + :param error: The string to be used in the exception if the flag is false. + """ + + def _requires_decorator(func): # type: ignore[no-untyped-def] + if not flag: + + @wraps(func) + def explode(*args, **kwargs): # type: ignore[no-untyped-def] + raise NotImplementedError(error) + + return explode + else: + return func + + return _requires_decorator + + +_requires_keylog = _make_requires( + getattr(_lib, "Cryptography_HAS_KEYLOG", 0), "Key logging not available" +) + + +class Session: + """ + A class representing an SSL session. A session defines certain connection + parameters which may be re-used to speed up the setup of subsequent + connections. + + .. versionadded:: 0.14 + """ + + _session: Any + + +F = TypeVar("F", bound=Callable[..., Any]) + + +def _require_not_used(f: F) -> F: + @wraps(f) + def inner(self: Context, *args: Any, **kwargs: Any) -> Any: + if self._used: + warnings.warn( + ( + "Attempting to mutate a Context after a Connection was " + "created. In the future, this will raise an exception" + ), + DeprecationWarning, + stacklevel=2, + ) + return f(self, *args, **kwargs) + + return typing.cast(F, inner) + + +class Context: + """ + :class:`OpenSSL.SSL.Context` instances define the parameters for setting + up new SSL connections. + + :param method: One of TLS_METHOD, TLS_CLIENT_METHOD, TLS_SERVER_METHOD, + DTLS_METHOD, DTLS_CLIENT_METHOD, or DTLS_SERVER_METHOD. + SSLv23_METHOD, TLSv1_METHOD, etc. are deprecated and should + not be used. + """ + + _methods: typing.ClassVar[ + dict[int, tuple[Callable[[], Any], int | None]] + ] = { + SSLv23_METHOD: (_lib.TLS_method, None), + TLSv1_METHOD: (_lib.TLS_method, TLS1_VERSION), + TLSv1_1_METHOD: (_lib.TLS_method, TLS1_1_VERSION), + TLSv1_2_METHOD: (_lib.TLS_method, TLS1_2_VERSION), + TLS_METHOD: (_lib.TLS_method, None), + TLS_SERVER_METHOD: (_lib.TLS_server_method, None), + TLS_CLIENT_METHOD: (_lib.TLS_client_method, None), + DTLS_METHOD: (_lib.DTLS_method, None), + DTLS_SERVER_METHOD: (_lib.DTLS_server_method, None), + DTLS_CLIENT_METHOD: (_lib.DTLS_client_method, None), + } + + def __init__(self, method: int) -> None: + if not isinstance(method, int): + raise TypeError("method must be an integer") + + try: + method_func, version = self._methods[method] + except KeyError: + raise ValueError("No such protocol") + + method_obj = method_func() + _openssl_assert(method_obj != _ffi.NULL) + + context = _lib.SSL_CTX_new(method_obj) + _openssl_assert(context != _ffi.NULL) + context = _ffi.gc(context, _lib.SSL_CTX_free) + + self._context = context + self._used = False + self._passphrase_helper: _PassphraseHelper | None = None + self._passphrase_callback: _PassphraseCallback[Any] | None = None + self._passphrase_userdata: Any | None = None + self._verify_helper: _VerifyHelper | None = None + self._verify_callback: _VerifyCallback | None = None + self._info_callback = None + self._keylog_callback = None + self._tlsext_servername_callback = None + self._app_data = None + self._alpn_select_helper: _ALPNSelectHelper | None = None + self._alpn_select_callback: _ALPNSelectCallback | None = None + self._ocsp_helper: ( + _OCSPClientCallbackHelper | _OCSPServerCallbackHelper | None + ) = None + self._ocsp_callback: ( + _OCSPClientCallback[Any] | _OCSPServerCallback[Any] | None + ) = None + self._ocsp_data: Any | None = None + self._cookie_generate_helper: _CookieGenerateCallbackHelper | None = ( + None + ) + self._cookie_verify_helper: _CookieVerifyCallbackHelper | None = None + + self.set_mode( + _lib.SSL_MODE_ENABLE_PARTIAL_WRITE + | _lib.SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER + ) + if version is not None: + self.set_min_proto_version(version) + self.set_max_proto_version(version) + + @_require_not_used + def set_min_proto_version(self, version: int) -> None: + """ + Set the minimum supported protocol version. Setting the minimum + version to 0 will enable protocol versions down to the lowest version + supported by the library. + + If the underlying OpenSSL build is missing support for the selected + version, this method will raise an exception. + """ + _openssl_assert( + _lib.SSL_CTX_set_min_proto_version(self._context, version) == 1 + ) + + @_require_not_used + def set_max_proto_version(self, version: int) -> None: + """ + Set the maximum supported protocol version. Setting the maximum + version to 0 will enable protocol versions up to the highest version + supported by the library. + + If the underlying OpenSSL build is missing support for the selected + version, this method will raise an exception. + """ + _openssl_assert( + _lib.SSL_CTX_set_max_proto_version(self._context, version) == 1 + ) + + @_require_not_used + def load_verify_locations( + self, + cafile: _StrOrBytesPath | None, + capath: _StrOrBytesPath | None = None, + ) -> None: + """ + Let SSL know where we can find trusted certificates for the certificate + chain. Note that the certificates have to be in PEM format. + + If capath is passed, it must be a directory prepared using the + ``c_rehash`` tool included with OpenSSL. Either, but not both, of + *pemfile* or *capath* may be :data:`None`. + + :param cafile: In which file we can find the certificates (``bytes`` or + ``str``). + :param capath: In which directory we can find the certificates + (``bytes`` or ``str``). + + :return: None + """ + if cafile is None: + cafile = _ffi.NULL + else: + cafile = _path_bytes(cafile) + + if capath is None: + capath = _ffi.NULL + else: + capath = _path_bytes(capath) + + load_result = _lib.SSL_CTX_load_verify_locations( + self._context, cafile, capath + ) + if not load_result: + _raise_current_error() + + def _wrap_callback( + self, callback: _PassphraseCallback[_T] + ) -> _PassphraseHelper: + @wraps(callback) + def wrapper(size: int, verify: bool, userdata: Any) -> bytes: + return callback(size, verify, self._passphrase_userdata) + + return _PassphraseHelper( + FILETYPE_PEM, wrapper, more_args=True, truncate=True + ) + + @_require_not_used + def set_passwd_cb( + self, + callback: _PassphraseCallback[_T], + userdata: _T | None = None, + ) -> None: + """ + Set the passphrase callback. This function will be called + when a private key with a passphrase is loaded. + + :param callback: The Python callback to use. This must accept three + positional arguments. First, an integer giving the maximum length + of the passphrase it may return. If the returned passphrase is + longer than this, it will be truncated. Second, a boolean value + which will be true if the user should be prompted for the + passphrase twice and the callback should verify that the two values + supplied are equal. Third, the value given as the *userdata* + parameter to :meth:`set_passwd_cb`. The *callback* must return + a byte string. If an error occurs, *callback* should return a false + value (e.g. an empty string). + :param userdata: (optional) A Python object which will be given as + argument to the callback + :return: None + """ + if not callable(callback): + raise TypeError("callback must be callable") + + self._passphrase_helper = self._wrap_callback(callback) + self._passphrase_callback = self._passphrase_helper.callback + _lib.SSL_CTX_set_default_passwd_cb( + self._context, self._passphrase_callback + ) + self._passphrase_userdata = userdata + + @_require_not_used + def set_default_verify_paths(self) -> None: + """ + Specify that the platform provided CA certificates are to be used for + verification purposes. This method has some caveats related to the + binary wheels that cryptography (pyOpenSSL's primary dependency) ships: + + * macOS will only load certificates using this method if the user has + the ``openssl@1.1`` `Homebrew `_ formula installed + in the default location. + * Windows will not work. + * manylinux cryptography wheels will work on most common Linux + distributions in pyOpenSSL 17.1.0 and above. pyOpenSSL detects the + manylinux wheel and attempts to load roots via a fallback path. + + :return: None + """ + # SSL_CTX_set_default_verify_paths will attempt to load certs from + # both a cafile and capath that are set at compile time. However, + # it will first check environment variables and, if present, load + # those paths instead + set_result = _lib.SSL_CTX_set_default_verify_paths(self._context) + _openssl_assert(set_result == 1) + # After attempting to set default_verify_paths we need to know whether + # to go down the fallback path. + # First we'll check to see if any env vars have been set. If so, + # we won't try to do anything else because the user has set the path + # themselves. + if not self._check_env_vars_set("SSL_CERT_DIR", "SSL_CERT_FILE"): + default_dir = _ffi.string(_lib.X509_get_default_cert_dir()) + default_file = _ffi.string(_lib.X509_get_default_cert_file()) + # Now we check to see if the default_dir and default_file are set + # to the exact values we use in our manylinux builds. If they are + # then we know to load the fallbacks + if ( + default_dir == _CRYPTOGRAPHY_MANYLINUX_CA_DIR + and default_file == _CRYPTOGRAPHY_MANYLINUX_CA_FILE + ): + # This is manylinux, let's load our fallback paths + self._fallback_default_verify_paths( + _CERTIFICATE_FILE_LOCATIONS, _CERTIFICATE_PATH_LOCATIONS + ) + + def _check_env_vars_set(self, dir_env_var: str, file_env_var: str) -> bool: + """ + Check to see if the default cert dir/file environment vars are present. + + :return: bool + """ + return ( + os.environ.get(file_env_var) is not None + or os.environ.get(dir_env_var) is not None + ) + + def _fallback_default_verify_paths( + self, file_path: list[str], dir_path: list[str] + ) -> None: + """ + Default verify paths are based on the compiled version of OpenSSL. + However, when pyca/cryptography is compiled as a manylinux wheel + that compiled location can potentially be wrong. So, like Go, we + will try a predefined set of paths and attempt to load roots + from there. + + :return: None + """ + for cafile in file_path: + if os.path.isfile(cafile): + self.load_verify_locations(cafile) + break + + for capath in dir_path: + if os.path.isdir(capath): + self.load_verify_locations(None, capath) + break + + @_require_not_used + def use_certificate_chain_file(self, certfile: _StrOrBytesPath) -> None: + """ + Load a certificate chain from a file. + + :param certfile: The name of the certificate chain file (``bytes`` or + ``str``). Must be PEM encoded. + + :return: None + """ + certfile = _path_bytes(certfile) + + result = _lib.SSL_CTX_use_certificate_chain_file( + self._context, certfile + ) + if not result: + _raise_current_error() + + @_require_not_used + def use_certificate_file( + self, certfile: _StrOrBytesPath, filetype: int = FILETYPE_PEM + ) -> None: + """ + Load a certificate from a file + + :param certfile: The name of the certificate file (``bytes`` or + ``str``). + :param filetype: (optional) The encoding of the file, which is either + :const:`FILETYPE_PEM` or :const:`FILETYPE_ASN1`. The default is + :const:`FILETYPE_PEM`. + + :return: None + """ + certfile = _path_bytes(certfile) + if not isinstance(filetype, int): + raise TypeError("filetype must be an integer") + + use_result = _lib.SSL_CTX_use_certificate_file( + self._context, certfile, filetype + ) + if not use_result: + _raise_current_error() + + @_require_not_used + def use_certificate(self, cert: X509 | x509.Certificate) -> None: + """ + Load a certificate from a X509 object + + :param cert: The X509 object + :return: None + """ + # Mirrored at Connection.use_certificate + if not isinstance(cert, X509): + cert = X509.from_cryptography(cert) + else: + warnings.warn( + ( + "Passing pyOpenSSL X509 objects is deprecated. You " + "should use a cryptography.x509.Certificate instead." + ), + DeprecationWarning, + stacklevel=2, + ) + + use_result = _lib.SSL_CTX_use_certificate(self._context, cert._x509) + if not use_result: + _raise_current_error() + + @_require_not_used + def add_extra_chain_cert(self, certobj: X509 | x509.Certificate) -> None: + """ + Add certificate to chain + + :param certobj: The X509 certificate object to add to the chain + :return: None + """ + if not isinstance(certobj, X509): + certobj = X509.from_cryptography(certobj) + else: + warnings.warn( + ( + "Passing pyOpenSSL X509 objects is deprecated. You " + "should use a cryptography.x509.Certificate instead." + ), + DeprecationWarning, + stacklevel=2, + ) + + copy = _lib.X509_dup(certobj._x509) + add_result = _lib.SSL_CTX_add_extra_chain_cert(self._context, copy) + if not add_result: + # TODO: This is untested. + _lib.X509_free(copy) + _raise_current_error() + + def _raise_passphrase_exception(self) -> None: + if self._passphrase_helper is not None: + self._passphrase_helper.raise_if_problem(Error) + + _raise_current_error() + + @_require_not_used + def use_privatekey_file( + self, keyfile: _StrOrBytesPath, filetype: int = FILETYPE_PEM + ) -> None: + """ + Load a private key from a file + + :param keyfile: The name of the key file (``bytes`` or ``str``) + :param filetype: (optional) The encoding of the file, which is either + :const:`FILETYPE_PEM` or :const:`FILETYPE_ASN1`. The default is + :const:`FILETYPE_PEM`. + + :return: None + """ + keyfile = _path_bytes(keyfile) + + if not isinstance(filetype, int): + raise TypeError("filetype must be an integer") + + use_result = _lib.SSL_CTX_use_PrivateKey_file( + self._context, keyfile, filetype + ) + if not use_result: + self._raise_passphrase_exception() + + @_require_not_used + def use_privatekey(self, pkey: _PrivateKey | PKey) -> None: + """ + Load a private key from a PKey object + + :param pkey: The PKey object + :return: None + """ + # Mirrored at Connection.use_privatekey + if not isinstance(pkey, PKey): + pkey = PKey.from_cryptography_key(pkey) + else: + warnings.warn( + ( + "Passing pyOpenSSL PKey objects is deprecated. You " + "should use a cryptography private key instead." + ), + DeprecationWarning, + stacklevel=2, + ) + + use_result = _lib.SSL_CTX_use_PrivateKey(self._context, pkey._pkey) + if not use_result: + self._raise_passphrase_exception() + + def check_privatekey(self) -> None: + """ + Check if the private key (loaded with :meth:`use_privatekey`) matches + the certificate (loaded with :meth:`use_certificate`) + + :return: :data:`None` (raises :exc:`Error` if something's wrong) + """ + if not _lib.SSL_CTX_check_private_key(self._context): + _raise_current_error() + + @_require_not_used + def load_client_ca(self, cafile: bytes) -> None: + """ + Load the trusted certificates that will be sent to the client. Does + not actually imply any of the certificates are trusted; that must be + configured separately. + + :param bytes cafile: The path to a certificates file in PEM format. + :return: None + """ + ca_list = _lib.SSL_load_client_CA_file( + _text_to_bytes_and_warn("cafile", cafile) + ) + _openssl_assert(ca_list != _ffi.NULL) + _lib.SSL_CTX_set_client_CA_list(self._context, ca_list) + + @_require_not_used + def set_session_id(self, buf: bytes) -> None: + """ + Set the session id to *buf* within which a session can be reused for + this Context object. This is needed when doing session resumption, + because there is no way for a stored session to know which Context + object it is associated with. + + :param bytes buf: The session id. + + :returns: None + """ + buf = _text_to_bytes_and_warn("buf", buf) + _openssl_assert( + _lib.SSL_CTX_set_session_id_context(self._context, buf, len(buf)) + == 1 + ) + + @_require_not_used + def set_session_cache_mode(self, mode: int) -> int: + """ + Set the behavior of the session cache used by all connections using + this Context. The previously set mode is returned. See + :const:`SESS_CACHE_*` for details about particular modes. + + :param mode: One or more of the SESS_CACHE_* flags (combine using + bitwise or) + :returns: The previously set caching mode. + + .. versionadded:: 0.14 + """ + if not isinstance(mode, int): + raise TypeError("mode must be an integer") + + return _lib.SSL_CTX_set_session_cache_mode(self._context, mode) + + def get_session_cache_mode(self) -> int: + """ + Get the current session cache mode. + + :returns: The currently used cache mode. + + .. versionadded:: 0.14 + """ + return _lib.SSL_CTX_get_session_cache_mode(self._context) + + @_require_not_used + def set_verify( + self, mode: int, callback: _VerifyCallback | None = None + ) -> None: + """ + Set the verification flags for this Context object to *mode* and + specify that *callback* should be used for verification callbacks. + + :param mode: The verify mode, this should be one of + :const:`VERIFY_NONE` and :const:`VERIFY_PEER`. If + :const:`VERIFY_PEER` is used, *mode* can be OR:ed with + :const:`VERIFY_FAIL_IF_NO_PEER_CERT` and + :const:`VERIFY_CLIENT_ONCE` to further control the behaviour. + :param callback: The optional Python verification callback to use. + This should take five arguments: A Connection object, an X509 + object, and three integer variables, which are in turn potential + error number, error depth and return code. *callback* should + return True if verification passes and False otherwise. + If omitted, OpenSSL's default verification is used. + :return: None + + See SSL_CTX_set_verify(3SSL) for further details. + """ + if not isinstance(mode, int): + raise TypeError("mode must be an integer") + + if callback is None: + self._verify_helper = None + self._verify_callback = None + _lib.SSL_CTX_set_verify(self._context, mode, _ffi.NULL) + else: + if not callable(callback): + raise TypeError("callback must be callable") + + self._verify_helper = _VerifyHelper(callback) + self._verify_callback = self._verify_helper.callback + _lib.SSL_CTX_set_verify(self._context, mode, self._verify_callback) + + @_require_not_used + def set_verify_depth(self, depth: int) -> None: + """ + Set the maximum depth for the certificate chain verification that shall + be allowed for this Context object. + + :param depth: An integer specifying the verify depth + :return: None + """ + if not isinstance(depth, int): + raise TypeError("depth must be an integer") + + _lib.SSL_CTX_set_verify_depth(self._context, depth) + + def get_verify_mode(self) -> int: + """ + Retrieve the Context object's verify mode, as set by + :meth:`set_verify`. + + :return: The verify mode + """ + return _lib.SSL_CTX_get_verify_mode(self._context) + + def get_verify_depth(self) -> int: + """ + Retrieve the Context object's verify depth, as set by + :meth:`set_verify_depth`. + + :return: The verify depth + """ + return _lib.SSL_CTX_get_verify_depth(self._context) + + @_require_not_used + def load_tmp_dh(self, dhfile: _StrOrBytesPath) -> None: + """ + Load parameters for Ephemeral Diffie-Hellman + + :param dhfile: The file to load EDH parameters from (``bytes`` or + ``str``). + + :return: None + """ + dhfile = _path_bytes(dhfile) + + bio = _lib.BIO_new_file(dhfile, b"r") + if bio == _ffi.NULL: + _raise_current_error() + bio = _ffi.gc(bio, _lib.BIO_free) + + dh = _lib.PEM_read_bio_DHparams(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL) + dh = _ffi.gc(dh, _lib.DH_free) + res = _lib.SSL_CTX_set_tmp_dh(self._context, dh) + _openssl_assert(res == 1) + + @_require_not_used + def set_tmp_ecdh(self, curve: _EllipticCurve | ec.EllipticCurve) -> None: + """ + Select a curve to use for ECDHE key exchange. + + :param curve: A curve instance from cryptography + (:class:`~cryptogragraphy.hazmat.primitives.asymmetric.ec.EllipticCurve`). + Alternatively (deprecated) a curve object from either + :meth:`OpenSSL.crypto.get_elliptic_curve` or + :meth:`OpenSSL.crypto.get_elliptic_curves`. + + :return: None + """ + + if isinstance(curve, _EllipticCurve): + warnings.warn( + ( + "Passing pyOpenSSL elliptic curves to set_tmp_ecdh is " + "deprecated. You should use cryptography's elliptic curve " + "types instead." + ), + DeprecationWarning, + stacklevel=2, + ) + _lib.SSL_CTX_set_tmp_ecdh(self._context, curve._to_EC_KEY()) + else: + name = curve.name + if name == "secp192r1": + name = "prime192v1" + elif name == "secp256r1": + name = "prime256v1" + nid = _lib.OBJ_txt2nid(name.encode()) + if nid == _lib.NID_undef: + _raise_current_error() + + ec = _lib.EC_KEY_new_by_curve_name(nid) + _openssl_assert(ec != _ffi.NULL) + ec = _ffi.gc(ec, _lib.EC_KEY_free) + _lib.SSL_CTX_set_tmp_ecdh(self._context, ec) + + @_require_not_used + def set_cipher_list(self, cipher_list: bytes) -> None: + """ + Set the list of ciphers to be used in this context. + + See the OpenSSL manual for more information (e.g. + :manpage:`ciphers(1)`). + + Note this API does not change the cipher suites used in TLS 1.3 + Use `set_tls13_ciphersuites` for that. + + :param bytes cipher_list: An OpenSSL cipher string. + :return: None + """ + cipher_list = _text_to_bytes_and_warn("cipher_list", cipher_list) + + if not isinstance(cipher_list, bytes): + raise TypeError("cipher_list must be a byte string.") + + _openssl_assert( + _lib.SSL_CTX_set_cipher_list(self._context, cipher_list) == 1 + ) + + @_require_not_used + def set_tls13_ciphersuites(self, ciphersuites: bytes) -> None: + """ + Set the list of TLS 1.3 ciphers to be used in this context. + OpenSSL maintains a separate list of TLS 1.3+ ciphers to + ciphers for TLS 1.2 and lowers. + + See the OpenSSL manual for more information (e.g. + :manpage:`ciphers(1)`). + + :param bytes ciphersuites: An OpenSSL cipher string containing + TLS 1.3+ ciphersuites. + :return: None + + .. versionadded:: 25.2.0 + """ + if not isinstance(ciphersuites, bytes): + raise TypeError("ciphersuites must be a byte string.") + + _openssl_assert( + _lib.SSL_CTX_set_ciphersuites(self._context, ciphersuites) == 1 + ) + + @_require_not_used + def set_client_ca_list( + self, certificate_authorities: Sequence[X509Name] + ) -> None: + """ + Set the list of preferred client certificate signers for this server + context. + + This list of certificate authorities will be sent to the client when + the server requests a client certificate. + + :param certificate_authorities: a sequence of X509Names. + :return: None + + .. versionadded:: 0.10 + """ + name_stack = _lib.sk_X509_NAME_new_null() + _openssl_assert(name_stack != _ffi.NULL) + + try: + for ca_name in certificate_authorities: + if not isinstance(ca_name, X509Name): + raise TypeError( + f"client CAs must be X509Name objects, not " + f"{type(ca_name).__name__} objects" + ) + copy = _lib.X509_NAME_dup(ca_name._name) + _openssl_assert(copy != _ffi.NULL) + push_result = _lib.sk_X509_NAME_push(name_stack, copy) + if not push_result: + _lib.X509_NAME_free(copy) + _raise_current_error() + except Exception: + _lib.sk_X509_NAME_free(name_stack) + raise + + _lib.SSL_CTX_set_client_CA_list(self._context, name_stack) + + @_require_not_used + def add_client_ca( + self, certificate_authority: X509 | x509.Certificate + ) -> None: + """ + Add the CA certificate to the list of preferred signers for this + context. + + The list of certificate authorities will be sent to the client when the + server requests a client certificate. + + :param certificate_authority: certificate authority's X509 certificate. + :return: None + + .. versionadded:: 0.10 + """ + if not isinstance(certificate_authority, X509): + certificate_authority = X509.from_cryptography( + certificate_authority + ) + else: + warnings.warn( + ( + "Passing pyOpenSSL X509 objects is deprecated. You " + "should use a cryptography.x509.Certificate instead." + ), + DeprecationWarning, + stacklevel=2, + ) + + add_result = _lib.SSL_CTX_add_client_CA( + self._context, certificate_authority._x509 + ) + _openssl_assert(add_result == 1) + + @_require_not_used + def set_timeout(self, timeout: int) -> None: + """ + Set the timeout for newly created sessions for this Context object to + *timeout*. The default value is 300 seconds. See the OpenSSL manual + for more information (e.g. :manpage:`SSL_CTX_set_timeout(3)`). + + :param timeout: The timeout in (whole) seconds + :return: The previous session timeout + """ + if not isinstance(timeout, int): + raise TypeError("timeout must be an integer") + + return _lib.SSL_CTX_set_timeout(self._context, timeout) + + def get_timeout(self) -> int: + """ + Retrieve session timeout, as set by :meth:`set_timeout`. The default + is 300 seconds. + + :return: The session timeout + """ + return _lib.SSL_CTX_get_timeout(self._context) + + @_require_not_used + def set_info_callback( + self, callback: Callable[[Connection, int, int], None] + ) -> None: + """ + Set the information callback to *callback*. This function will be + called from time to time during SSL handshakes. + + :param callback: The Python callback to use. This should take three + arguments: a Connection object and two integers. The first integer + specifies where in the SSL handshake the function was called, and + the other the return code from a (possibly failed) internal + function call. + :return: None + """ + + @wraps(callback) + def wrapper(ssl, where, return_code): # type: ignore[no-untyped-def] + callback(Connection._reverse_mapping[ssl], where, return_code) + + self._info_callback = _ffi.callback( + "void (*)(const SSL *, int, int)", wrapper + ) + _lib.SSL_CTX_set_info_callback(self._context, self._info_callback) + + @_requires_keylog + @_require_not_used + def set_keylog_callback( + self, callback: Callable[[Connection, bytes], None] + ) -> None: + """ + Set the TLS key logging callback to *callback*. This function will be + called whenever TLS key material is generated or received, in order + to allow applications to store this keying material for debugging + purposes. + + :param callback: The Python callback to use. This should take two + arguments: a Connection object and a bytestring that contains + the key material in the format used by NSS for its SSLKEYLOGFILE + debugging output. + :return: None + """ + + @wraps(callback) + def wrapper(ssl, line): # type: ignore[no-untyped-def] + line = _ffi.string(line) + callback(Connection._reverse_mapping[ssl], line) + + self._keylog_callback = _ffi.callback( + "void (*)(const SSL *, const char *)", wrapper + ) + _lib.SSL_CTX_set_keylog_callback(self._context, self._keylog_callback) + + def get_app_data(self) -> Any: + """ + Get the application data (supplied via :meth:`set_app_data()`) + + :return: The application data + """ + return self._app_data + + @_require_not_used + def set_app_data(self, data: Any) -> None: + """ + Set the application data (will be returned from get_app_data()) + + :param data: Any Python object + :return: None + """ + self._app_data = data + + def get_cert_store(self) -> X509Store | None: + """ + Get the certificate store for the context. This can be used to add + "trusted" certificates without using the + :meth:`load_verify_locations` method. + + :return: A X509Store object or None if it does not have one. + """ + store = _lib.SSL_CTX_get_cert_store(self._context) + if store == _ffi.NULL: + # TODO: This is untested. + return None + + pystore = X509Store.__new__(X509Store) + pystore._store = store + return pystore + + @_require_not_used + def set_options(self, options: int) -> int: + """ + Add options. Options set before are not cleared! + This method should be used with the :const:`OP_*` constants. + + :param options: The options to add. + :return: The new option bitmask. + """ + if not isinstance(options, int): + raise TypeError("options must be an integer") + + return _lib.SSL_CTX_set_options(self._context, options) + + @_require_not_used + def set_mode(self, mode: int) -> int: + """ + Add modes via bitmask. Modes set before are not cleared! This method + should be used with the :const:`MODE_*` constants. + + :param mode: The mode to add. + :return: The new mode bitmask. + """ + if not isinstance(mode, int): + raise TypeError("mode must be an integer") + + return _lib.SSL_CTX_set_mode(self._context, mode) + + @_require_not_used + def clear_mode(self, mode_to_clear: int) -> int: + """ + Modes previously set cannot be overwritten without being + cleared first. This method should be used to clear existing modes. + """ + return _lib.SSL_CTX_clear_mode(self._context, mode_to_clear) + + @_require_not_used + def set_tlsext_servername_callback( + self, callback: Callable[[Connection], None] + ) -> None: + """ + Specify a callback function to be called when clients specify a server + name. + + :param callback: The callback function. It will be invoked with one + argument, the Connection instance. + + .. versionadded:: 0.13 + """ + + @wraps(callback) + def wrapper(ssl, alert, arg): # type: ignore[no-untyped-def] + callback(Connection._reverse_mapping[ssl]) + return 0 + + self._tlsext_servername_callback = _ffi.callback( + "int (*)(SSL *, int *, void *)", wrapper + ) + _lib.SSL_CTX_set_tlsext_servername_callback( + self._context, self._tlsext_servername_callback + ) + + @_require_not_used + def set_tlsext_use_srtp(self, profiles: bytes) -> None: + """ + Enable support for negotiating SRTP keying material. + + :param bytes profiles: A colon delimited list of protection profile + names, like ``b'SRTP_AES128_CM_SHA1_80:SRTP_AES128_CM_SHA1_32'``. + :return: None + """ + if not isinstance(profiles, bytes): + raise TypeError("profiles must be a byte string.") + + _openssl_assert( + _lib.SSL_CTX_set_tlsext_use_srtp(self._context, profiles) == 0 + ) + + @_require_not_used + def set_alpn_protos(self, protos: list[bytes]) -> None: + """ + Specify the protocols that the client is prepared to speak after the + TLS connection has been negotiated using Application Layer Protocol + Negotiation. + + :param protos: A list of the protocols to be offered to the server. + This list should be a Python list of bytestrings representing the + protocols to offer, e.g. ``[b'http/1.1', b'spdy/2']``. + """ + # Different versions of OpenSSL are inconsistent about how they handle + # empty proto lists (see #1043), so we avoid the problem entirely by + # rejecting them ourselves. + if not protos: + raise ValueError("at least one protocol must be specified") + + # Take the list of protocols and join them together, prefixing them + # with their lengths. + protostr = b"".join( + chain.from_iterable((bytes((len(p),)), p) for p in protos) + ) + + # Build a C string from the list. We don't need to save this off + # because OpenSSL immediately copies the data out. + input_str = _ffi.new("unsigned char[]", protostr) + + # https://www.openssl.org/docs/man1.1.0/man3/SSL_CTX_set_alpn_protos.html: + # SSL_CTX_set_alpn_protos() and SSL_set_alpn_protos() + # return 0 on success, and non-0 on failure. + # WARNING: these functions reverse the return value convention. + _openssl_assert( + _lib.SSL_CTX_set_alpn_protos( + self._context, input_str, len(protostr) + ) + == 0 + ) + + @_require_not_used + def set_alpn_select_callback(self, callback: _ALPNSelectCallback) -> None: + """ + Specify a callback function that will be called on the server when a + client offers protocols using ALPN. + + :param callback: The callback function. It will be invoked with two + arguments: the Connection, and a list of offered protocols as + bytestrings, e.g ``[b'http/1.1', b'spdy/2']``. It can return + one of those bytestrings to indicate the chosen protocol, the + empty bytestring to terminate the TLS connection, or the + :py:obj:`NO_OVERLAPPING_PROTOCOLS` to indicate that no offered + protocol was selected, but that the connection should not be + aborted. + """ + self._alpn_select_helper = _ALPNSelectHelper(callback) + self._alpn_select_callback = self._alpn_select_helper.callback + _lib.SSL_CTX_set_alpn_select_cb( + self._context, self._alpn_select_callback, _ffi.NULL + ) + + def _set_ocsp_callback( + self, + helper: _OCSPClientCallbackHelper | _OCSPServerCallbackHelper, + data: Any | None, + ) -> None: + """ + This internal helper does the common work for + ``set_ocsp_server_callback`` and ``set_ocsp_client_callback``, which is + almost all of it. + """ + self._ocsp_helper = helper + self._ocsp_callback = helper.callback + if data is None: + self._ocsp_data = _ffi.NULL + else: + self._ocsp_data = _ffi.new_handle(data) + + rc = _lib.SSL_CTX_set_tlsext_status_cb( + self._context, self._ocsp_callback + ) + _openssl_assert(rc == 1) + rc = _lib.SSL_CTX_set_tlsext_status_arg(self._context, self._ocsp_data) + _openssl_assert(rc == 1) + + @_require_not_used + def set_ocsp_server_callback( + self, + callback: _OCSPServerCallback[_T], + data: _T | None = None, + ) -> None: + """ + Set a callback to provide OCSP data to be stapled to the TLS handshake + on the server side. + + :param callback: The callback function. It will be invoked with two + arguments: the Connection, and the optional arbitrary data you have + provided. The callback must return a bytestring that contains the + OCSP data to staple to the handshake. If no OCSP data is available + for this connection, return the empty bytestring. + :param data: Some opaque data that will be passed into the callback + function when called. This can be used to avoid needing to do + complex data lookups or to keep track of what context is being + used. This parameter is optional. + """ + helper = _OCSPServerCallbackHelper(callback) + self._set_ocsp_callback(helper, data) + + @_require_not_used + def set_ocsp_client_callback( + self, + callback: _OCSPClientCallback[_T], + data: _T | None = None, + ) -> None: + """ + Set a callback to validate OCSP data stapled to the TLS handshake on + the client side. + + :param callback: The callback function. It will be invoked with three + arguments: the Connection, a bytestring containing the stapled OCSP + assertion, and the optional arbitrary data you have provided. The + callback must return a boolean that indicates the result of + validating the OCSP data: ``True`` if the OCSP data is valid and + the certificate can be trusted, or ``False`` if either the OCSP + data is invalid or the certificate has been revoked. + :param data: Some opaque data that will be passed into the callback + function when called. This can be used to avoid needing to do + complex data lookups or to keep track of what context is being + used. This parameter is optional. + """ + helper = _OCSPClientCallbackHelper(callback) + self._set_ocsp_callback(helper, data) + + @_require_not_used + def set_cookie_generate_callback( + self, callback: _CookieGenerateCallback + ) -> None: + self._cookie_generate_helper = _CookieGenerateCallbackHelper(callback) + _lib.SSL_CTX_set_cookie_generate_cb( + self._context, + self._cookie_generate_helper.callback, + ) + + @_require_not_used + def set_cookie_verify_callback( + self, callback: _CookieVerifyCallback + ) -> None: + self._cookie_verify_helper = _CookieVerifyCallbackHelper(callback) + _lib.SSL_CTX_set_cookie_verify_cb( + self._context, + self._cookie_verify_helper.callback, + ) + + +class Connection: + _reverse_mapping: typing.MutableMapping[Any, Connection] = ( + WeakValueDictionary() + ) + + def __init__( + self, context: Context, socket: socket.socket | None = None + ) -> None: + """ + Create a new Connection object, using the given OpenSSL.SSL.Context + instance and socket. + + :param context: An SSL Context to use for this connection + :param socket: The socket to use for transport layer + """ + if not isinstance(context, Context): + raise TypeError("context must be a Context instance") + + context._used = True + + ssl = _lib.SSL_new(context._context) + self._ssl = _ffi.gc(ssl, _lib.SSL_free) + # We set SSL_MODE_AUTO_RETRY to handle situations where OpenSSL returns + # an SSL_ERROR_WANT_READ when processing a non-application data packet + # even though there is still data on the underlying transport. + # See https://github.com/openssl/openssl/issues/6234 for more details. + _lib.SSL_set_mode(self._ssl, _lib.SSL_MODE_AUTO_RETRY) + self._context = context + self._app_data = None + + # References to strings used for Application Layer Protocol + # Negotiation. These strings get copied at some point but it's well + # after the callback returns, so we have to hang them somewhere to + # avoid them getting freed. + self._alpn_select_callback_args: Any = None + + # Reference the verify_callback of the Context. This ensures that if + # set_verify is called again after the SSL object has been created we + # do not point to a dangling reference + self._verify_helper = context._verify_helper + self._verify_callback = context._verify_callback + + # And likewise for the cookie callbacks + self._cookie_generate_helper = context._cookie_generate_helper + self._cookie_verify_helper = context._cookie_verify_helper + + self._reverse_mapping[self._ssl] = self + + if socket is None: + self._socket = None + # Don't set up any gc for these, SSL_free will take care of them. + self._into_ssl = _lib.BIO_new(_lib.BIO_s_mem()) + _openssl_assert(self._into_ssl != _ffi.NULL) + + self._from_ssl = _lib.BIO_new(_lib.BIO_s_mem()) + _openssl_assert(self._from_ssl != _ffi.NULL) + + _lib.SSL_set_bio(self._ssl, self._into_ssl, self._from_ssl) + else: + self._into_ssl = None + self._from_ssl = None + self._socket = socket + set_result = _lib.SSL_set_fd( + self._ssl, _asFileDescriptor(self._socket) + ) + _openssl_assert(set_result == 1) + + def __getattr__(self, name: str) -> Any: + """ + Look up attributes on the wrapped socket object if they are not found + on the Connection object. + """ + if self._socket is None: + raise AttributeError( + f"'{self.__class__.__name__}' object has no attribute '{name}'" + ) + else: + return getattr(self._socket, name) + + def _raise_ssl_error(self, ssl: Any, result: int) -> None: + if self._context._verify_helper is not None: + self._context._verify_helper.raise_if_problem() + if self._context._alpn_select_helper is not None: + self._context._alpn_select_helper.raise_if_problem() + if self._context._ocsp_helper is not None: + self._context._ocsp_helper.raise_if_problem() + + error = _lib.SSL_get_error(ssl, result) + if error == _lib.SSL_ERROR_WANT_READ: + raise WantReadError() + elif error == _lib.SSL_ERROR_WANT_WRITE: + raise WantWriteError() + elif error == _lib.SSL_ERROR_ZERO_RETURN: + raise ZeroReturnError() + elif error == _lib.SSL_ERROR_WANT_X509_LOOKUP: + # TODO: This is untested. + raise WantX509LookupError() + elif error == _lib.SSL_ERROR_SYSCALL: + if platform == "win32": + errno = _ffi.getwinerror()[0] + else: + errno = _ffi.errno + if _lib.ERR_peek_error() == 0 or errno != 0: + if result < 0 and errno != 0: + raise SysCallError(errno, errorcode.get(errno)) + raise SysCallError(-1, "Unexpected EOF") + else: + # TODO: This is untested, but I think twisted hits it? + _raise_current_error() + elif error == _lib.SSL_ERROR_SSL and _lib.ERR_peek_error() != 0: + # In 3.0.x an unexpected EOF no longer triggers syscall error + # but we want to maintain compatibility so we check here and + # raise syscall if it is an EOF. Since we're not actually sure + # what else could raise SSL_ERROR_SSL we check for the presence + # of the OpenSSL 3 constant SSL_R_UNEXPECTED_EOF_WHILE_READING + # and if it's not present we just raise an error, which matches + # the behavior before we added this elif section + peeked_error = _lib.ERR_peek_error() + reason = _lib.ERR_GET_REASON(peeked_error) + if _lib.Cryptography_HAS_UNEXPECTED_EOF_WHILE_READING: + _openssl_assert( + reason == _lib.SSL_R_UNEXPECTED_EOF_WHILE_READING + ) + _lib.ERR_clear_error() + raise SysCallError(-1, "Unexpected EOF") + else: + _raise_current_error() + elif error == _lib.SSL_ERROR_NONE: + pass + else: + _raise_current_error() + + def get_context(self) -> Context: + """ + Retrieve the :class:`Context` object associated with this + :class:`Connection`. + """ + return self._context + + def set_context(self, context: Context) -> None: + """ + Switch this connection to a new session context. + + :param context: A :class:`Context` instance giving the new session + context to use. + """ + if not isinstance(context, Context): + raise TypeError("context must be a Context instance") + + _lib.SSL_set_SSL_CTX(self._ssl, context._context) + self._context = context + self._context._used = True + + def get_servername(self) -> bytes | None: + """ + Retrieve the servername extension value if provided in the client hello + message, or None if there wasn't one. + + :return: A byte string giving the server name or :data:`None`. + + .. versionadded:: 0.13 + """ + name = _lib.SSL_get_servername( + self._ssl, _lib.TLSEXT_NAMETYPE_host_name + ) + if name == _ffi.NULL: + return None + + return _ffi.string(name) + + def set_verify( + self, mode: int, callback: _VerifyCallback | None = None + ) -> None: + """ + Override the Context object's verification flags for this specific + connection. See :py:meth:`Context.set_verify` for details. + """ + if not isinstance(mode, int): + raise TypeError("mode must be an integer") + + if callback is None: + self._verify_helper = None + self._verify_callback = None + _lib.SSL_set_verify(self._ssl, mode, _ffi.NULL) + else: + if not callable(callback): + raise TypeError("callback must be callable") + + self._verify_helper = _VerifyHelper(callback) + self._verify_callback = self._verify_helper.callback + _lib.SSL_set_verify(self._ssl, mode, self._verify_callback) + + def get_verify_mode(self) -> int: + """ + Retrieve the Connection object's verify mode, as set by + :meth:`set_verify`. + + :return: The verify mode + """ + return _lib.SSL_get_verify_mode(self._ssl) + + def use_certificate(self, cert: X509 | x509.Certificate) -> None: + """ + Load a certificate from a X509 object + + :param cert: The X509 object + :return: None + """ + # Mirrored from Context.use_certificate + if not isinstance(cert, X509): + cert = X509.from_cryptography(cert) + else: + warnings.warn( + ( + "Passing pyOpenSSL X509 objects is deprecated. You " + "should use a cryptography.x509.Certificate instead." + ), + DeprecationWarning, + stacklevel=2, + ) + + use_result = _lib.SSL_use_certificate(self._ssl, cert._x509) + if not use_result: + _raise_current_error() + + def use_privatekey(self, pkey: _PrivateKey | PKey) -> None: + """ + Load a private key from a PKey object + + :param pkey: The PKey object + :return: None + """ + # Mirrored from Context.use_privatekey + if not isinstance(pkey, PKey): + pkey = PKey.from_cryptography_key(pkey) + else: + warnings.warn( + ( + "Passing pyOpenSSL PKey objects is deprecated. You " + "should use a cryptography private key instead." + ), + DeprecationWarning, + stacklevel=2, + ) + + use_result = _lib.SSL_use_PrivateKey(self._ssl, pkey._pkey) + if not use_result: + self._context._raise_passphrase_exception() + + def set_ciphertext_mtu(self, mtu: int) -> None: + """ + For DTLS, set the maximum UDP payload size (*not* including IP/UDP + overhead). + + Note that you might have to set :data:`OP_NO_QUERY_MTU` to prevent + OpenSSL from spontaneously clearing this. + + :param mtu: An integer giving the maximum transmission unit. + + .. versionadded:: 21.1 + """ + _lib.SSL_set_mtu(self._ssl, mtu) + + def get_cleartext_mtu(self) -> int: + """ + For DTLS, get the maximum size of unencrypted data you can pass to + :meth:`write` without exceeding the MTU (as passed to + :meth:`set_ciphertext_mtu`). + + :return: The effective MTU as an integer. + + .. versionadded:: 21.1 + """ + + if not hasattr(_lib, "DTLS_get_data_mtu"): + raise NotImplementedError("requires OpenSSL 1.1.1 or better") + return _lib.DTLS_get_data_mtu(self._ssl) + + def set_tlsext_host_name(self, name: bytes) -> None: + """ + Set the value of the servername extension to send in the client hello. + + :param name: A byte string giving the name. + + .. versionadded:: 0.13 + """ + if not isinstance(name, bytes): + raise TypeError("name must be a byte string") + elif b"\0" in name: + raise TypeError("name must not contain NUL byte") + + # XXX I guess this can fail sometimes? + _lib.SSL_set_tlsext_host_name(self._ssl, name) + + def pending(self) -> int: + """ + Get the number of bytes that can be safely read from the SSL buffer + (**not** the underlying transport buffer). + + :return: The number of bytes available in the receive buffer. + """ + return _lib.SSL_pending(self._ssl) + + def send(self, buf: _Buffer, flags: int = 0) -> int: + """ + Send data on the connection. NOTE: If you get one of the WantRead, + WantWrite or WantX509Lookup exceptions on this, you have to call the + method again with the SAME buffer. + + :param buf: The string, buffer or memoryview to send + :param flags: (optional) Included for compatibility with the socket + API, the value is ignored + :return: The number of bytes written + """ + # Backward compatibility + buf = _text_to_bytes_and_warn("buf", buf) + + with _ffi.from_buffer(buf) as data: + # check len(buf) instead of len(data) for testability + if len(buf) > 2147483647: + raise ValueError( + "Cannot send more than 2**31-1 bytes at once." + ) + + result = _lib.SSL_write(self._ssl, data, len(data)) + self._raise_ssl_error(self._ssl, result) + + return result + + write = send + + def sendall(self, buf: _Buffer, flags: int = 0) -> int: + """ + Send "all" data on the connection. This calls send() repeatedly until + all data is sent. If an error occurs, it's impossible to tell how much + data has been sent. + + :param buf: The string, buffer or memoryview to send + :param flags: (optional) Included for compatibility with the socket + API, the value is ignored + :return: The number of bytes written + """ + buf = _text_to_bytes_and_warn("buf", buf) + + with _ffi.from_buffer(buf) as data: + left_to_send = len(buf) + total_sent = 0 + + while left_to_send: + # SSL_write's num arg is an int, + # so we cannot send more than 2**31-1 bytes at once. + result = _lib.SSL_write( + self._ssl, data + total_sent, min(left_to_send, 2147483647) + ) + self._raise_ssl_error(self._ssl, result) + total_sent += result + left_to_send -= result + + return total_sent + + def recv(self, bufsiz: int, flags: int | None = None) -> bytes: + """ + Receive data on the connection. + + :param bufsiz: The maximum number of bytes to read + :param flags: (optional) The only supported flag is ``MSG_PEEK``, + all other flags are ignored. + :return: The string read from the Connection + """ + buf = _no_zero_allocator("char[]", bufsiz) + if flags is not None and flags & socket.MSG_PEEK: + result = _lib.SSL_peek(self._ssl, buf, bufsiz) + else: + result = _lib.SSL_read(self._ssl, buf, bufsiz) + self._raise_ssl_error(self._ssl, result) + return _ffi.buffer(buf, result)[:] + + read = recv + + def recv_into( + self, + buffer: Any, # collections.abc.Buffer once we use Python 3.12+ + nbytes: int | None = None, + flags: int | None = None, + ) -> int: + """ + Receive data on the connection and copy it directly into the provided + buffer, rather than creating a new string. + + :param buffer: The buffer to copy into. + :param nbytes: (optional) The maximum number of bytes to read into the + buffer. If not present, defaults to the size of the buffer. If + larger than the size of the buffer, is reduced to the size of the + buffer. + :param flags: (optional) The only supported flag is ``MSG_PEEK``, + all other flags are ignored. + :return: The number of bytes read into the buffer. + """ + if nbytes is None: + nbytes = len(buffer) + else: + nbytes = min(nbytes, len(buffer)) + + # We need to create a temporary buffer. This is annoying, it would be + # better if we could pass memoryviews straight into the SSL_read call, + # but right now we can't. Revisit this if CFFI gets that ability. + buf = _no_zero_allocator("char[]", nbytes) + if flags is not None and flags & socket.MSG_PEEK: + result = _lib.SSL_peek(self._ssl, buf, nbytes) + else: + result = _lib.SSL_read(self._ssl, buf, nbytes) + self._raise_ssl_error(self._ssl, result) + + # This strange line is all to avoid a memory copy. The buffer protocol + # should allow us to assign a CFFI buffer to the LHS of this line, but + # on CPython 3.3+ that segfaults. As a workaround, we can temporarily + # wrap it in a memoryview. + buffer[:result] = memoryview(_ffi.buffer(buf, result)) + + return result + + def _handle_bio_errors(self, bio: Any, result: int) -> typing.NoReturn: + if _lib.BIO_should_retry(bio): + if _lib.BIO_should_read(bio): + raise WantReadError() + elif _lib.BIO_should_write(bio): + # TODO: This is untested. + raise WantWriteError() + elif _lib.BIO_should_io_special(bio): + # TODO: This is untested. I think io_special means the socket + # BIO has a not-yet connected socket. + raise ValueError("BIO_should_io_special") + else: + # TODO: This is untested. + raise ValueError("unknown bio failure") + else: + # TODO: This is untested. + _raise_current_error() + + def bio_read(self, bufsiz: int) -> bytes: + """ + If the Connection was created with a memory BIO, this method can be + used to read bytes from the write end of that memory BIO. Many + Connection methods will add bytes which must be read in this manner or + the buffer will eventually fill up and the Connection will be able to + take no further actions. + + :param bufsiz: The maximum number of bytes to read + :return: The string read. + """ + if self._from_ssl is None: + raise TypeError("Connection sock was not None") + + if not isinstance(bufsiz, int): + raise TypeError("bufsiz must be an integer") + + buf = _no_zero_allocator("char[]", bufsiz) + result = _lib.BIO_read(self._from_ssl, buf, bufsiz) + if result <= 0: + self._handle_bio_errors(self._from_ssl, result) + + return _ffi.buffer(buf, result)[:] + + def bio_write(self, buf: _Buffer) -> int: + """ + If the Connection was created with a memory BIO, this method can be + used to add bytes to the read end of that memory BIO. The Connection + can then read the bytes (for example, in response to a call to + :meth:`recv`). + + :param buf: The string to put into the memory BIO. + :return: The number of bytes written + """ + buf = _text_to_bytes_and_warn("buf", buf) + + if self._into_ssl is None: + raise TypeError("Connection sock was not None") + + with _ffi.from_buffer(buf) as data: + result = _lib.BIO_write(self._into_ssl, data, len(data)) + if result <= 0: + self._handle_bio_errors(self._into_ssl, result) + return result + + def renegotiate(self) -> bool: + """ + Renegotiate the session. + + :return: True if the renegotiation can be started, False otherwise + """ + if not self.renegotiate_pending(): + _openssl_assert(_lib.SSL_renegotiate(self._ssl) == 1) + return True + return False + + def do_handshake(self) -> None: + """ + Perform an SSL handshake (usually called after :meth:`renegotiate` or + one of :meth:`set_accept_state` or :meth:`set_connect_state`). This can + raise the same exceptions as :meth:`send` and :meth:`recv`. + + :return: None. + """ + result = _lib.SSL_do_handshake(self._ssl) + self._raise_ssl_error(self._ssl, result) + + def renegotiate_pending(self) -> bool: + """ + Check if there's a renegotiation in progress, it will return False once + a renegotiation is finished. + + :return: Whether there's a renegotiation in progress + """ + return _lib.SSL_renegotiate_pending(self._ssl) == 1 + + def total_renegotiations(self) -> int: + """ + Find out the total number of renegotiations. + + :return: The number of renegotiations. + """ + return _lib.SSL_total_renegotiations(self._ssl) + + def connect(self, addr: Any) -> None: + """ + Call the :meth:`connect` method of the underlying socket and set up SSL + on the socket, using the :class:`Context` object supplied to this + :class:`Connection` object at creation. + + :param addr: A remote address + :return: What the socket's connect method returns + """ + _lib.SSL_set_connect_state(self._ssl) + return self._socket.connect(addr) # type: ignore[return-value, union-attr] + + def connect_ex(self, addr: Any) -> int: + """ + Call the :meth:`connect_ex` method of the underlying socket and set up + SSL on the socket, using the Context object supplied to this Connection + object at creation. Note that if the :meth:`connect_ex` method of the + socket doesn't return 0, SSL won't be initialized. + + :param addr: A remove address + :return: What the socket's connect_ex method returns + """ + connect_ex = self._socket.connect_ex # type: ignore[union-attr] + self.set_connect_state() + return connect_ex(addr) + + def accept(self) -> tuple[Connection, Any]: + """ + Call the :meth:`accept` method of the underlying socket and set up SSL + on the returned socket, using the Context object supplied to this + :class:`Connection` object at creation. + + :return: A *(conn, addr)* pair where *conn* is the new + :class:`Connection` object created, and *address* is as returned by + the socket's :meth:`accept`. + """ + client, addr = self._socket.accept() # type: ignore[union-attr] + conn = Connection(self._context, client) + conn.set_accept_state() + return (conn, addr) + + def DTLSv1_listen(self) -> None: + """ + Call the OpenSSL function DTLSv1_listen on this connection. See the + OpenSSL manual for more details. + + :return: None + """ + # Possible future extension: return the BIO_ADDR in some form. + bio_addr = _lib.BIO_ADDR_new() + try: + result = _lib.DTLSv1_listen(self._ssl, bio_addr) + finally: + _lib.BIO_ADDR_free(bio_addr) + # DTLSv1_listen is weird. A zero return value means 'didn't find a + # ClientHello with valid cookie, but keep trying'. So basically + # WantReadError. But it doesn't work correctly with _raise_ssl_error. + # So we raise it manually instead. + if self._cookie_generate_helper is not None: + self._cookie_generate_helper.raise_if_problem() + if self._cookie_verify_helper is not None: + self._cookie_verify_helper.raise_if_problem() + if result == 0: + raise WantReadError() + if result < 0: + self._raise_ssl_error(self._ssl, result) + + def DTLSv1_get_timeout(self) -> int | None: + """ + Determine when the DTLS SSL object next needs to perform internal + processing due to the passage of time. + + When the returned number of seconds have passed, the + :meth:`DTLSv1_handle_timeout` method needs to be called. + + :return: The time left in seconds before the next timeout or `None` + if no timeout is currently active. + """ + ptv_sec = _ffi.new("time_t *") + ptv_usec = _ffi.new("long *") + if _lib.Cryptography_DTLSv1_get_timeout(self._ssl, ptv_sec, ptv_usec): + return ptv_sec[0] + (ptv_usec[0] / 1000000) + else: + return None + + def DTLSv1_handle_timeout(self) -> bool: + """ + Handles any timeout events which have become pending on a DTLS SSL + object. + + :return: `True` if there was a pending timeout, `False` otherwise. + """ + result = _lib.DTLSv1_handle_timeout(self._ssl) + if result < 0: + self._raise_ssl_error(self._ssl, result) + assert False, "unreachable" + else: + return bool(result) + + def bio_shutdown(self) -> None: + """ + If the Connection was created with a memory BIO, this method can be + used to indicate that *end of file* has been reached on the read end of + that memory BIO. + + :return: None + """ + if self._from_ssl is None: + raise TypeError("Connection sock was not None") + + _lib.BIO_set_mem_eof_return(self._into_ssl, 0) + + def shutdown(self) -> bool: + """ + Send the shutdown message to the Connection. + + :return: True if the shutdown completed successfully (i.e. both sides + have sent closure alerts), False otherwise (in which case you + call :meth:`recv` or :meth:`send` when the connection becomes + readable/writeable). + """ + result = _lib.SSL_shutdown(self._ssl) + if result < 0: + self._raise_ssl_error(self._ssl, result) + assert False, "unreachable" + elif result > 0: + return True + else: + return False + + def get_cipher_list(self) -> list[str]: + """ + Retrieve the list of ciphers used by the Connection object. + + :return: A list of native cipher strings. + """ + ciphers = [] + for i in count(): + result = _lib.SSL_get_cipher_list(self._ssl, i) + if result == _ffi.NULL: + break + ciphers.append(_ffi.string(result).decode("utf-8")) + return ciphers + + def get_client_ca_list(self) -> list[X509Name]: + """ + Get CAs whose certificates are suggested for client authentication. + + :return: If this is a server connection, the list of certificate + authorities that will be sent or has been sent to the client, as + controlled by this :class:`Connection`'s :class:`Context`. + + If this is a client connection, the list will be empty until the + connection with the server is established. + + .. versionadded:: 0.10 + """ + ca_names = _lib.SSL_get_client_CA_list(self._ssl) + if ca_names == _ffi.NULL: + # TODO: This is untested. + return [] + + result = [] + for i in range(_lib.sk_X509_NAME_num(ca_names)): + name = _lib.sk_X509_NAME_value(ca_names, i) + copy = _lib.X509_NAME_dup(name) + _openssl_assert(copy != _ffi.NULL) + + pyname = X509Name.__new__(X509Name) + pyname._name = _ffi.gc(copy, _lib.X509_NAME_free) + result.append(pyname) + return result + + def makefile(self, *args: Any, **kwargs: Any) -> typing.NoReturn: + """ + The makefile() method is not implemented, since there is no dup + semantics for SSL connections + + :raise: NotImplementedError + """ + raise NotImplementedError( + "Cannot make file object of OpenSSL.SSL.Connection" + ) + + def get_app_data(self) -> Any: + """ + Retrieve application data as set by :meth:`set_app_data`. + + :return: The application data + """ + return self._app_data + + def set_app_data(self, data: Any) -> None: + """ + Set application data + + :param data: The application data + :return: None + """ + self._app_data = data + + def get_shutdown(self) -> int: + """ + Get the shutdown state of the Connection. + + :return: The shutdown state, a bitvector of SENT_SHUTDOWN, + RECEIVED_SHUTDOWN. + """ + return _lib.SSL_get_shutdown(self._ssl) + + def set_shutdown(self, state: int) -> None: + """ + Set the shutdown state of the Connection. + + :param state: bitvector of SENT_SHUTDOWN, RECEIVED_SHUTDOWN. + :return: None + """ + if not isinstance(state, int): + raise TypeError("state must be an integer") + + _lib.SSL_set_shutdown(self._ssl, state) + + def get_state_string(self) -> bytes: + """ + Retrieve a verbose string detailing the state of the Connection. + + :return: A string representing the state + """ + return _ffi.string(_lib.SSL_state_string_long(self._ssl)) + + def server_random(self) -> bytes | None: + """ + Retrieve the random value used with the server hello message. + + :return: A string representing the state + """ + session = _lib.SSL_get_session(self._ssl) + if session == _ffi.NULL: + return None + length = _lib.SSL_get_server_random(self._ssl, _ffi.NULL, 0) + _openssl_assert(length > 0) + outp = _no_zero_allocator("unsigned char[]", length) + _lib.SSL_get_server_random(self._ssl, outp, length) + return _ffi.buffer(outp, length)[:] + + def client_random(self) -> bytes | None: + """ + Retrieve the random value used with the client hello message. + + :return: A string representing the state + """ + session = _lib.SSL_get_session(self._ssl) + if session == _ffi.NULL: + return None + + length = _lib.SSL_get_client_random(self._ssl, _ffi.NULL, 0) + _openssl_assert(length > 0) + outp = _no_zero_allocator("unsigned char[]", length) + _lib.SSL_get_client_random(self._ssl, outp, length) + return _ffi.buffer(outp, length)[:] + + def master_key(self) -> bytes | None: + """ + Retrieve the value of the master key for this session. + + :return: A string representing the state + """ + session = _lib.SSL_get_session(self._ssl) + if session == _ffi.NULL: + return None + + length = _lib.SSL_SESSION_get_master_key(session, _ffi.NULL, 0) + _openssl_assert(length > 0) + outp = _no_zero_allocator("unsigned char[]", length) + _lib.SSL_SESSION_get_master_key(session, outp, length) + return _ffi.buffer(outp, length)[:] + + def export_keying_material( + self, label: bytes, olen: int, context: bytes | None = None + ) -> bytes: + """ + Obtain keying material for application use. + + :param: label - a disambiguating label string as described in RFC 5705 + :param: olen - the length of the exported key material in bytes + :param: context - a per-association context value + :return: the exported key material bytes or None + """ + outp = _no_zero_allocator("unsigned char[]", olen) + context_buf = _ffi.NULL + context_len = 0 + use_context = 0 + if context is not None: + context_buf = context + context_len = len(context) + use_context = 1 + success = _lib.SSL_export_keying_material( + self._ssl, + outp, + olen, + label, + len(label), + context_buf, + context_len, + use_context, + ) + _openssl_assert(success == 1) + return _ffi.buffer(outp, olen)[:] + + def sock_shutdown(self, *args: Any, **kwargs: Any) -> None: + """ + Call the :meth:`shutdown` method of the underlying socket. + See :manpage:`shutdown(2)`. + + :return: What the socket's shutdown() method returns + """ + return self._socket.shutdown(*args, **kwargs) # type: ignore[return-value, union-attr] + + @typing.overload + def get_certificate( + self, *, as_cryptography: typing.Literal[True] + ) -> x509.Certificate | None: + pass + + @typing.overload + def get_certificate( + self, *, as_cryptography: typing.Literal[False] = False + ) -> X509 | None: + pass + + def get_certificate( + self, + *, + as_cryptography: typing.Literal[True] | typing.Literal[False] = False, + ) -> X509 | x509.Certificate | None: + """ + Retrieve the local certificate (if any) + + :param bool as_cryptography: Controls whether a + ``cryptography.x509.Certificate`` or an ``OpenSSL.crypto.X509`` + object should be returned. + + :return: The local certificate + """ + cert = _lib.SSL_get_certificate(self._ssl) + if cert != _ffi.NULL: + _lib.X509_up_ref(cert) + pycert = X509._from_raw_x509_ptr(cert) + if as_cryptography: + return pycert.to_cryptography() + return pycert + return None + + @typing.overload + def get_peer_certificate( + self, *, as_cryptography: typing.Literal[True] + ) -> x509.Certificate | None: + pass + + @typing.overload + def get_peer_certificate( + self, *, as_cryptography: typing.Literal[False] = False + ) -> X509 | None: + pass + + def get_peer_certificate( + self, + *, + as_cryptography: typing.Literal[True] | typing.Literal[False] = False, + ) -> X509 | x509.Certificate | None: + """ + Retrieve the other side's certificate (if any) + + :param bool as_cryptography: Controls whether a + ``cryptography.x509.Certificate`` or an ``OpenSSL.crypto.X509`` + object should be returned. + + :return: The peer's certificate + """ + cert = _lib.SSL_get_peer_certificate(self._ssl) + if cert != _ffi.NULL: + pycert = X509._from_raw_x509_ptr(cert) + if as_cryptography: + return pycert.to_cryptography() + return pycert + return None + + @staticmethod + def _cert_stack_to_list(cert_stack: Any) -> list[X509]: + """ + Internal helper to convert a STACK_OF(X509) to a list of X509 + instances. + """ + result = [] + for i in range(_lib.sk_X509_num(cert_stack)): + cert = _lib.sk_X509_value(cert_stack, i) + _openssl_assert(cert != _ffi.NULL) + res = _lib.X509_up_ref(cert) + _openssl_assert(res >= 1) + pycert = X509._from_raw_x509_ptr(cert) + result.append(pycert) + return result + + @staticmethod + def _cert_stack_to_cryptography_list( + cert_stack: Any, + ) -> list[x509.Certificate]: + """ + Internal helper to convert a STACK_OF(X509) to a list of X509 + instances. + """ + result = [] + for i in range(_lib.sk_X509_num(cert_stack)): + cert = _lib.sk_X509_value(cert_stack, i) + _openssl_assert(cert != _ffi.NULL) + res = _lib.X509_up_ref(cert) + _openssl_assert(res >= 1) + pycert = X509._from_raw_x509_ptr(cert) + result.append(pycert.to_cryptography()) + return result + + @typing.overload + def get_peer_cert_chain( + self, *, as_cryptography: typing.Literal[True] + ) -> list[x509.Certificate] | None: + pass + + @typing.overload + def get_peer_cert_chain( + self, *, as_cryptography: typing.Literal[False] = False + ) -> list[X509] | None: + pass + + def get_peer_cert_chain( + self, + *, + as_cryptography: typing.Literal[True] | typing.Literal[False] = False, + ) -> list[X509] | list[x509.Certificate] | None: + """ + Retrieve the other side's certificate (if any) + + :param bool as_cryptography: Controls whether a list of + ``cryptography.x509.Certificate`` or ``OpenSSL.crypto.X509`` + object should be returned. + + :return: A list of X509 instances giving the peer's certificate chain, + or None if it does not have one. + """ + cert_stack = _lib.SSL_get_peer_cert_chain(self._ssl) + if cert_stack == _ffi.NULL: + return None + + if as_cryptography: + return self._cert_stack_to_cryptography_list(cert_stack) + return self._cert_stack_to_list(cert_stack) + + @typing.overload + def get_verified_chain( + self, *, as_cryptography: typing.Literal[True] + ) -> list[x509.Certificate] | None: + pass + + @typing.overload + def get_verified_chain( + self, *, as_cryptography: typing.Literal[False] = False + ) -> list[X509] | None: + pass + + def get_verified_chain( + self, + *, + as_cryptography: typing.Literal[True] | typing.Literal[False] = False, + ) -> list[X509] | list[x509.Certificate] | None: + """ + Retrieve the verified certificate chain of the peer including the + peer's end entity certificate. It must be called after a session has + been successfully established. If peer verification was not successful + the chain may be incomplete, invalid, or None. + + :param bool as_cryptography: Controls whether a list of + ``cryptography.x509.Certificate`` or ``OpenSSL.crypto.X509`` + object should be returned. + + :return: A list of X509 instances giving the peer's verified + certificate chain, or None if it does not have one. + + .. versionadded:: 20.0 + """ + # OpenSSL 1.1+ + cert_stack = _lib.SSL_get0_verified_chain(self._ssl) + if cert_stack == _ffi.NULL: + return None + + if as_cryptography: + return self._cert_stack_to_cryptography_list(cert_stack) + return self._cert_stack_to_list(cert_stack) + + def want_read(self) -> bool: + """ + Checks if more data has to be read from the transport layer to complete + an operation. + + :return: True iff more data has to be read + """ + return _lib.SSL_want_read(self._ssl) + + def want_write(self) -> bool: + """ + Checks if there is data to write to the transport layer to complete an + operation. + + :return: True iff there is data to write + """ + return _lib.SSL_want_write(self._ssl) + + def set_accept_state(self) -> None: + """ + Set the connection to work in server mode. The handshake will be + handled automatically by read/write. + + :return: None + """ + _lib.SSL_set_accept_state(self._ssl) + + def set_connect_state(self) -> None: + """ + Set the connection to work in client mode. The handshake will be + handled automatically by read/write. + + :return: None + """ + _lib.SSL_set_connect_state(self._ssl) + + def get_session(self) -> Session | None: + """ + Returns the Session currently used. + + :return: An instance of :class:`OpenSSL.SSL.Session` or + :obj:`None` if no session exists. + + .. versionadded:: 0.14 + """ + session = _lib.SSL_get1_session(self._ssl) + if session == _ffi.NULL: + return None + + pysession = Session.__new__(Session) + pysession._session = _ffi.gc(session, _lib.SSL_SESSION_free) + return pysession + + def set_session(self, session: Session) -> None: + """ + Set the session to be used when the TLS/SSL connection is established. + + :param session: A Session instance representing the session to use. + :returns: None + + .. versionadded:: 0.14 + """ + if not isinstance(session, Session): + raise TypeError("session must be a Session instance") + + result = _lib.SSL_set_session(self._ssl, session._session) + _openssl_assert(result == 1) + + def _get_finished_message( + self, function: Callable[[Any, Any, int], int] + ) -> bytes | None: + """ + Helper to implement :meth:`get_finished` and + :meth:`get_peer_finished`. + + :param function: Either :data:`SSL_get_finished`: or + :data:`SSL_get_peer_finished`. + + :return: :data:`None` if the desired message has not yet been + received, otherwise the contents of the message. + """ + # The OpenSSL documentation says nothing about what might happen if the + # count argument given is zero. Specifically, it doesn't say whether + # the output buffer may be NULL in that case or not. Inspection of the + # implementation reveals that it calls memcpy() unconditionally. + # Section 7.1.4, paragraph 1 of the C standard suggests that + # memcpy(NULL, source, 0) is not guaranteed to produce defined (let + # alone desirable) behavior (though it probably does on just about + # every implementation...) + # + # Allocate a tiny buffer to pass in (instead of just passing NULL as + # one might expect) for the initial call so as to be safe against this + # potentially undefined behavior. + empty = _ffi.new("char[]", 0) + size = function(self._ssl, empty, 0) + if size == 0: + # No Finished message so far. + return None + + buf = _no_zero_allocator("char[]", size) + function(self._ssl, buf, size) + return _ffi.buffer(buf, size)[:] + + def get_finished(self) -> bytes | None: + """ + Obtain the latest TLS Finished message that we sent. + + :return: The contents of the message or :obj:`None` if the TLS + handshake has not yet completed. + + .. versionadded:: 0.15 + """ + return self._get_finished_message(_lib.SSL_get_finished) + + def get_peer_finished(self) -> bytes | None: + """ + Obtain the latest TLS Finished message that we received from the peer. + + :return: The contents of the message or :obj:`None` if the TLS + handshake has not yet completed. + + .. versionadded:: 0.15 + """ + return self._get_finished_message(_lib.SSL_get_peer_finished) + + def get_cipher_name(self) -> str | None: + """ + Obtain the name of the currently used cipher. + + :returns: The name of the currently used cipher or :obj:`None` + if no connection has been established. + + .. versionadded:: 0.15 + """ + cipher = _lib.SSL_get_current_cipher(self._ssl) + if cipher == _ffi.NULL: + return None + else: + name = _ffi.string(_lib.SSL_CIPHER_get_name(cipher)) + return name.decode("utf-8") + + def get_cipher_bits(self) -> int | None: + """ + Obtain the number of secret bits of the currently used cipher. + + :returns: The number of secret bits of the currently used cipher + or :obj:`None` if no connection has been established. + + .. versionadded:: 0.15 + """ + cipher = _lib.SSL_get_current_cipher(self._ssl) + if cipher == _ffi.NULL: + return None + else: + return _lib.SSL_CIPHER_get_bits(cipher, _ffi.NULL) + + def get_cipher_version(self) -> str | None: + """ + Obtain the protocol version of the currently used cipher. + + :returns: The protocol name of the currently used cipher + or :obj:`None` if no connection has been established. + + .. versionadded:: 0.15 + """ + cipher = _lib.SSL_get_current_cipher(self._ssl) + if cipher == _ffi.NULL: + return None + else: + version = _ffi.string(_lib.SSL_CIPHER_get_version(cipher)) + return version.decode("utf-8") + + def get_protocol_version_name(self) -> str: + """ + Retrieve the protocol version of the current connection. + + :returns: The TLS version of the current connection, for example + the value for TLS 1.2 would be ``TLSv1.2``or ``Unknown`` + for connections that were not successfully established. + """ + version = _ffi.string(_lib.SSL_get_version(self._ssl)) + return version.decode("utf-8") + + def get_protocol_version(self) -> int: + """ + Retrieve the SSL or TLS protocol version of the current connection. + + :returns: The TLS version of the current connection. For example, + it will return ``0x769`` for connections made over TLS version 1. + """ + version = _lib.SSL_version(self._ssl) + return version + + def set_alpn_protos(self, protos: list[bytes]) -> None: + """ + Specify the client's ALPN protocol list. + + These protocols are offered to the server during protocol negotiation. + + :param protos: A list of the protocols to be offered to the server. + This list should be a Python list of bytestrings representing the + protocols to offer, e.g. ``[b'http/1.1', b'spdy/2']``. + """ + # Different versions of OpenSSL are inconsistent about how they handle + # empty proto lists (see #1043), so we avoid the problem entirely by + # rejecting them ourselves. + if not protos: + raise ValueError("at least one protocol must be specified") + + # Take the list of protocols and join them together, prefixing them + # with their lengths. + protostr = b"".join( + chain.from_iterable((bytes((len(p),)), p) for p in protos) + ) + + # Build a C string from the list. We don't need to save this off + # because OpenSSL immediately copies the data out. + input_str = _ffi.new("unsigned char[]", protostr) + + # https://www.openssl.org/docs/man1.1.0/man3/SSL_CTX_set_alpn_protos.html: + # SSL_CTX_set_alpn_protos() and SSL_set_alpn_protos() + # return 0 on success, and non-0 on failure. + # WARNING: these functions reverse the return value convention. + _openssl_assert( + _lib.SSL_set_alpn_protos(self._ssl, input_str, len(protostr)) == 0 + ) + + def get_alpn_proto_negotiated(self) -> bytes: + """ + Get the protocol that was negotiated by ALPN. + + :returns: A bytestring of the protocol name. If no protocol has been + negotiated yet, returns an empty bytestring. + """ + data = _ffi.new("unsigned char **") + data_len = _ffi.new("unsigned int *") + + _lib.SSL_get0_alpn_selected(self._ssl, data, data_len) + + if not data_len: + return b"" + + return _ffi.buffer(data[0], data_len[0])[:] + + def get_selected_srtp_profile(self) -> bytes: + """ + Get the SRTP protocol which was negotiated. + + :returns: A bytestring of the SRTP profile name. If no profile has been + negotiated yet, returns an empty bytestring. + """ + profile = _lib.SSL_get_selected_srtp_profile(self._ssl) + if not profile: + return b"" + + return _ffi.string(profile.name) + + def request_ocsp(self) -> None: + """ + Called to request that the server sends stapled OCSP data, if + available. If this is not called on the client side then the server + will not send OCSP data. Should be used in conjunction with + :meth:`Context.set_ocsp_client_callback`. + """ + rc = _lib.SSL_set_tlsext_status_type( + self._ssl, _lib.TLSEXT_STATUSTYPE_ocsp + ) + _openssl_assert(rc == 1) + + def set_info_callback( + self, callback: Callable[[Connection, int, int], None] + ) -> None: + """ + Set the information callback to *callback*. This function will be + called from time to time during SSL handshakes. + + :param callback: The Python callback to use. This should take three + arguments: a Connection object and two integers. The first integer + specifies where in the SSL handshake the function was called, and + the other the return code from a (possibly failed) internal + function call. + :return: None + """ + + @wraps(callback) + def wrapper(ssl, where, return_code): # type: ignore[no-untyped-def] + callback(Connection._reverse_mapping[ssl], where, return_code) + + self._info_callback = _ffi.callback( + "void (*)(const SSL *, int, int)", wrapper + ) + _lib.SSL_set_info_callback(self._ssl, self._info_callback) diff --git a/venv/Lib/site-packages/OpenSSL/__init__.py b/venv/Lib/site-packages/OpenSSL/__init__.py new file mode 100644 index 0000000..7b077cf --- /dev/null +++ b/venv/Lib/site-packages/OpenSSL/__init__.py @@ -0,0 +1,31 @@ +# Copyright (C) AB Strakt +# See LICENSE for details. + +""" +pyOpenSSL - A simple wrapper around the OpenSSL library +""" + +from OpenSSL import SSL, crypto +from OpenSSL.version import ( + __author__, + __copyright__, + __email__, + __license__, + __summary__, + __title__, + __uri__, + __version__, +) + +__all__ = [ + "SSL", + "__author__", + "__copyright__", + "__email__", + "__license__", + "__summary__", + "__title__", + "__uri__", + "__version__", + "crypto", +] diff --git a/venv/Lib/site-packages/OpenSSL/__pycache__/SSL.cpython-312.pyc b/venv/Lib/site-packages/OpenSSL/__pycache__/SSL.cpython-312.pyc new file mode 100644 index 0000000..8295c5d Binary files /dev/null and b/venv/Lib/site-packages/OpenSSL/__pycache__/SSL.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/OpenSSL/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/OpenSSL/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000..94edd2b Binary files /dev/null and b/venv/Lib/site-packages/OpenSSL/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/OpenSSL/__pycache__/_util.cpython-312.pyc b/venv/Lib/site-packages/OpenSSL/__pycache__/_util.cpython-312.pyc new file mode 100644 index 0000000..780c1e0 Binary files /dev/null and b/venv/Lib/site-packages/OpenSSL/__pycache__/_util.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/OpenSSL/__pycache__/crypto.cpython-312.pyc b/venv/Lib/site-packages/OpenSSL/__pycache__/crypto.cpython-312.pyc new file mode 100644 index 0000000..685f8b9 Binary files /dev/null and b/venv/Lib/site-packages/OpenSSL/__pycache__/crypto.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/OpenSSL/__pycache__/debug.cpython-312.pyc b/venv/Lib/site-packages/OpenSSL/__pycache__/debug.cpython-312.pyc new file mode 100644 index 0000000..debdb08 Binary files /dev/null and b/venv/Lib/site-packages/OpenSSL/__pycache__/debug.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/OpenSSL/__pycache__/rand.cpython-312.pyc b/venv/Lib/site-packages/OpenSSL/__pycache__/rand.cpython-312.pyc new file mode 100644 index 0000000..026708f Binary files /dev/null and b/venv/Lib/site-packages/OpenSSL/__pycache__/rand.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/OpenSSL/__pycache__/version.cpython-312.pyc b/venv/Lib/site-packages/OpenSSL/__pycache__/version.cpython-312.pyc new file mode 100644 index 0000000..4528b3c Binary files /dev/null and b/venv/Lib/site-packages/OpenSSL/__pycache__/version.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/OpenSSL/_util.py b/venv/Lib/site-packages/OpenSSL/_util.py new file mode 100644 index 0000000..41a6452 --- /dev/null +++ b/venv/Lib/site-packages/OpenSSL/_util.py @@ -0,0 +1,129 @@ +from __future__ import annotations + +import os +import sys +import warnings +from typing import Any, Callable, NoReturn, Union + +from cryptography.hazmat.bindings.openssl.binding import Binding + +if sys.version_info >= (3, 9): + StrOrBytesPath = Union[str, bytes, os.PathLike[str], os.PathLike[bytes]] +else: + StrOrBytesPath = Union[str, bytes, os.PathLike] + +binding = Binding() +ffi = binding.ffi +lib: Any = binding.lib + + +# This is a special CFFI allocator that does not bother to zero its memory +# after allocation. This has vastly better performance on large allocations and +# so should be used whenever we don't need the memory zeroed out. +no_zero_allocator = ffi.new_allocator(should_clear_after_alloc=False) + + +def text(charp: Any) -> str: + """ + Get a native string type representing of the given CFFI ``char*`` object. + + :param charp: A C-style string represented using CFFI. + + :return: :class:`str` + """ + if not charp: + return "" + return ffi.string(charp).decode("utf-8") + + +def exception_from_error_queue(exception_type: type[Exception]) -> NoReturn: + """ + Convert an OpenSSL library failure into a Python exception. + + When a call to the native OpenSSL library fails, this is usually signalled + by the return value, and an error code is stored in an error queue + associated with the current thread. The err library provides functions to + obtain these error codes and textual error messages. + """ + errors = [] + + while True: + error = lib.ERR_get_error() + if error == 0: + break + errors.append( + ( + text(lib.ERR_lib_error_string(error)), + text(lib.ERR_func_error_string(error)), + text(lib.ERR_reason_error_string(error)), + ) + ) + + raise exception_type(errors) + + +def make_assert(error: type[Exception]) -> Callable[[bool], Any]: + """ + Create an assert function that uses :func:`exception_from_error_queue` to + raise an exception wrapped by *error*. + """ + + def openssl_assert(ok: bool) -> None: + """ + If *ok* is not True, retrieve the error from OpenSSL and raise it. + """ + if ok is not True: + exception_from_error_queue(error) + + return openssl_assert + + +def path_bytes(s: StrOrBytesPath) -> bytes: + """ + Convert a Python path to a :py:class:`bytes` for the path which can be + passed into an OpenSSL API accepting a filename. + + :param s: A path (valid for os.fspath). + + :return: An instance of :py:class:`bytes`. + """ + b = os.fspath(s) + + if isinstance(b, str): + return b.encode(sys.getfilesystemencoding()) + else: + return b + + +def byte_string(s: str) -> bytes: + return s.encode("charmap") + + +# A marker object to observe whether some optional arguments are passed any +# value or not. +UNSPECIFIED = object() + +_TEXT_WARNING = "str for {0} is no longer accepted, use bytes" + + +def text_to_bytes_and_warn(label: str, obj: Any) -> Any: + """ + If ``obj`` is text, emit a warning that it should be bytes instead and try + to convert it to bytes automatically. + + :param str label: The name of the parameter from which ``obj`` was taken + (so a developer can easily find the source of the problem and correct + it). + + :return: If ``obj`` is the text string type, a ``bytes`` object giving the + UTF-8 encoding of that text is returned. Otherwise, ``obj`` itself is + returned. + """ + if isinstance(obj, str): + warnings.warn( + _TEXT_WARNING.format(label), + category=DeprecationWarning, + stacklevel=3, + ) + return obj.encode("utf-8") + return obj diff --git a/venv/Lib/site-packages/OpenSSL/crypto.py b/venv/Lib/site-packages/OpenSSL/crypto.py new file mode 100644 index 0000000..366007e --- /dev/null +++ b/venv/Lib/site-packages/OpenSSL/crypto.py @@ -0,0 +1,2450 @@ +from __future__ import annotations + +import calendar +import datetime +import functools +import sys +import typing +import warnings +from base64 import b16encode +from collections.abc import Iterable, Sequence +from functools import partial +from typing import ( + Any, + Callable, + Union, +) + +if sys.version_info >= (3, 13): + from warnings import deprecated +elif sys.version_info < (3, 8): + _T = typing.TypeVar("T") + + def deprecated(msg: str, **kwargs: object) -> Callable[[_T], _T]: + return lambda f: f +else: + from typing_extensions import deprecated + +from cryptography import utils, x509 +from cryptography.hazmat.primitives.asymmetric import ( + dsa, + ec, + ed448, + ed25519, + rsa, +) + +from OpenSSL._util import StrOrBytesPath +from OpenSSL._util import ( + byte_string as _byte_string, +) +from OpenSSL._util import ( + exception_from_error_queue as _exception_from_error_queue, +) +from OpenSSL._util import ( + ffi as _ffi, +) +from OpenSSL._util import ( + lib as _lib, +) +from OpenSSL._util import ( + make_assert as _make_assert, +) +from OpenSSL._util import ( + path_bytes as _path_bytes, +) + +__all__ = [ + "FILETYPE_ASN1", + "FILETYPE_PEM", + "FILETYPE_TEXT", + "TYPE_DSA", + "TYPE_RSA", + "X509", + "Error", + "PKey", + "X509Extension", + "X509Name", + "X509Req", + "X509Store", + "X509StoreContext", + "X509StoreContextError", + "X509StoreFlags", + "dump_certificate", + "dump_certificate_request", + "dump_privatekey", + "dump_publickey", + "get_elliptic_curve", + "get_elliptic_curves", + "load_certificate", + "load_certificate_request", + "load_privatekey", + "load_publickey", +] + + +_PrivateKey = Union[ + dsa.DSAPrivateKey, + ec.EllipticCurvePrivateKey, + ed25519.Ed25519PrivateKey, + ed448.Ed448PrivateKey, + rsa.RSAPrivateKey, +] +_PublicKey = Union[ + dsa.DSAPublicKey, + ec.EllipticCurvePublicKey, + ed25519.Ed25519PublicKey, + ed448.Ed448PublicKey, + rsa.RSAPublicKey, +] +_Key = Union[_PrivateKey, _PublicKey] +PassphraseCallableT = Union[bytes, Callable[..., bytes]] + + +FILETYPE_PEM: int = _lib.SSL_FILETYPE_PEM +FILETYPE_ASN1: int = _lib.SSL_FILETYPE_ASN1 + +# TODO This was an API mistake. OpenSSL has no such constant. +FILETYPE_TEXT = 2**16 - 1 + +TYPE_RSA: int = _lib.EVP_PKEY_RSA +TYPE_DSA: int = _lib.EVP_PKEY_DSA +TYPE_DH: int = _lib.EVP_PKEY_DH +TYPE_EC: int = _lib.EVP_PKEY_EC + + +class Error(Exception): + """ + An error occurred in an `OpenSSL.crypto` API. + """ + + +_raise_current_error = partial(_exception_from_error_queue, Error) +_openssl_assert = _make_assert(Error) + + +def _new_mem_buf(buffer: bytes | None = None) -> Any: + """ + Allocate a new OpenSSL memory BIO. + + Arrange for the garbage collector to clean it up automatically. + + :param buffer: None or some bytes to use to put into the BIO so that they + can be read out. + """ + if buffer is None: + bio = _lib.BIO_new(_lib.BIO_s_mem()) + free = _lib.BIO_free + else: + data = _ffi.new("char[]", buffer) + bio = _lib.BIO_new_mem_buf(data, len(buffer)) + + # Keep the memory alive as long as the bio is alive! + def free(bio: Any, ref: Any = data) -> Any: + return _lib.BIO_free(bio) + + _openssl_assert(bio != _ffi.NULL) + + bio = _ffi.gc(bio, free) + return bio + + +def _bio_to_string(bio: Any) -> bytes: + """ + Copy the contents of an OpenSSL BIO object into a Python byte string. + """ + result_buffer = _ffi.new("char**") + buffer_length = _lib.BIO_get_mem_data(bio, result_buffer) + return _ffi.buffer(result_buffer[0], buffer_length)[:] + + +def _set_asn1_time(boundary: Any, when: bytes) -> None: + """ + The the time value of an ASN1 time object. + + @param boundary: An ASN1_TIME pointer (or an object safely + castable to that type) which will have its value set. + @param when: A string representation of the desired time value. + + @raise TypeError: If C{when} is not a L{bytes} string. + @raise ValueError: If C{when} does not represent a time in the required + format. + @raise RuntimeError: If the time value cannot be set for some other + (unspecified) reason. + """ + if not isinstance(when, bytes): + raise TypeError("when must be a byte string") + # ASN1_TIME_set_string validates the string without writing anything + # when the destination is NULL. + _openssl_assert(boundary != _ffi.NULL) + + set_result = _lib.ASN1_TIME_set_string(boundary, when) + if set_result == 0: + raise ValueError("Invalid string") + + +def _new_asn1_time(when: bytes) -> Any: + """ + Behaves like _set_asn1_time but returns a new ASN1_TIME object. + + @param when: A string representation of the desired time value. + + @raise TypeError: If C{when} is not a L{bytes} string. + @raise ValueError: If C{when} does not represent a time in the required + format. + @raise RuntimeError: If the time value cannot be set for some other + (unspecified) reason. + """ + ret = _lib.ASN1_TIME_new() + _openssl_assert(ret != _ffi.NULL) + ret = _ffi.gc(ret, _lib.ASN1_TIME_free) + _set_asn1_time(ret, when) + return ret + + +def _get_asn1_time(timestamp: Any) -> bytes | None: + """ + Retrieve the time value of an ASN1 time object. + + @param timestamp: An ASN1_GENERALIZEDTIME* (or an object safely castable to + that type) from which the time value will be retrieved. + + @return: The time value from C{timestamp} as a L{bytes} string in a certain + format. Or C{None} if the object contains no time value. + """ + string_timestamp = _ffi.cast("ASN1_STRING*", timestamp) + if _lib.ASN1_STRING_length(string_timestamp) == 0: + return None + elif ( + _lib.ASN1_STRING_type(string_timestamp) == _lib.V_ASN1_GENERALIZEDTIME + ): + return _ffi.string(_lib.ASN1_STRING_get0_data(string_timestamp)) + else: + generalized_timestamp = _ffi.new("ASN1_GENERALIZEDTIME**") + _lib.ASN1_TIME_to_generalizedtime(timestamp, generalized_timestamp) + _openssl_assert(generalized_timestamp[0] != _ffi.NULL) + + string_timestamp = _ffi.cast("ASN1_STRING*", generalized_timestamp[0]) + string_data = _lib.ASN1_STRING_get0_data(string_timestamp) + string_result = _ffi.string(string_data) + _lib.ASN1_GENERALIZEDTIME_free(generalized_timestamp[0]) + return string_result + + +class _X509NameInvalidator: + def __init__(self) -> None: + self._names: list[X509Name] = [] + + def add(self, name: X509Name) -> None: + self._names.append(name) + + def clear(self) -> None: + for name in self._names: + # Breaks the object, but also prevents UAF! + del name._name + + +class PKey: + """ + A class representing an DSA or RSA public key or key pair. + """ + + _only_public = False + _initialized = True + + def __init__(self) -> None: + pkey = _lib.EVP_PKEY_new() + self._pkey = _ffi.gc(pkey, _lib.EVP_PKEY_free) + self._initialized = False + + def to_cryptography_key(self) -> _Key: + """ + Export as a ``cryptography`` key. + + :rtype: One of ``cryptography``'s `key interfaces`_. + + .. _key interfaces: https://cryptography.io/en/latest/hazmat/\ + primitives/asymmetric/rsa/#key-interfaces + + .. versionadded:: 16.1.0 + """ + from cryptography.hazmat.primitives.serialization import ( + load_der_private_key, + load_der_public_key, + ) + + if self._only_public: + der = dump_publickey(FILETYPE_ASN1, self) + return typing.cast(_Key, load_der_public_key(der)) + else: + der = dump_privatekey(FILETYPE_ASN1, self) + return typing.cast(_Key, load_der_private_key(der, password=None)) + + @classmethod + def from_cryptography_key(cls, crypto_key: _Key) -> PKey: + """ + Construct based on a ``cryptography`` *crypto_key*. + + :param crypto_key: A ``cryptography`` key. + :type crypto_key: One of ``cryptography``'s `key interfaces`_. + + :rtype: PKey + + .. versionadded:: 16.1.0 + """ + if not isinstance( + crypto_key, + ( + dsa.DSAPrivateKey, + dsa.DSAPublicKey, + ec.EllipticCurvePrivateKey, + ec.EllipticCurvePublicKey, + ed25519.Ed25519PrivateKey, + ed25519.Ed25519PublicKey, + ed448.Ed448PrivateKey, + ed448.Ed448PublicKey, + rsa.RSAPrivateKey, + rsa.RSAPublicKey, + ), + ): + raise TypeError("Unsupported key type") + + from cryptography.hazmat.primitives.serialization import ( + Encoding, + NoEncryption, + PrivateFormat, + PublicFormat, + ) + + if isinstance( + crypto_key, + ( + dsa.DSAPublicKey, + ec.EllipticCurvePublicKey, + ed25519.Ed25519PublicKey, + ed448.Ed448PublicKey, + rsa.RSAPublicKey, + ), + ): + return load_publickey( + FILETYPE_ASN1, + crypto_key.public_bytes( + Encoding.DER, PublicFormat.SubjectPublicKeyInfo + ), + ) + else: + der = crypto_key.private_bytes( + Encoding.DER, PrivateFormat.PKCS8, NoEncryption() + ) + return load_privatekey(FILETYPE_ASN1, der) + + def generate_key(self, type: int, bits: int) -> None: + """ + Generate a key pair of the given type, with the given number of bits. + + This generates a key "into" the this object. + + :param type: The key type. + :type type: :py:data:`TYPE_RSA` or :py:data:`TYPE_DSA` + :param bits: The number of bits. + :type bits: :py:data:`int` ``>= 0`` + :raises TypeError: If :py:data:`type` or :py:data:`bits` isn't + of the appropriate type. + :raises ValueError: If the number of bits isn't an integer of + the appropriate size. + :return: ``None`` + """ + if not isinstance(type, int): + raise TypeError("type must be an integer") + + if not isinstance(bits, int): + raise TypeError("bits must be an integer") + + if type == TYPE_RSA: + if bits <= 0: + raise ValueError("Invalid number of bits") + + # TODO Check error return + exponent = _lib.BN_new() + exponent = _ffi.gc(exponent, _lib.BN_free) + _lib.BN_set_word(exponent, _lib.RSA_F4) + + rsa = _lib.RSA_new() + + result = _lib.RSA_generate_key_ex(rsa, bits, exponent, _ffi.NULL) + _openssl_assert(result == 1) + + result = _lib.EVP_PKEY_assign_RSA(self._pkey, rsa) + _openssl_assert(result == 1) + + elif type == TYPE_DSA: + dsa = _lib.DSA_new() + _openssl_assert(dsa != _ffi.NULL) + + dsa = _ffi.gc(dsa, _lib.DSA_free) + res = _lib.DSA_generate_parameters_ex( + dsa, bits, _ffi.NULL, 0, _ffi.NULL, _ffi.NULL, _ffi.NULL + ) + _openssl_assert(res == 1) + + _openssl_assert(_lib.DSA_generate_key(dsa) == 1) + _openssl_assert(_lib.EVP_PKEY_set1_DSA(self._pkey, dsa) == 1) + else: + raise Error("No such key type") + + self._initialized = True + + def check(self) -> bool: + """ + Check the consistency of an RSA private key. + + This is the Python equivalent of OpenSSL's ``RSA_check_key``. + + :return: ``True`` if key is consistent. + + :raise OpenSSL.crypto.Error: if the key is inconsistent. + + :raise TypeError: if the key is of a type which cannot be checked. + Only RSA keys can currently be checked. + """ + if self._only_public: + raise TypeError("public key only") + + if _lib.EVP_PKEY_type(self.type()) != _lib.EVP_PKEY_RSA: + raise TypeError("Only RSA keys can currently be checked.") + + rsa = _lib.EVP_PKEY_get1_RSA(self._pkey) + rsa = _ffi.gc(rsa, _lib.RSA_free) + result = _lib.RSA_check_key(rsa) + if result == 1: + return True + _raise_current_error() + + def type(self) -> int: + """ + Returns the type of the key + + :return: The type of the key. + """ + return _lib.EVP_PKEY_id(self._pkey) + + def bits(self) -> int: + """ + Returns the number of bits of the key + + :return: The number of bits of the key. + """ + return _lib.EVP_PKEY_bits(self._pkey) + + +class _EllipticCurve: + """ + A representation of a supported elliptic curve. + + @cvar _curves: :py:obj:`None` until an attempt is made to load the curves. + Thereafter, a :py:type:`set` containing :py:type:`_EllipticCurve` + instances each of which represents one curve supported by the system. + @type _curves: :py:type:`NoneType` or :py:type:`set` + """ + + _curves = None + + def __ne__(self, other: Any) -> bool: + """ + Implement cooperation with the right-hand side argument of ``!=``. + + Python 3 seems to have dropped this cooperation in this very narrow + circumstance. + """ + if isinstance(other, _EllipticCurve): + return super().__ne__(other) + return NotImplemented + + @classmethod + def _load_elliptic_curves(cls, lib: Any) -> set[_EllipticCurve]: + """ + Get the curves supported by OpenSSL. + + :param lib: The OpenSSL library binding object. + + :return: A :py:type:`set` of ``cls`` instances giving the names of the + elliptic curves the underlying library supports. + """ + num_curves = lib.EC_get_builtin_curves(_ffi.NULL, 0) + builtin_curves = _ffi.new("EC_builtin_curve[]", num_curves) + # The return value on this call should be num_curves again. We + # could check it to make sure but if it *isn't* then.. what could + # we do? Abort the whole process, I suppose...? -exarkun + lib.EC_get_builtin_curves(builtin_curves, num_curves) + return set(cls.from_nid(lib, c.nid) for c in builtin_curves) + + @classmethod + def _get_elliptic_curves(cls, lib: Any) -> set[_EllipticCurve]: + """ + Get, cache, and return the curves supported by OpenSSL. + + :param lib: The OpenSSL library binding object. + + :return: A :py:type:`set` of ``cls`` instances giving the names of the + elliptic curves the underlying library supports. + """ + if cls._curves is None: + cls._curves = cls._load_elliptic_curves(lib) + return cls._curves + + @classmethod + def from_nid(cls, lib: Any, nid: int) -> _EllipticCurve: + """ + Instantiate a new :py:class:`_EllipticCurve` associated with the given + OpenSSL NID. + + :param lib: The OpenSSL library binding object. + + :param nid: The OpenSSL NID the resulting curve object will represent. + This must be a curve NID (and not, for example, a hash NID) or + subsequent operations will fail in unpredictable ways. + :type nid: :py:class:`int` + + :return: The curve object. + """ + return cls(lib, nid, _ffi.string(lib.OBJ_nid2sn(nid)).decode("ascii")) + + def __init__(self, lib: Any, nid: int, name: str) -> None: + """ + :param _lib: The :py:mod:`cryptography` binding instance used to + interface with OpenSSL. + + :param _nid: The OpenSSL NID identifying the curve this object + represents. + :type _nid: :py:class:`int` + + :param name: The OpenSSL short name identifying the curve this object + represents. + :type name: :py:class:`unicode` + """ + self._lib = lib + self._nid = nid + self.name = name + + def __repr__(self) -> str: + return f"" + + def _to_EC_KEY(self) -> Any: + """ + Create a new OpenSSL EC_KEY structure initialized to use this curve. + + The structure is automatically garbage collected when the Python object + is garbage collected. + """ + key = self._lib.EC_KEY_new_by_curve_name(self._nid) + return _ffi.gc(key, _lib.EC_KEY_free) + + +@deprecated( + "get_elliptic_curves is deprecated. You should use the APIs in " + "cryptography instead." +) +def get_elliptic_curves() -> set[_EllipticCurve]: + """ + Return a set of objects representing the elliptic curves supported in the + OpenSSL build in use. + + The curve objects have a :py:class:`unicode` ``name`` attribute by which + they identify themselves. + + The curve objects are useful as values for the argument accepted by + :py:meth:`Context.set_tmp_ecdh` to specify which elliptical curve should be + used for ECDHE key exchange. + """ + return _EllipticCurve._get_elliptic_curves(_lib) + + +@deprecated( + "get_elliptic_curve is deprecated. You should use the APIs in " + "cryptography instead." +) +def get_elliptic_curve(name: str) -> _EllipticCurve: + """ + Return a single curve object selected by name. + + See :py:func:`get_elliptic_curves` for information about curve objects. + + :param name: The OpenSSL short name identifying the curve object to + retrieve. + :type name: :py:class:`unicode` + + If the named curve is not supported then :py:class:`ValueError` is raised. + """ + for curve in get_elliptic_curves(): + if curve.name == name: + return curve + raise ValueError("unknown curve name", name) + + +@functools.total_ordering +class X509Name: + """ + An X.509 Distinguished Name. + + :ivar countryName: The country of the entity. + :ivar C: Alias for :py:attr:`countryName`. + + :ivar stateOrProvinceName: The state or province of the entity. + :ivar ST: Alias for :py:attr:`stateOrProvinceName`. + + :ivar localityName: The locality of the entity. + :ivar L: Alias for :py:attr:`localityName`. + + :ivar organizationName: The organization name of the entity. + :ivar O: Alias for :py:attr:`organizationName`. + + :ivar organizationalUnitName: The organizational unit of the entity. + :ivar OU: Alias for :py:attr:`organizationalUnitName` + + :ivar commonName: The common name of the entity. + :ivar CN: Alias for :py:attr:`commonName`. + + :ivar emailAddress: The e-mail address of the entity. + """ + + def __init__(self, name: X509Name) -> None: + """ + Create a new X509Name, copying the given X509Name instance. + + :param name: The name to copy. + :type name: :py:class:`X509Name` + """ + name = _lib.X509_NAME_dup(name._name) + self._name: Any = _ffi.gc(name, _lib.X509_NAME_free) + + def __setattr__(self, name: str, value: Any) -> None: + if name.startswith("_"): + return super().__setattr__(name, value) + + # Note: we really do not want str subclasses here, so we do not use + # isinstance. + if type(name) is not str: + raise TypeError( + f"attribute name must be string, not " + f"'{type(value).__name__:.200}'" + ) + + nid = _lib.OBJ_txt2nid(_byte_string(name)) + if nid == _lib.NID_undef: + try: + _raise_current_error() + except Error: + pass + raise AttributeError("No such attribute") + + # If there's an old entry for this NID, remove it + for i in range(_lib.X509_NAME_entry_count(self._name)): + ent = _lib.X509_NAME_get_entry(self._name, i) + ent_obj = _lib.X509_NAME_ENTRY_get_object(ent) + ent_nid = _lib.OBJ_obj2nid(ent_obj) + if nid == ent_nid: + ent = _lib.X509_NAME_delete_entry(self._name, i) + _lib.X509_NAME_ENTRY_free(ent) + break + + if isinstance(value, str): + value = value.encode("utf-8") + + add_result = _lib.X509_NAME_add_entry_by_NID( + self._name, nid, _lib.MBSTRING_UTF8, value, -1, -1, 0 + ) + if not add_result: + _raise_current_error() + + def __getattr__(self, name: str) -> str | None: + """ + Find attribute. An X509Name object has the following attributes: + countryName (alias C), stateOrProvince (alias ST), locality (alias L), + organization (alias O), organizationalUnit (alias OU), commonName + (alias CN) and more... + """ + nid = _lib.OBJ_txt2nid(_byte_string(name)) + if nid == _lib.NID_undef: + # This is a bit weird. OBJ_txt2nid indicated failure, but it seems + # a lower level function, a2d_ASN1_OBJECT, also feels the need to + # push something onto the error queue. If we don't clean that up + # now, someone else will bump into it later and be quite confused. + # See lp#314814. + try: + _raise_current_error() + except Error: + pass + raise AttributeError("No such attribute") + + entry_index = _lib.X509_NAME_get_index_by_NID(self._name, nid, -1) + if entry_index == -1: + return None + + entry = _lib.X509_NAME_get_entry(self._name, entry_index) + data = _lib.X509_NAME_ENTRY_get_data(entry) + + result_buffer = _ffi.new("unsigned char**") + data_length = _lib.ASN1_STRING_to_UTF8(result_buffer, data) + _openssl_assert(data_length >= 0) + + try: + result = _ffi.buffer(result_buffer[0], data_length)[:].decode( + "utf-8" + ) + finally: + # XXX untested + _lib.OPENSSL_free(result_buffer[0]) + return result + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, X509Name): + return NotImplemented + + return _lib.X509_NAME_cmp(self._name, other._name) == 0 + + def __lt__(self, other: Any) -> bool: + if not isinstance(other, X509Name): + return NotImplemented + + return _lib.X509_NAME_cmp(self._name, other._name) < 0 + + def __repr__(self) -> str: + """ + String representation of an X509Name + """ + result_buffer = _ffi.new("char[]", 512) + format_result = _lib.X509_NAME_oneline( + self._name, result_buffer, len(result_buffer) + ) + _openssl_assert(format_result != _ffi.NULL) + + return "".format( + _ffi.string(result_buffer).decode("utf-8"), + ) + + def hash(self) -> int: + """ + Return an integer representation of the first four bytes of the + MD5 digest of the DER representation of the name. + + This is the Python equivalent of OpenSSL's ``X509_NAME_hash``. + + :return: The (integer) hash of this name. + :rtype: :py:class:`int` + """ + return _lib.X509_NAME_hash(self._name) + + def der(self) -> bytes: + """ + Return the DER encoding of this name. + + :return: The DER encoded form of this name. + :rtype: :py:class:`bytes` + """ + result_buffer = _ffi.new("unsigned char**") + encode_result = _lib.i2d_X509_NAME(self._name, result_buffer) + _openssl_assert(encode_result >= 0) + + string_result = _ffi.buffer(result_buffer[0], encode_result)[:] + _lib.OPENSSL_free(result_buffer[0]) + return string_result + + def get_components(self) -> list[tuple[bytes, bytes]]: + """ + Returns the components of this name, as a sequence of 2-tuples. + + :return: The components of this name. + :rtype: :py:class:`list` of ``name, value`` tuples. + """ + result = [] + for i in range(_lib.X509_NAME_entry_count(self._name)): + ent = _lib.X509_NAME_get_entry(self._name, i) + + fname = _lib.X509_NAME_ENTRY_get_object(ent) + fval = _lib.X509_NAME_ENTRY_get_data(ent) + + nid = _lib.OBJ_obj2nid(fname) + name = _lib.OBJ_nid2sn(nid) + + # ffi.string does not handle strings containing NULL bytes + # (which may have been generated by old, broken software) + value = _ffi.buffer( + _lib.ASN1_STRING_get0_data(fval), _lib.ASN1_STRING_length(fval) + )[:] + result.append((_ffi.string(name), value)) + + return result + + +@deprecated( + "X509Extension support in pyOpenSSL is deprecated. You should use the " + "APIs in cryptography." +) +class X509Extension: + """ + An X.509 v3 certificate extension. + + .. deprecated:: 23.3.0 + Use cryptography's X509 APIs instead. + """ + + def __init__( + self, + type_name: bytes, + critical: bool, + value: bytes, + subject: X509 | None = None, + issuer: X509 | None = None, + ) -> None: + """ + Initializes an X509 extension. + + :param type_name: The name of the type of extension_ to create. + :type type_name: :py:data:`bytes` + + :param bool critical: A flag indicating whether this is a critical + extension. + + :param value: The OpenSSL textual representation of the extension's + value. + :type value: :py:data:`bytes` + + :param subject: Optional X509 certificate to use as subject. + :type subject: :py:class:`X509` + + :param issuer: Optional X509 certificate to use as issuer. + :type issuer: :py:class:`X509` + + .. _extension: https://www.openssl.org/docs/manmaster/man5/ + x509v3_config.html#STANDARD-EXTENSIONS + """ + ctx = _ffi.new("X509V3_CTX*") + + # A context is necessary for any extension which uses the r2i + # conversion method. That is, X509V3_EXT_nconf may segfault if passed + # a NULL ctx. Start off by initializing most of the fields to NULL. + _lib.X509V3_set_ctx(ctx, _ffi.NULL, _ffi.NULL, _ffi.NULL, _ffi.NULL, 0) + + # We have no configuration database - but perhaps we should (some + # extensions may require it). + _lib.X509V3_set_ctx_nodb(ctx) + + # Initialize the subject and issuer, if appropriate. ctx is a local, + # and as far as I can tell none of the X509V3_* APIs invoked here steal + # any references, so no need to mess with reference counts or + # duplicates. + if issuer is not None: + if not isinstance(issuer, X509): + raise TypeError("issuer must be an X509 instance") + ctx.issuer_cert = issuer._x509 + if subject is not None: + if not isinstance(subject, X509): + raise TypeError("subject must be an X509 instance") + ctx.subject_cert = subject._x509 + + if critical: + # There are other OpenSSL APIs which would let us pass in critical + # separately, but they're harder to use, and since value is already + # a pile of crappy junk smuggling a ton of utterly important + # structured data, what's the point of trying to avoid nasty stuff + # with strings? (However, X509V3_EXT_i2d in particular seems like + # it would be a better API to invoke. I do not know where to get + # the ext_struc it desires for its last parameter, though.) + value = b"critical," + value + + extension = _lib.X509V3_EXT_nconf(_ffi.NULL, ctx, type_name, value) + if extension == _ffi.NULL: + _raise_current_error() + self._extension = _ffi.gc(extension, _lib.X509_EXTENSION_free) + + @property + def _nid(self) -> Any: + return _lib.OBJ_obj2nid( + _lib.X509_EXTENSION_get_object(self._extension) + ) + + _prefixes: typing.ClassVar[dict[int, str]] = { + _lib.GEN_EMAIL: "email", + _lib.GEN_DNS: "DNS", + _lib.GEN_URI: "URI", + } + + def _subjectAltNameString(self) -> str: + names = _ffi.cast( + "GENERAL_NAMES*", _lib.X509V3_EXT_d2i(self._extension) + ) + + names = _ffi.gc(names, _lib.GENERAL_NAMES_free) + parts = [] + for i in range(_lib.sk_GENERAL_NAME_num(names)): + name = _lib.sk_GENERAL_NAME_value(names, i) + try: + label = self._prefixes[name.type] + except KeyError: + bio = _new_mem_buf() + _lib.GENERAL_NAME_print(bio, name) + parts.append(_bio_to_string(bio).decode("utf-8")) + else: + value = _ffi.buffer(name.d.ia5.data, name.d.ia5.length)[ + : + ].decode("utf-8") + parts.append(label + ":" + value) + return ", ".join(parts) + + def __str__(self) -> str: + """ + :return: a nice text representation of the extension + """ + if _lib.NID_subject_alt_name == self._nid: + return self._subjectAltNameString() + + bio = _new_mem_buf() + print_result = _lib.X509V3_EXT_print(bio, self._extension, 0, 0) + _openssl_assert(print_result != 0) + + return _bio_to_string(bio).decode("utf-8") + + def get_critical(self) -> bool: + """ + Returns the critical field of this X.509 extension. + + :return: The critical field. + """ + return _lib.X509_EXTENSION_get_critical(self._extension) + + def get_short_name(self) -> bytes: + """ + Returns the short type name of this X.509 extension. + + The result is a byte string such as :py:const:`b"basicConstraints"`. + + :return: The short type name. + :rtype: :py:data:`bytes` + + .. versionadded:: 0.12 + """ + obj = _lib.X509_EXTENSION_get_object(self._extension) + nid = _lib.OBJ_obj2nid(obj) + # OpenSSL 3.1.0 has a bug where nid2sn returns NULL for NIDs that + # previously returned UNDEF. This is a workaround for that issue. + # https://github.com/openssl/openssl/commit/908ba3ed9adbb3df90f76 + buf = _lib.OBJ_nid2sn(nid) + if buf != _ffi.NULL: + return _ffi.string(buf) + else: + return b"UNDEF" + + def get_data(self) -> bytes: + """ + Returns the data of the X509 extension, encoded as ASN.1. + + :return: The ASN.1 encoded data of this X509 extension. + :rtype: :py:data:`bytes` + + .. versionadded:: 0.12 + """ + octet_result = _lib.X509_EXTENSION_get_data(self._extension) + string_result = _ffi.cast("ASN1_STRING*", octet_result) + char_result = _lib.ASN1_STRING_get0_data(string_result) + result_length = _lib.ASN1_STRING_length(string_result) + return _ffi.buffer(char_result, result_length)[:] + + +@deprecated( + "CSR support in pyOpenSSL is deprecated. You should use the APIs " + "in cryptography." +) +class X509Req: + """ + An X.509 certificate signing requests. + + .. deprecated:: 24.2.0 + Use `cryptography.x509.CertificateSigningRequest` instead. + """ + + def __init__(self) -> None: + req = _lib.X509_REQ_new() + self._req = _ffi.gc(req, _lib.X509_REQ_free) + # Default to version 0. + self.set_version(0) + + def to_cryptography(self) -> x509.CertificateSigningRequest: + """ + Export as a ``cryptography`` certificate signing request. + + :rtype: ``cryptography.x509.CertificateSigningRequest`` + + .. versionadded:: 17.1.0 + """ + from cryptography.x509 import load_der_x509_csr + + der = _dump_certificate_request_internal(FILETYPE_ASN1, self) + + return load_der_x509_csr(der) + + @classmethod + def from_cryptography( + cls, crypto_req: x509.CertificateSigningRequest + ) -> X509Req: + """ + Construct based on a ``cryptography`` *crypto_req*. + + :param crypto_req: A ``cryptography`` X.509 certificate signing request + :type crypto_req: ``cryptography.x509.CertificateSigningRequest`` + + :rtype: X509Req + + .. versionadded:: 17.1.0 + """ + if not isinstance(crypto_req, x509.CertificateSigningRequest): + raise TypeError("Must be a certificate signing request") + + from cryptography.hazmat.primitives.serialization import Encoding + + der = crypto_req.public_bytes(Encoding.DER) + return _load_certificate_request_internal(FILETYPE_ASN1, der) + + def set_pubkey(self, pkey: PKey) -> None: + """ + Set the public key of the certificate signing request. + + :param pkey: The public key to use. + :type pkey: :py:class:`PKey` + + :return: ``None`` + """ + set_result = _lib.X509_REQ_set_pubkey(self._req, pkey._pkey) + _openssl_assert(set_result == 1) + + def get_pubkey(self) -> PKey: + """ + Get the public key of the certificate signing request. + + :return: The public key. + :rtype: :py:class:`PKey` + """ + pkey = PKey.__new__(PKey) + pkey._pkey = _lib.X509_REQ_get_pubkey(self._req) + _openssl_assert(pkey._pkey != _ffi.NULL) + pkey._pkey = _ffi.gc(pkey._pkey, _lib.EVP_PKEY_free) + pkey._only_public = True + return pkey + + def set_version(self, version: int) -> None: + """ + Set the version subfield (RFC 2986, section 4.1) of the certificate + request. + + :param int version: The version number. + :return: ``None`` + """ + if not isinstance(version, int): + raise TypeError("version must be an int") + if version != 0: + raise ValueError( + "Invalid version. The only valid version for X509Req is 0." + ) + set_result = _lib.X509_REQ_set_version(self._req, version) + _openssl_assert(set_result == 1) + + def get_version(self) -> int: + """ + Get the version subfield (RFC 2459, section 4.1.2.1) of the certificate + request. + + :return: The value of the version subfield. + :rtype: :py:class:`int` + """ + return _lib.X509_REQ_get_version(self._req) + + def get_subject(self) -> X509Name: + """ + Return the subject of this certificate signing request. + + This creates a new :class:`X509Name` that wraps the underlying subject + name field on the certificate signing request. Modifying it will modify + the underlying signing request, and will have the effect of modifying + any other :class:`X509Name` that refers to this subject. + + :return: The subject of this certificate signing request. + :rtype: :class:`X509Name` + """ + name = X509Name.__new__(X509Name) + name._name = _lib.X509_REQ_get_subject_name(self._req) + _openssl_assert(name._name != _ffi.NULL) + + # The name is owned by the X509Req structure. As long as the X509Name + # Python object is alive, keep the X509Req Python object alive. + name._owner = self + + return name + + def add_extensions(self, extensions: Iterable[X509Extension]) -> None: + """ + Add extensions to the certificate signing request. + + :param extensions: The X.509 extensions to add. + :type extensions: iterable of :py:class:`X509Extension` + :return: ``None`` + """ + warnings.warn( + ( + "This API is deprecated and will be removed in a future " + "version of pyOpenSSL. You should use pyca/cryptography's " + "X.509 APIs instead." + ), + DeprecationWarning, + stacklevel=2, + ) + + stack = _lib.sk_X509_EXTENSION_new_null() + _openssl_assert(stack != _ffi.NULL) + + stack = _ffi.gc(stack, _lib.sk_X509_EXTENSION_free) + + for ext in extensions: + if not isinstance(ext, X509Extension): + raise ValueError("One of the elements is not an X509Extension") + + # TODO push can fail (here and elsewhere) + _lib.sk_X509_EXTENSION_push(stack, ext._extension) + + add_result = _lib.X509_REQ_add_extensions(self._req, stack) + _openssl_assert(add_result == 1) + + def get_extensions(self) -> list[X509Extension]: + """ + Get X.509 extensions in the certificate signing request. + + :return: The X.509 extensions in this request. + :rtype: :py:class:`list` of :py:class:`X509Extension` objects. + + .. versionadded:: 0.15 + """ + warnings.warn( + ( + "This API is deprecated and will be removed in a future " + "version of pyOpenSSL. You should use pyca/cryptography's " + "X.509 APIs instead." + ), + DeprecationWarning, + stacklevel=2, + ) + + exts = [] + native_exts_obj = _lib.X509_REQ_get_extensions(self._req) + native_exts_obj = _ffi.gc( + native_exts_obj, + lambda x: _lib.sk_X509_EXTENSION_pop_free( + x, + _ffi.addressof(_lib._original_lib, "X509_EXTENSION_free"), + ), + ) + + for i in range(_lib.sk_X509_EXTENSION_num(native_exts_obj)): + ext = X509Extension.__new__(X509Extension) + extension = _lib.X509_EXTENSION_dup( + _lib.sk_X509_EXTENSION_value(native_exts_obj, i) + ) + ext._extension = _ffi.gc(extension, _lib.X509_EXTENSION_free) + exts.append(ext) + return exts + + def sign(self, pkey: PKey, digest: str) -> None: + """ + Sign the certificate signing request with this key and digest type. + + :param pkey: The key pair to sign with. + :type pkey: :py:class:`PKey` + :param digest: The name of the message digest to use for the signature, + e.g. :py:data:`"sha256"`. + :type digest: :py:class:`str` + :return: ``None`` + """ + if pkey._only_public: + raise ValueError("Key has only public part") + + if not pkey._initialized: + raise ValueError("Key is uninitialized") + + digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest)) + if digest_obj == _ffi.NULL: + raise ValueError("No such digest method") + + sign_result = _lib.X509_REQ_sign(self._req, pkey._pkey, digest_obj) + _openssl_assert(sign_result > 0) + + def verify(self, pkey: PKey) -> bool: + """ + Verifies the signature on this certificate signing request. + + :param PKey key: A public key. + + :return: ``True`` if the signature is correct. + :rtype: bool + + :raises OpenSSL.crypto.Error: If the signature is invalid or there is a + problem verifying the signature. + """ + if not isinstance(pkey, PKey): + raise TypeError("pkey must be a PKey instance") + + result = _lib.X509_REQ_verify(self._req, pkey._pkey) + if result <= 0: + _raise_current_error() + + return result + + +class X509: + """ + An X.509 certificate. + """ + + def __init__(self) -> None: + x509 = _lib.X509_new() + _openssl_assert(x509 != _ffi.NULL) + self._x509 = _ffi.gc(x509, _lib.X509_free) + + self._issuer_invalidator = _X509NameInvalidator() + self._subject_invalidator = _X509NameInvalidator() + + @classmethod + def _from_raw_x509_ptr(cls, x509: Any) -> X509: + cert = cls.__new__(cls) + cert._x509 = _ffi.gc(x509, _lib.X509_free) + cert._issuer_invalidator = _X509NameInvalidator() + cert._subject_invalidator = _X509NameInvalidator() + return cert + + def to_cryptography(self) -> x509.Certificate: + """ + Export as a ``cryptography`` certificate. + + :rtype: ``cryptography.x509.Certificate`` + + .. versionadded:: 17.1.0 + """ + from cryptography.x509 import load_der_x509_certificate + + der = dump_certificate(FILETYPE_ASN1, self) + return load_der_x509_certificate(der) + + @classmethod + def from_cryptography(cls, crypto_cert: x509.Certificate) -> X509: + """ + Construct based on a ``cryptography`` *crypto_cert*. + + :param crypto_key: A ``cryptography`` X.509 certificate. + :type crypto_key: ``cryptography.x509.Certificate`` + + :rtype: X509 + + .. versionadded:: 17.1.0 + """ + if not isinstance(crypto_cert, x509.Certificate): + raise TypeError("Must be a certificate") + + from cryptography.hazmat.primitives.serialization import Encoding + + der = crypto_cert.public_bytes(Encoding.DER) + return load_certificate(FILETYPE_ASN1, der) + + def set_version(self, version: int) -> None: + """ + Set the version number of the certificate. Note that the + version value is zero-based, eg. a value of 0 is V1. + + :param version: The version number of the certificate. + :type version: :py:class:`int` + + :return: ``None`` + """ + if not isinstance(version, int): + raise TypeError("version must be an integer") + + _openssl_assert(_lib.X509_set_version(self._x509, version) == 1) + + def get_version(self) -> int: + """ + Return the version number of the certificate. + + :return: The version number of the certificate. + :rtype: :py:class:`int` + """ + return _lib.X509_get_version(self._x509) + + def get_pubkey(self) -> PKey: + """ + Get the public key of the certificate. + + :return: The public key. + :rtype: :py:class:`PKey` + """ + pkey = PKey.__new__(PKey) + pkey._pkey = _lib.X509_get_pubkey(self._x509) + if pkey._pkey == _ffi.NULL: + _raise_current_error() + pkey._pkey = _ffi.gc(pkey._pkey, _lib.EVP_PKEY_free) + pkey._only_public = True + return pkey + + def set_pubkey(self, pkey: PKey) -> None: + """ + Set the public key of the certificate. + + :param pkey: The public key. + :type pkey: :py:class:`PKey` + + :return: :py:data:`None` + """ + if not isinstance(pkey, PKey): + raise TypeError("pkey must be a PKey instance") + + set_result = _lib.X509_set_pubkey(self._x509, pkey._pkey) + _openssl_assert(set_result == 1) + + def sign(self, pkey: PKey, digest: str) -> None: + """ + Sign the certificate with this key and digest type. + + :param pkey: The key to sign with. + :type pkey: :py:class:`PKey` + + :param digest: The name of the message digest to use. + :type digest: :py:class:`str` + + :return: :py:data:`None` + """ + if not isinstance(pkey, PKey): + raise TypeError("pkey must be a PKey instance") + + if pkey._only_public: + raise ValueError("Key only has public part") + + if not pkey._initialized: + raise ValueError("Key is uninitialized") + + evp_md = _lib.EVP_get_digestbyname(_byte_string(digest)) + if evp_md == _ffi.NULL: + raise ValueError("No such digest method") + + sign_result = _lib.X509_sign(self._x509, pkey._pkey, evp_md) + _openssl_assert(sign_result > 0) + + def get_signature_algorithm(self) -> bytes: + """ + Return the signature algorithm used in the certificate. + + :return: The name of the algorithm. + :rtype: :py:class:`bytes` + + :raises ValueError: If the signature algorithm is undefined. + + .. versionadded:: 0.13 + """ + sig_alg = _lib.X509_get0_tbs_sigalg(self._x509) + alg = _ffi.new("ASN1_OBJECT **") + _lib.X509_ALGOR_get0(alg, _ffi.NULL, _ffi.NULL, sig_alg) + nid = _lib.OBJ_obj2nid(alg[0]) + if nid == _lib.NID_undef: + raise ValueError("Undefined signature algorithm") + return _ffi.string(_lib.OBJ_nid2ln(nid)) + + def digest(self, digest_name: str) -> bytes: + """ + Return the digest of the X509 object. + + :param digest_name: The name of the digest algorithm to use. + :type digest_name: :py:class:`str` + + :return: The digest of the object, formatted as + :py:const:`b":"`-delimited hex pairs. + :rtype: :py:class:`bytes` + """ + digest = _lib.EVP_get_digestbyname(_byte_string(digest_name)) + if digest == _ffi.NULL: + raise ValueError("No such digest method") + + result_buffer = _ffi.new("unsigned char[]", _lib.EVP_MAX_MD_SIZE) + result_length = _ffi.new("unsigned int[]", 1) + result_length[0] = len(result_buffer) + + digest_result = _lib.X509_digest( + self._x509, digest, result_buffer, result_length + ) + _openssl_assert(digest_result == 1) + + return b":".join( + [ + b16encode(ch).upper() + for ch in _ffi.buffer(result_buffer, result_length[0]) + ] + ) + + def subject_name_hash(self) -> int: + """ + Return the hash of the X509 subject. + + :return: The hash of the subject. + :rtype: :py:class:`int` + """ + return _lib.X509_subject_name_hash(self._x509) + + def set_serial_number(self, serial: int) -> None: + """ + Set the serial number of the certificate. + + :param serial: The new serial number. + :type serial: :py:class:`int` + + :return: :py:data`None` + """ + if not isinstance(serial, int): + raise TypeError("serial must be an integer") + + hex_serial = hex(serial)[2:] + hex_serial_bytes = hex_serial.encode("ascii") + + bignum_serial = _ffi.new("BIGNUM**") + + # BN_hex2bn stores the result in &bignum. + result = _lib.BN_hex2bn(bignum_serial, hex_serial_bytes) + _openssl_assert(result != _ffi.NULL) + + asn1_serial = _lib.BN_to_ASN1_INTEGER(bignum_serial[0], _ffi.NULL) + _lib.BN_free(bignum_serial[0]) + _openssl_assert(asn1_serial != _ffi.NULL) + asn1_serial = _ffi.gc(asn1_serial, _lib.ASN1_INTEGER_free) + set_result = _lib.X509_set_serialNumber(self._x509, asn1_serial) + _openssl_assert(set_result == 1) + + def get_serial_number(self) -> int: + """ + Return the serial number of this certificate. + + :return: The serial number. + :rtype: int + """ + asn1_serial = _lib.X509_get_serialNumber(self._x509) + bignum_serial = _lib.ASN1_INTEGER_to_BN(asn1_serial, _ffi.NULL) + try: + hex_serial = _lib.BN_bn2hex(bignum_serial) + try: + hexstring_serial = _ffi.string(hex_serial) + serial = int(hexstring_serial, 16) + return serial + finally: + _lib.OPENSSL_free(hex_serial) + finally: + _lib.BN_free(bignum_serial) + + def gmtime_adj_notAfter(self, amount: int) -> None: + """ + Adjust the time stamp on which the certificate stops being valid. + + :param int amount: The number of seconds by which to adjust the + timestamp. + :return: ``None`` + """ + if not isinstance(amount, int): + raise TypeError("amount must be an integer") + + notAfter = _lib.X509_getm_notAfter(self._x509) + _lib.X509_gmtime_adj(notAfter, amount) + + def gmtime_adj_notBefore(self, amount: int) -> None: + """ + Adjust the timestamp on which the certificate starts being valid. + + :param amount: The number of seconds by which to adjust the timestamp. + :return: ``None`` + """ + if not isinstance(amount, int): + raise TypeError("amount must be an integer") + + notBefore = _lib.X509_getm_notBefore(self._x509) + _lib.X509_gmtime_adj(notBefore, amount) + + def has_expired(self) -> bool: + """ + Check whether the certificate has expired. + + :return: ``True`` if the certificate has expired, ``False`` otherwise. + :rtype: bool + """ + time_bytes = self.get_notAfter() + if time_bytes is None: + raise ValueError("Unable to determine notAfter") + time_string = time_bytes.decode("utf-8") + not_after = datetime.datetime.strptime(time_string, "%Y%m%d%H%M%SZ") + + UTC = datetime.timezone.utc + utcnow = datetime.datetime.now(UTC).replace(tzinfo=None) + return not_after < utcnow + + def _get_boundary_time(self, which: Any) -> bytes | None: + return _get_asn1_time(which(self._x509)) + + def get_notBefore(self) -> bytes | None: + """ + Get the timestamp at which the certificate starts being valid. + + The timestamp is formatted as an ASN.1 TIME:: + + YYYYMMDDhhmmssZ + + :return: A timestamp string, or ``None`` if there is none. + :rtype: bytes or NoneType + """ + return self._get_boundary_time(_lib.X509_getm_notBefore) + + def _set_boundary_time( + self, which: Callable[..., Any], when: bytes + ) -> None: + return _set_asn1_time(which(self._x509), when) + + def set_notBefore(self, when: bytes) -> None: + """ + Set the timestamp at which the certificate starts being valid. + + The timestamp is formatted as an ASN.1 TIME:: + + YYYYMMDDhhmmssZ + + :param bytes when: A timestamp string. + :return: ``None`` + """ + return self._set_boundary_time(_lib.X509_getm_notBefore, when) + + def get_notAfter(self) -> bytes | None: + """ + Get the timestamp at which the certificate stops being valid. + + The timestamp is formatted as an ASN.1 TIME:: + + YYYYMMDDhhmmssZ + + :return: A timestamp string, or ``None`` if there is none. + :rtype: bytes or NoneType + """ + return self._get_boundary_time(_lib.X509_getm_notAfter) + + def set_notAfter(self, when: bytes) -> None: + """ + Set the timestamp at which the certificate stops being valid. + + The timestamp is formatted as an ASN.1 TIME:: + + YYYYMMDDhhmmssZ + + :param bytes when: A timestamp string. + :return: ``None`` + """ + return self._set_boundary_time(_lib.X509_getm_notAfter, when) + + def _get_name(self, which: Any) -> X509Name: + name = X509Name.__new__(X509Name) + name._name = which(self._x509) + _openssl_assert(name._name != _ffi.NULL) + + # The name is owned by the X509 structure. As long as the X509Name + # Python object is alive, keep the X509 Python object alive. + name._owner = self + + return name + + def _set_name(self, which: Any, name: X509Name) -> None: + if not isinstance(name, X509Name): + raise TypeError("name must be an X509Name") + set_result = which(self._x509, name._name) + _openssl_assert(set_result == 1) + + def get_issuer(self) -> X509Name: + """ + Return the issuer of this certificate. + + This creates a new :class:`X509Name` that wraps the underlying issuer + name field on the certificate. Modifying it will modify the underlying + certificate, and will have the effect of modifying any other + :class:`X509Name` that refers to this issuer. + + :return: The issuer of this certificate. + :rtype: :class:`X509Name` + """ + name = self._get_name(_lib.X509_get_issuer_name) + self._issuer_invalidator.add(name) + return name + + def set_issuer(self, issuer: X509Name) -> None: + """ + Set the issuer of this certificate. + + :param issuer: The issuer. + :type issuer: :py:class:`X509Name` + + :return: ``None`` + """ + self._set_name(_lib.X509_set_issuer_name, issuer) + self._issuer_invalidator.clear() + + def get_subject(self) -> X509Name: + """ + Return the subject of this certificate. + + This creates a new :class:`X509Name` that wraps the underlying subject + name field on the certificate. Modifying it will modify the underlying + certificate, and will have the effect of modifying any other + :class:`X509Name` that refers to this subject. + + :return: The subject of this certificate. + :rtype: :class:`X509Name` + """ + name = self._get_name(_lib.X509_get_subject_name) + self._subject_invalidator.add(name) + return name + + def set_subject(self, subject: X509Name) -> None: + """ + Set the subject of this certificate. + + :param subject: The subject. + :type subject: :py:class:`X509Name` + + :return: ``None`` + """ + self._set_name(_lib.X509_set_subject_name, subject) + self._subject_invalidator.clear() + + def get_extension_count(self) -> int: + """ + Get the number of extensions on this certificate. + + :return: The number of extensions. + :rtype: :py:class:`int` + + .. versionadded:: 0.12 + """ + return _lib.X509_get_ext_count(self._x509) + + def add_extensions(self, extensions: Iterable[X509Extension]) -> None: + """ + Add extensions to the certificate. + + :param extensions: The extensions to add. + :type extensions: An iterable of :py:class:`X509Extension` objects. + :return: ``None`` + """ + warnings.warn( + ( + "This API is deprecated and will be removed in a future " + "version of pyOpenSSL. You should use pyca/cryptography's " + "X.509 APIs instead." + ), + DeprecationWarning, + stacklevel=2, + ) + + for ext in extensions: + if not isinstance(ext, X509Extension): + raise ValueError("One of the elements is not an X509Extension") + + add_result = _lib.X509_add_ext(self._x509, ext._extension, -1) + _openssl_assert(add_result == 1) + + def get_extension(self, index: int) -> X509Extension: + """ + Get a specific extension of the certificate by index. + + Extensions on a certificate are kept in order. The index + parameter selects which extension will be returned. + + :param int index: The index of the extension to retrieve. + :return: The extension at the specified index. + :rtype: :py:class:`X509Extension` + :raises IndexError: If the extension index was out of bounds. + + .. versionadded:: 0.12 + """ + warnings.warn( + ( + "This API is deprecated and will be removed in a future " + "version of pyOpenSSL. You should use pyca/cryptography's " + "X.509 APIs instead." + ), + DeprecationWarning, + stacklevel=2, + ) + + ext = X509Extension.__new__(X509Extension) + ext._extension = _lib.X509_get_ext(self._x509, index) + if ext._extension == _ffi.NULL: + raise IndexError("extension index out of bounds") + + extension = _lib.X509_EXTENSION_dup(ext._extension) + ext._extension = _ffi.gc(extension, _lib.X509_EXTENSION_free) + return ext + + +class X509StoreFlags: + """ + Flags for X509 verification, used to change the behavior of + :class:`X509Store`. + + See `OpenSSL Verification Flags`_ for details. + + .. _OpenSSL Verification Flags: + https://www.openssl.org/docs/manmaster/man3/X509_VERIFY_PARAM_set_flags.html + """ + + CRL_CHECK: int = _lib.X509_V_FLAG_CRL_CHECK + CRL_CHECK_ALL: int = _lib.X509_V_FLAG_CRL_CHECK_ALL + IGNORE_CRITICAL: int = _lib.X509_V_FLAG_IGNORE_CRITICAL + X509_STRICT: int = _lib.X509_V_FLAG_X509_STRICT + ALLOW_PROXY_CERTS: int = _lib.X509_V_FLAG_ALLOW_PROXY_CERTS + POLICY_CHECK: int = _lib.X509_V_FLAG_POLICY_CHECK + EXPLICIT_POLICY: int = _lib.X509_V_FLAG_EXPLICIT_POLICY + INHIBIT_MAP: int = _lib.X509_V_FLAG_INHIBIT_MAP + CHECK_SS_SIGNATURE: int = _lib.X509_V_FLAG_CHECK_SS_SIGNATURE + PARTIAL_CHAIN: int = _lib.X509_V_FLAG_PARTIAL_CHAIN + + +class X509Store: + """ + An X.509 store. + + An X.509 store is used to describe a context in which to verify a + certificate. A description of a context may include a set of certificates + to trust, a set of certificate revocation lists, verification flags and + more. + + An X.509 store, being only a description, cannot be used by itself to + verify a certificate. To carry out the actual verification process, see + :class:`X509StoreContext`. + """ + + def __init__(self) -> None: + store = _lib.X509_STORE_new() + self._store = _ffi.gc(store, _lib.X509_STORE_free) + + def add_cert(self, cert: X509) -> None: + """ + Adds a trusted certificate to this store. + + Adding a certificate with this method adds this certificate as a + *trusted* certificate. + + :param X509 cert: The certificate to add to this store. + + :raises TypeError: If the certificate is not an :class:`X509`. + + :raises OpenSSL.crypto.Error: If OpenSSL was unhappy with your + certificate. + + :return: ``None`` if the certificate was added successfully. + """ + if not isinstance(cert, X509): + raise TypeError() + + res = _lib.X509_STORE_add_cert(self._store, cert._x509) + _openssl_assert(res == 1) + + def add_crl(self, crl: x509.CertificateRevocationList) -> None: + """ + Add a certificate revocation list to this store. + + The certificate revocation lists added to a store will only be used if + the associated flags are configured to check certificate revocation + lists. + + .. versionadded:: 16.1.0 + + :param crl: The certificate revocation list to add to this store. + :type crl: ``cryptography.x509.CertificateRevocationList`` + :return: ``None`` if the certificate revocation list was added + successfully. + """ + if isinstance(crl, x509.CertificateRevocationList): + from cryptography.hazmat.primitives.serialization import Encoding + + bio = _new_mem_buf(crl.public_bytes(Encoding.DER)) + openssl_crl = _lib.d2i_X509_CRL_bio(bio, _ffi.NULL) + _openssl_assert(openssl_crl != _ffi.NULL) + crl = _ffi.gc(openssl_crl, _lib.X509_CRL_free) + else: + raise TypeError( + "CRL must be of type " + "cryptography.x509.CertificateRevocationList" + ) + + _openssl_assert(_lib.X509_STORE_add_crl(self._store, crl) != 0) + + def set_flags(self, flags: int) -> None: + """ + Set verification flags to this store. + + Verification flags can be combined by oring them together. + + .. note:: + + Setting a verification flag sometimes requires clients to add + additional information to the store, otherwise a suitable error will + be raised. + + For example, in setting flags to enable CRL checking a + suitable CRL must be added to the store otherwise an error will be + raised. + + .. versionadded:: 16.1.0 + + :param int flags: The verification flags to set on this store. + See :class:`X509StoreFlags` for available constants. + :return: ``None`` if the verification flags were successfully set. + """ + _openssl_assert(_lib.X509_STORE_set_flags(self._store, flags) != 0) + + def set_time(self, vfy_time: datetime.datetime) -> None: + """ + Set the time against which the certificates are verified. + + Normally the current time is used. + + .. note:: + + For example, you can determine if a certificate was valid at a given + time. + + .. versionadded:: 17.0.0 + + :param datetime vfy_time: The verification time to set on this store. + :return: ``None`` if the verification time was successfully set. + """ + param = _lib.X509_VERIFY_PARAM_new() + param = _ffi.gc(param, _lib.X509_VERIFY_PARAM_free) + + _lib.X509_VERIFY_PARAM_set_time( + param, calendar.timegm(vfy_time.timetuple()) + ) + _openssl_assert(_lib.X509_STORE_set1_param(self._store, param) != 0) + + def load_locations( + self, + cafile: StrOrBytesPath | None, + capath: StrOrBytesPath | None = None, + ) -> None: + """ + Let X509Store know where we can find trusted certificates for the + certificate chain. Note that the certificates have to be in PEM + format. + + If *capath* is passed, it must be a directory prepared using the + ``c_rehash`` tool included with OpenSSL. Either, but not both, of + *cafile* or *capath* may be ``None``. + + .. note:: + + Both *cafile* and *capath* may be set simultaneously. + + Call this method multiple times to add more than one location. + For example, CA certificates, and certificate revocation list bundles + may be passed in *cafile* in subsequent calls to this method. + + .. versionadded:: 20.0 + + :param cafile: In which file we can find the certificates (``bytes`` or + ``unicode``). + :param capath: In which directory we can find the certificates + (``bytes`` or ``unicode``). + + :return: ``None`` if the locations were set successfully. + + :raises OpenSSL.crypto.Error: If both *cafile* and *capath* is ``None`` + or the locations could not be set for any reason. + + """ + if cafile is None: + cafile = _ffi.NULL + else: + cafile = _path_bytes(cafile) + + if capath is None: + capath = _ffi.NULL + else: + capath = _path_bytes(capath) + + load_result = _lib.X509_STORE_load_locations( + self._store, cafile, capath + ) + if not load_result: + _raise_current_error() + + +class X509StoreContextError(Exception): + """ + An exception raised when an error occurred while verifying a certificate + using `OpenSSL.X509StoreContext.verify_certificate`. + + :ivar certificate: The certificate which caused verificate failure. + :type certificate: :class:`X509` + """ + + def __init__( + self, message: str, errors: list[Any], certificate: X509 + ) -> None: + super().__init__(message) + self.errors = errors + self.certificate = certificate + + +class X509StoreContext: + """ + An X.509 store context. + + An X.509 store context is used to carry out the actual verification process + of a certificate in a described context. For describing such a context, see + :class:`X509Store`. + + :param X509Store store: The certificates which will be trusted for the + purposes of any verifications. + :param X509 certificate: The certificate to be verified. + :param chain: List of untrusted certificates that may be used for building + the certificate chain. May be ``None``. + :type chain: :class:`list` of :class:`X509` + """ + + def __init__( + self, + store: X509Store, + certificate: X509, + chain: Sequence[X509] | None = None, + ) -> None: + self._store = store + self._cert = certificate + self._chain = self._build_certificate_stack(chain) + + @staticmethod + def _build_certificate_stack( + certificates: Sequence[X509] | None, + ) -> None: + def cleanup(s: Any) -> None: + # Equivalent to sk_X509_pop_free, but we don't + # currently have a CFFI binding for that available + for i in range(_lib.sk_X509_num(s)): + x = _lib.sk_X509_value(s, i) + _lib.X509_free(x) + _lib.sk_X509_free(s) + + if certificates is None or len(certificates) == 0: + return _ffi.NULL + + stack = _lib.sk_X509_new_null() + _openssl_assert(stack != _ffi.NULL) + stack = _ffi.gc(stack, cleanup) + + for cert in certificates: + if not isinstance(cert, X509): + raise TypeError("One of the elements is not an X509 instance") + + _openssl_assert(_lib.X509_up_ref(cert._x509) > 0) + if _lib.sk_X509_push(stack, cert._x509) <= 0: + _lib.X509_free(cert._x509) + _raise_current_error() + + return stack + + @staticmethod + def _exception_from_context(store_ctx: Any) -> X509StoreContextError: + """ + Convert an OpenSSL native context error failure into a Python + exception. + + When a call to native OpenSSL X509_verify_cert fails, additional + information about the failure can be obtained from the store context. + """ + message = _ffi.string( + _lib.X509_verify_cert_error_string( + _lib.X509_STORE_CTX_get_error(store_ctx) + ) + ).decode("utf-8") + errors = [ + _lib.X509_STORE_CTX_get_error(store_ctx), + _lib.X509_STORE_CTX_get_error_depth(store_ctx), + message, + ] + # A context error should always be associated with a certificate, so we + # expect this call to never return :class:`None`. + _x509 = _lib.X509_STORE_CTX_get_current_cert(store_ctx) + _cert = _lib.X509_dup(_x509) + pycert = X509._from_raw_x509_ptr(_cert) + return X509StoreContextError(message, errors, pycert) + + def _verify_certificate(self) -> Any: + """ + Verifies the certificate and runs an X509_STORE_CTX containing the + results. + + :raises X509StoreContextError: If an error occurred when validating a + certificate in the context. Sets ``certificate`` attribute to + indicate which certificate caused the error. + """ + store_ctx = _lib.X509_STORE_CTX_new() + _openssl_assert(store_ctx != _ffi.NULL) + store_ctx = _ffi.gc(store_ctx, _lib.X509_STORE_CTX_free) + + ret = _lib.X509_STORE_CTX_init( + store_ctx, self._store._store, self._cert._x509, self._chain + ) + _openssl_assert(ret == 1) + + ret = _lib.X509_verify_cert(store_ctx) + if ret <= 0: + raise self._exception_from_context(store_ctx) + + return store_ctx + + def set_store(self, store: X509Store) -> None: + """ + Set the context's X.509 store. + + .. versionadded:: 0.15 + + :param X509Store store: The store description which will be used for + the purposes of any *future* verifications. + """ + self._store = store + + def verify_certificate(self) -> None: + """ + Verify a certificate in a context. + + .. versionadded:: 0.15 + + :raises X509StoreContextError: If an error occurred when validating a + certificate in the context. Sets ``certificate`` attribute to + indicate which certificate caused the error. + """ + self._verify_certificate() + + def get_verified_chain(self) -> list[X509]: + """ + Verify a certificate in a context and return the complete validated + chain. + + :raises X509StoreContextError: If an error occurred when validating a + certificate in the context. Sets ``certificate`` attribute to + indicate which certificate caused the error. + + .. versionadded:: 20.0 + """ + store_ctx = self._verify_certificate() + + # Note: X509_STORE_CTX_get1_chain returns a deep copy of the chain. + cert_stack = _lib.X509_STORE_CTX_get1_chain(store_ctx) + _openssl_assert(cert_stack != _ffi.NULL) + + result = [] + for i in range(_lib.sk_X509_num(cert_stack)): + cert = _lib.sk_X509_value(cert_stack, i) + _openssl_assert(cert != _ffi.NULL) + pycert = X509._from_raw_x509_ptr(cert) + result.append(pycert) + + # Free the stack but not the members which are freed by the X509 class. + _lib.sk_X509_free(cert_stack) + return result + + +def load_certificate(type: int, buffer: bytes) -> X509: + """ + Load a certificate (X509) from the string *buffer* encoded with the + type *type*. + + :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1) + + :param bytes buffer: The buffer the certificate is stored in + + :return: The X509 object + """ + if isinstance(buffer, str): + buffer = buffer.encode("ascii") + + bio = _new_mem_buf(buffer) + + if type == FILETYPE_PEM: + x509 = _lib.PEM_read_bio_X509(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL) + elif type == FILETYPE_ASN1: + x509 = _lib.d2i_X509_bio(bio, _ffi.NULL) + else: + raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1") + + if x509 == _ffi.NULL: + _raise_current_error() + + return X509._from_raw_x509_ptr(x509) + + +def dump_certificate(type: int, cert: X509) -> bytes: + """ + Dump the certificate *cert* into a buffer string encoded with the type + *type*. + + :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1, or + FILETYPE_TEXT) + :param cert: The certificate to dump + :return: The buffer with the dumped certificate in + """ + bio = _new_mem_buf() + + if type == FILETYPE_PEM: + result_code = _lib.PEM_write_bio_X509(bio, cert._x509) + elif type == FILETYPE_ASN1: + result_code = _lib.i2d_X509_bio(bio, cert._x509) + elif type == FILETYPE_TEXT: + result_code = _lib.X509_print_ex(bio, cert._x509, 0, 0) + else: + raise ValueError( + "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or " + "FILETYPE_TEXT" + ) + + _openssl_assert(result_code == 1) + return _bio_to_string(bio) + + +def dump_publickey(type: int, pkey: PKey) -> bytes: + """ + Dump a public key to a buffer. + + :param type: The file type (one of :data:`FILETYPE_PEM` or + :data:`FILETYPE_ASN1`). + :param PKey pkey: The public key to dump + :return: The buffer with the dumped key in it. + :rtype: bytes + """ + bio = _new_mem_buf() + if type == FILETYPE_PEM: + write_bio = _lib.PEM_write_bio_PUBKEY + elif type == FILETYPE_ASN1: + write_bio = _lib.i2d_PUBKEY_bio + else: + raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1") + + result_code = write_bio(bio, pkey._pkey) + if result_code != 1: # pragma: no cover + _raise_current_error() + + return _bio_to_string(bio) + + +def dump_privatekey( + type: int, + pkey: PKey, + cipher: str | None = None, + passphrase: PassphraseCallableT | None = None, +) -> bytes: + """ + Dump the private key *pkey* into a buffer string encoded with the type + *type*. Optionally (if *type* is :const:`FILETYPE_PEM`) encrypting it + using *cipher* and *passphrase*. + + :param type: The file type (one of :const:`FILETYPE_PEM`, + :const:`FILETYPE_ASN1`, or :const:`FILETYPE_TEXT`) + :param PKey pkey: The PKey to dump + :param cipher: (optional) if encrypted PEM format, the cipher to use + :param passphrase: (optional) if encrypted PEM format, this can be either + the passphrase to use, or a callback for providing the passphrase. + + :return: The buffer with the dumped key in + :rtype: bytes + """ + bio = _new_mem_buf() + + if not isinstance(pkey, PKey): + raise TypeError("pkey must be a PKey") + + if cipher is not None: + if passphrase is None: + raise TypeError( + "if a value is given for cipher " + "one must also be given for passphrase" + ) + cipher_obj = _lib.EVP_get_cipherbyname(_byte_string(cipher)) + if cipher_obj == _ffi.NULL: + raise ValueError("Invalid cipher name") + else: + cipher_obj = _ffi.NULL + + helper = _PassphraseHelper(type, passphrase) + if type == FILETYPE_PEM: + result_code = _lib.PEM_write_bio_PrivateKey( + bio, + pkey._pkey, + cipher_obj, + _ffi.NULL, + 0, + helper.callback, + helper.callback_args, + ) + helper.raise_if_problem() + elif type == FILETYPE_ASN1: + result_code = _lib.i2d_PrivateKey_bio(bio, pkey._pkey) + elif type == FILETYPE_TEXT: + if _lib.EVP_PKEY_id(pkey._pkey) != _lib.EVP_PKEY_RSA: + raise TypeError("Only RSA keys are supported for FILETYPE_TEXT") + + rsa = _ffi.gc(_lib.EVP_PKEY_get1_RSA(pkey._pkey), _lib.RSA_free) + result_code = _lib.RSA_print(bio, rsa, 0) + else: + raise ValueError( + "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or " + "FILETYPE_TEXT" + ) + + _openssl_assert(result_code != 0) + + return _bio_to_string(bio) + + +class _PassphraseHelper: + def __init__( + self, + type: int, + passphrase: PassphraseCallableT | None, + more_args: bool = False, + truncate: bool = False, + ) -> None: + if type != FILETYPE_PEM and passphrase is not None: + raise ValueError( + "only FILETYPE_PEM key format supports encryption" + ) + self._passphrase = passphrase + self._more_args = more_args + self._truncate = truncate + self._problems: list[Exception] = [] + + @property + def callback(self) -> Any: + if self._passphrase is None: + return _ffi.NULL + elif isinstance(self._passphrase, bytes) or callable(self._passphrase): + return _ffi.callback("pem_password_cb", self._read_passphrase) + else: + raise TypeError( + "Last argument must be a byte string or a callable." + ) + + @property + def callback_args(self) -> Any: + if self._passphrase is None: + return _ffi.NULL + elif isinstance(self._passphrase, bytes) or callable(self._passphrase): + return _ffi.NULL + else: + raise TypeError( + "Last argument must be a byte string or a callable." + ) + + def raise_if_problem(self, exceptionType: type[Exception] = Error) -> None: + if self._problems: + # Flush the OpenSSL error queue + try: + _exception_from_error_queue(exceptionType) + except exceptionType: + pass + + raise self._problems.pop(0) + + def _read_passphrase( + self, buf: Any, size: int, rwflag: Any, userdata: Any + ) -> int: + try: + if callable(self._passphrase): + if self._more_args: + result = self._passphrase(size, rwflag, userdata) + else: + result = self._passphrase(rwflag) + else: + assert self._passphrase is not None + result = self._passphrase + if not isinstance(result, bytes): + raise ValueError("Bytes expected") + if len(result) > size: + if self._truncate: + result = result[:size] + else: + raise ValueError( + "passphrase returned by callback is too long" + ) + for i in range(len(result)): + buf[i] = result[i : i + 1] + return len(result) + except Exception as e: + self._problems.append(e) + return 0 + + +def load_publickey(type: int, buffer: str | bytes) -> PKey: + """ + Load a public key from a buffer. + + :param type: The file type (one of :data:`FILETYPE_PEM`, + :data:`FILETYPE_ASN1`). + :param buffer: The buffer the key is stored in. + :type buffer: A Python string object, either unicode or bytestring. + :return: The PKey object. + :rtype: :class:`PKey` + """ + if isinstance(buffer, str): + buffer = buffer.encode("ascii") + + bio = _new_mem_buf(buffer) + + if type == FILETYPE_PEM: + evp_pkey = _lib.PEM_read_bio_PUBKEY( + bio, _ffi.NULL, _ffi.NULL, _ffi.NULL + ) + elif type == FILETYPE_ASN1: + evp_pkey = _lib.d2i_PUBKEY_bio(bio, _ffi.NULL) + else: + raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1") + + if evp_pkey == _ffi.NULL: + _raise_current_error() + + pkey = PKey.__new__(PKey) + pkey._pkey = _ffi.gc(evp_pkey, _lib.EVP_PKEY_free) + pkey._only_public = True + return pkey + + +def load_privatekey( + type: int, + buffer: str | bytes, + passphrase: PassphraseCallableT | None = None, +) -> PKey: + """ + Load a private key (PKey) from the string *buffer* encoded with the type + *type*. + + :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1) + :param buffer: The buffer the key is stored in + :param passphrase: (optional) if encrypted PEM format, this can be + either the passphrase to use, or a callback for + providing the passphrase. + + :return: The PKey object + """ + if isinstance(buffer, str): + buffer = buffer.encode("ascii") + + bio = _new_mem_buf(buffer) + + helper = _PassphraseHelper(type, passphrase) + if type == FILETYPE_PEM: + evp_pkey = _lib.PEM_read_bio_PrivateKey( + bio, _ffi.NULL, helper.callback, helper.callback_args + ) + helper.raise_if_problem() + elif type == FILETYPE_ASN1: + evp_pkey = _lib.d2i_PrivateKey_bio(bio, _ffi.NULL) + else: + raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1") + + if evp_pkey == _ffi.NULL: + _raise_current_error() + + pkey = PKey.__new__(PKey) + pkey._pkey = _ffi.gc(evp_pkey, _lib.EVP_PKEY_free) + return pkey + + +def dump_certificate_request(type: int, req: X509Req) -> bytes: + """ + Dump the certificate request *req* into a buffer string encoded with the + type *type*. + + :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1) + :param req: The certificate request to dump + :return: The buffer with the dumped certificate request in + + + .. deprecated:: 24.2.0 + Use `cryptography.x509.CertificateSigningRequest` instead. + """ + bio = _new_mem_buf() + + if type == FILETYPE_PEM: + result_code = _lib.PEM_write_bio_X509_REQ(bio, req._req) + elif type == FILETYPE_ASN1: + result_code = _lib.i2d_X509_REQ_bio(bio, req._req) + elif type == FILETYPE_TEXT: + result_code = _lib.X509_REQ_print_ex(bio, req._req, 0, 0) + else: + raise ValueError( + "type argument must be FILETYPE_PEM, FILETYPE_ASN1, or " + "FILETYPE_TEXT" + ) + + _openssl_assert(result_code != 0) + + return _bio_to_string(bio) + + +_dump_certificate_request_internal = dump_certificate_request + +utils.deprecated( + dump_certificate_request, + __name__, + ( + "CSR support in pyOpenSSL is deprecated. You should use the APIs " + "in cryptography." + ), + DeprecationWarning, + name="dump_certificate_request", +) + + +def load_certificate_request(type: int, buffer: bytes) -> X509Req: + """ + Load a certificate request (X509Req) from the string *buffer* encoded with + the type *type*. + + :param type: The file type (one of FILETYPE_PEM, FILETYPE_ASN1) + :param buffer: The buffer the certificate request is stored in + :return: The X509Req object + + .. deprecated:: 24.2.0 + Use `cryptography.x509.load_der_x509_csr` or + `cryptography.x509.load_pem_x509_csr` instead. + """ + if isinstance(buffer, str): + buffer = buffer.encode("ascii") + + bio = _new_mem_buf(buffer) + + if type == FILETYPE_PEM: + req = _lib.PEM_read_bio_X509_REQ(bio, _ffi.NULL, _ffi.NULL, _ffi.NULL) + elif type == FILETYPE_ASN1: + req = _lib.d2i_X509_REQ_bio(bio, _ffi.NULL) + else: + raise ValueError("type argument must be FILETYPE_PEM or FILETYPE_ASN1") + + _openssl_assert(req != _ffi.NULL) + + x509req = X509Req.__new__(X509Req) + x509req._req = _ffi.gc(req, _lib.X509_REQ_free) + return x509req + + +_load_certificate_request_internal = load_certificate_request + +utils.deprecated( + load_certificate_request, + __name__, + ( + "CSR support in pyOpenSSL is deprecated. You should use the APIs " + "in cryptography." + ), + DeprecationWarning, + name="load_certificate_request", +) diff --git a/venv/Lib/site-packages/OpenSSL/debug.py b/venv/Lib/site-packages/OpenSSL/debug.py new file mode 100644 index 0000000..e0ed3f8 --- /dev/null +++ b/venv/Lib/site-packages/OpenSSL/debug.py @@ -0,0 +1,40 @@ +import ssl +import sys + +import cffi +import cryptography + +import OpenSSL.SSL + +from . import version + +_env_info = """\ +pyOpenSSL: {pyopenssl} +cryptography: {cryptography} +cffi: {cffi} +cryptography's compiled against OpenSSL: {crypto_openssl_compile} +cryptography's linked OpenSSL: {crypto_openssl_link} +Python's OpenSSL: {python_openssl} +Python executable: {python} +Python version: {python_version} +Platform: {platform} +sys.path: {sys_path}""".format( + pyopenssl=version.__version__, + crypto_openssl_compile=OpenSSL._util.ffi.string( + OpenSSL._util.lib.OPENSSL_VERSION_TEXT, + ).decode("ascii"), + crypto_openssl_link=OpenSSL.SSL.SSLeay_version( + OpenSSL.SSL.SSLEAY_VERSION + ).decode("ascii"), + python_openssl=getattr(ssl, "OPENSSL_VERSION", "n/a"), + cryptography=cryptography.__version__, + cffi=cffi.__version__, + python=sys.executable, + python_version=sys.version, + platform=sys.platform, + sys_path=sys.path, +) + + +if __name__ == "__main__": + print(_env_info) diff --git a/venv/Lib/site-packages/OpenSSL/py.typed b/venv/Lib/site-packages/OpenSSL/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/venv/Lib/site-packages/OpenSSL/rand.py b/venv/Lib/site-packages/OpenSSL/rand.py new file mode 100644 index 0000000..e57425f --- /dev/null +++ b/venv/Lib/site-packages/OpenSSL/rand.py @@ -0,0 +1,50 @@ +""" +PRNG management routines, thin wrappers. +""" + +from __future__ import annotations + +import warnings + +from OpenSSL._util import lib as _lib + +warnings.warn( + "OpenSSL.rand is deprecated - you should use os.urandom instead", + DeprecationWarning, + stacklevel=3, +) + + +def add(buffer: bytes, entropy: int) -> None: + """ + Mix bytes from *string* into the PRNG state. + + The *entropy* argument is (the lower bound of) an estimate of how much + randomness is contained in *string*, measured in bytes. + + For more information, see e.g. :rfc:`1750`. + + This function is only relevant if you are forking Python processes and + need to reseed the CSPRNG after fork. + + :param buffer: Buffer with random data. + :param entropy: The entropy (in bytes) measurement of the buffer. + + :return: :obj:`None` + """ + if not isinstance(buffer, bytes): + raise TypeError("buffer must be a byte string") + + if not isinstance(entropy, int): + raise TypeError("entropy must be an integer") + + _lib.RAND_add(buffer, len(buffer), entropy) + + +def status() -> int: + """ + Check whether the PRNG has been seeded with enough data. + + :return: 1 if the PRNG is seeded enough, 0 otherwise. + """ + return _lib.RAND_status() diff --git a/venv/Lib/site-packages/OpenSSL/version.py b/venv/Lib/site-packages/OpenSSL/version.py new file mode 100644 index 0000000..c49055e --- /dev/null +++ b/venv/Lib/site-packages/OpenSSL/version.py @@ -0,0 +1,28 @@ +# Copyright (C) AB Strakt +# Copyright (C) Jean-Paul Calderone +# See LICENSE for details. + +""" +pyOpenSSL - A simple wrapper around the OpenSSL library +""" + +__all__ = [ + "__author__", + "__copyright__", + "__email__", + "__license__", + "__summary__", + "__title__", + "__uri__", + "__version__", +] + +__version__ = "25.3.0" + +__title__ = "pyOpenSSL" +__uri__ = "https://pyopenssl.org/" +__summary__ = "Python wrapper module around the OpenSSL library" +__author__ = "The pyOpenSSL developers" +__email__ = "cryptography-dev@python.org" +__license__ = "Apache License, Version 2.0" +__copyright__ = f"Copyright 2001-2025 {__author__}" diff --git a/venv/Lib/site-packages/PIL/AvifImagePlugin.py b/venv/Lib/site-packages/PIL/AvifImagePlugin.py deleted file mode 100644 index 43c39a9..0000000 --- a/venv/Lib/site-packages/PIL/AvifImagePlugin.py +++ /dev/null @@ -1,293 +0,0 @@ -from __future__ import annotations - -import os -from io import BytesIO -from typing import IO - -from . import ExifTags, Image, ImageFile - -try: - from . import _avif - - SUPPORTED = True -except ImportError: - SUPPORTED = False - -# Decoder options as module globals, until there is a way to pass parameters -# to Image.open (see https://github.com/python-pillow/Pillow/issues/569) -DECODE_CODEC_CHOICE = "auto" -DEFAULT_MAX_THREADS = 0 - - -def get_codec_version(codec_name: str) -> str | None: - versions = _avif.codec_versions() - for version in versions.split(", "): - if version.split(" [")[0] == codec_name: - return version.split(":")[-1].split(" ")[0] - return None - - -def _accept(prefix: bytes) -> bool | str: - if prefix[4:8] != b"ftyp": - return False - major_brand = prefix[8:12] - if major_brand in ( - # coding brands - b"avif", - b"avis", - # We accept files with AVIF container brands; we can't yet know if - # the ftyp box has the correct compatible brands, but if it doesn't - # then the plugin will raise a SyntaxError which Pillow will catch - # before moving on to the next plugin that accepts the file. - # - # Also, because this file might not actually be an AVIF file, we - # don't raise an error if AVIF support isn't properly compiled. - b"mif1", - b"msf1", - ): - if not SUPPORTED: - return ( - "image file could not be identified because AVIF support not installed" - ) - return True - return False - - -def _get_default_max_threads() -> int: - if DEFAULT_MAX_THREADS: - return DEFAULT_MAX_THREADS - if hasattr(os, "sched_getaffinity"): - return len(os.sched_getaffinity(0)) - else: - return os.cpu_count() or 1 - - -class AvifImageFile(ImageFile.ImageFile): - format = "AVIF" - format_description = "AVIF image" - __frame = -1 - - def _open(self) -> None: - if not SUPPORTED: - msg = "image file could not be opened because AVIF support not installed" - raise SyntaxError(msg) - - if DECODE_CODEC_CHOICE != "auto" and not _avif.decoder_codec_available( - DECODE_CODEC_CHOICE - ): - msg = "Invalid opening codec" - raise ValueError(msg) - - assert self.fp is not None - self._decoder = _avif.AvifDecoder( - self.fp.read(), - DECODE_CODEC_CHOICE, - _get_default_max_threads(), - ) - - # Get info from decoder - self._size, self.n_frames, self._mode, icc, exif, exif_orientation, xmp = ( - self._decoder.get_info() - ) - self.is_animated = self.n_frames > 1 - - if icc: - self.info["icc_profile"] = icc - if xmp: - self.info["xmp"] = xmp - - if exif_orientation != 1 or exif: - exif_data = Image.Exif() - if exif: - exif_data.load(exif) - original_orientation = exif_data.get(ExifTags.Base.Orientation, 1) - else: - original_orientation = 1 - if exif_orientation != original_orientation: - exif_data[ExifTags.Base.Orientation] = exif_orientation - exif = exif_data.tobytes() - if exif: - self.info["exif"] = exif - self.seek(0) - - def seek(self, frame: int) -> None: - if not self._seek_check(frame): - return - - # Set tile - self.__frame = frame - self.tile = [ImageFile._Tile("raw", (0, 0) + self.size, 0, self.mode)] - - def load(self) -> Image.core.PixelAccess | None: - if self.tile: - # We need to load the image data for this frame - data, timescale, pts_in_timescales, duration_in_timescales = ( - self._decoder.get_frame(self.__frame) - ) - self.info["timestamp"] = round(1000 * (pts_in_timescales / timescale)) - self.info["duration"] = round(1000 * (duration_in_timescales / timescale)) - - if self.fp and self._exclusive_fp: - self.fp.close() - self.fp = BytesIO(data) - - return super().load() - - def load_seek(self, pos: int) -> None: - pass - - def tell(self) -> int: - return self.__frame - - -def _save_all(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: - _save(im, fp, filename, save_all=True) - - -def _save( - im: Image.Image, fp: IO[bytes], filename: str | bytes, save_all: bool = False -) -> None: - info = im.encoderinfo.copy() - if save_all: - append_images = list(info.get("append_images", [])) - else: - append_images = [] - - total = 0 - for ims in [im] + append_images: - total += getattr(ims, "n_frames", 1) - - quality = info.get("quality", 75) - if not isinstance(quality, int) or quality < 0 or quality > 100: - msg = "Invalid quality setting" - raise ValueError(msg) - - duration = info.get("duration", 0) - subsampling = info.get("subsampling", "4:2:0") - speed = info.get("speed", 6) - max_threads = info.get("max_threads", _get_default_max_threads()) - codec = info.get("codec", "auto") - if codec != "auto" and not _avif.encoder_codec_available(codec): - msg = "Invalid saving codec" - raise ValueError(msg) - range_ = info.get("range", "full") - tile_rows_log2 = info.get("tile_rows", 0) - tile_cols_log2 = info.get("tile_cols", 0) - alpha_premultiplied = bool(info.get("alpha_premultiplied", False)) - autotiling = bool(info.get("autotiling", tile_rows_log2 == tile_cols_log2 == 0)) - - icc_profile = info.get("icc_profile", im.info.get("icc_profile")) - exif_orientation = 1 - if exif := info.get("exif"): - if isinstance(exif, Image.Exif): - exif_data = exif - else: - exif_data = Image.Exif() - exif_data.load(exif) - if ExifTags.Base.Orientation in exif_data: - exif_orientation = exif_data.pop(ExifTags.Base.Orientation) - exif = exif_data.tobytes() if exif_data else b"" - elif isinstance(exif, Image.Exif): - exif = exif_data.tobytes() - - xmp = info.get("xmp") - - if isinstance(xmp, str): - xmp = xmp.encode("utf-8") - - advanced = info.get("advanced") - if advanced is not None: - if isinstance(advanced, dict): - advanced = advanced.items() - try: - advanced = tuple(advanced) - except TypeError: - invalid = True - else: - invalid = any(not isinstance(v, tuple) or len(v) != 2 for v in advanced) - if invalid: - msg = ( - "advanced codec options must be a dict of key-value string " - "pairs or a series of key-value two-tuples" - ) - raise ValueError(msg) - - # Setup the AVIF encoder - enc = _avif.AvifEncoder( - im.size, - subsampling, - quality, - speed, - max_threads, - codec, - range_, - tile_rows_log2, - tile_cols_log2, - alpha_premultiplied, - autotiling, - icc_profile or b"", - exif or b"", - exif_orientation, - xmp or b"", - advanced, - ) - - # Add each frame - frame_idx = 0 - frame_duration = 0 - cur_idx = im.tell() - is_single_frame = total == 1 - try: - for ims in [im] + append_images: - # Get number of frames in this image - nfr = getattr(ims, "n_frames", 1) - - for idx in range(nfr): - ims.seek(idx) - - # Make sure image mode is supported - frame = ims - rawmode = ims.mode - if ims.mode not in {"RGB", "RGBA"}: - rawmode = "RGBA" if ims.has_transparency_data else "RGB" - frame = ims.convert(rawmode) - - # Update frame duration - if isinstance(duration, (list, tuple)): - frame_duration = duration[frame_idx] - else: - frame_duration = duration - - # Append the frame to the animation encoder - enc.add( - frame.tobytes("raw", rawmode), - frame_duration, - frame.size, - rawmode, - is_single_frame, - ) - - # Update frame index - frame_idx += 1 - - if not save_all: - break - - finally: - im.seek(cur_idx) - - # Get the final output from the encoder - data = enc.finish() - if data is None: - msg = "cannot write file as AVIF (encoder returned None)" - raise OSError(msg) - - fp.write(data) - - -Image.register_open(AvifImageFile.format, AvifImageFile, _accept) -if SUPPORTED: - Image.register_save(AvifImageFile.format, _save) - Image.register_save_all(AvifImageFile.format, _save_all) - Image.register_extensions(AvifImageFile.format, [".avif", ".avifs"]) - Image.register_mime(AvifImageFile.format, "image/avif") diff --git a/venv/Lib/site-packages/PIL/BdfFontFile.py b/venv/Lib/site-packages/PIL/BdfFontFile.py index f175e2f..bc1416c 100644 --- a/venv/Lib/site-packages/PIL/BdfFontFile.py +++ b/venv/Lib/site-packages/PIL/BdfFontFile.py @@ -26,6 +26,17 @@ from typing import BinaryIO from . import FontFile, Image +bdf_slant = { + "R": "Roman", + "I": "Italic", + "O": "Oblique", + "RI": "Reverse Italic", + "RO": "Reverse Oblique", + "OT": "Other", +} + +bdf_spacing = {"P": "Proportional", "M": "Monospaced", "C": "Cell"} + def bdf_char( f: BinaryIO, @@ -43,7 +54,7 @@ def bdf_char( s = f.readline() if not s: return None - if s.startswith(b"STARTCHAR"): + if s[:9] == b"STARTCHAR": break id = s[9:].strip().decode("ascii") @@ -51,7 +62,7 @@ def bdf_char( props = {} while True: s = f.readline() - if not s or s.startswith(b"BITMAP"): + if not s or s[:6] == b"BITMAP": break i = s.find(b" ") props[s[:i].decode("ascii")] = s[i + 1 : -1].decode("ascii") @@ -60,7 +71,7 @@ def bdf_char( bitmap = bytearray() while True: s = f.readline() - if not s or s.startswith(b"ENDCHAR"): + if not s or s[:7] == b"ENDCHAR": break bitmap += s[:-1] @@ -96,7 +107,7 @@ class BdfFontFile(FontFile.FontFile): super().__init__() s = fp.readline() - if not s.startswith(b"STARTFONT 2.1"): + if s[:13] != b"STARTFONT 2.1": msg = "not a valid BDF file" raise SyntaxError(msg) @@ -105,7 +116,7 @@ class BdfFontFile(FontFile.FontFile): while True: s = fp.readline() - if not s or s.startswith(b"ENDPROPERTIES"): + if not s or s[:13] == b"ENDPROPERTIES": break i = s.find(b" ") props[s[:i].decode("ascii")] = s[i + 1 : -1].decode("ascii") diff --git a/venv/Lib/site-packages/PIL/BlpImagePlugin.py b/venv/Lib/site-packages/PIL/BlpImagePlugin.py index 6bb92ed..b9cefaf 100644 --- a/venv/Lib/site-packages/PIL/BlpImagePlugin.py +++ b/venv/Lib/site-packages/PIL/BlpImagePlugin.py @@ -246,7 +246,7 @@ class BLPFormatError(NotImplementedError): def _accept(prefix: bytes) -> bool: - return prefix.startswith((b"BLP1", b"BLP2")) + return prefix[:4] in (b"BLP1", b"BLP2") class BlpImageFile(ImageFile.ImageFile): @@ -258,46 +258,30 @@ class BlpImageFile(ImageFile.ImageFile): format_description = "Blizzard Mipmap Format" def _open(self) -> None: - assert self.fp is not None self.magic = self.fp.read(4) - if not _accept(self.magic): + + self.fp.seek(5, os.SEEK_CUR) + (self._blp_alpha_depth,) = struct.unpack(" tuple[int, int]: + def decode(self, buffer: bytes) -> tuple[int, int]: try: - self._read_header() + self._read_blp_header() self._load() except struct.error as e: msg = "Truncated BLP file" @@ -308,12 +292,27 @@ class _BLPBaseDecoder(abc.ABC, ImageFile.PyDecoder): def _load(self) -> None: pass - def _read_header(self) -> None: - self._offsets = struct.unpack("<16I", self._safe_read(16 * 4)) - self._lengths = struct.unpack("<16I", self._safe_read(16 * 4)) + def _read_blp_header(self) -> None: + assert self.fd is not None + self.fd.seek(4) + (self._blp_compression,) = struct.unpack(" bytes: - assert self.fd is not None return ImageFile._safe_read(self.fd, length) def _read_palette(self) -> list[tuple[int, int, int, int]]: @@ -326,11 +325,9 @@ class _BLPBaseDecoder(abc.ABC, ImageFile.PyDecoder): ret.append((b, g, r, a)) return ret - def _read_bgra( - self, palette: list[tuple[int, int, int, int]], alpha: bool - ) -> bytearray: + def _read_bgra(self, palette: list[tuple[int, int, int, int]]) -> bytearray: data = bytearray() - _data = BytesIO(self._safe_read(self._lengths[0])) + _data = BytesIO(self._safe_read(self._blp_lengths[0])) while True: try: (offset,) = struct.unpack(" None: - self._compression, self._encoding, alpha = self.args - - if self._compression == Format.JPEG: + if self._blp_compression == Format.JPEG: self._decode_jpeg_stream() - elif self._compression == 1: - if self._encoding in (4, 5): + elif self._blp_compression == 1: + if self._blp_encoding in (4, 5): palette = self._read_palette() - data = self._read_bgra(palette, alpha) + data = self._read_bgra(palette) self.set_as_raw(data) else: - msg = f"Unsupported BLP encoding {repr(self._encoding)}" + msg = f"Unsupported BLP encoding {repr(self._blp_encoding)}" raise BLPFormatError(msg) else: - msg = f"Unsupported BLP compression {repr(self._encoding)}" + msg = f"Unsupported BLP compression {repr(self._blp_encoding)}" raise BLPFormatError(msg) def _decode_jpeg_stream(self) -> None: @@ -369,61 +364,62 @@ class BLP1Decoder(_BLPBaseDecoder): (jpeg_header_size,) = struct.unpack(" None: - self._compression, self._encoding, alpha, self._alpha_encoding = self.args - palette = self._read_palette() assert self.fd is not None - self.fd.seek(self._offsets[0]) + self.fd.seek(self._blp_offsets[0]) - if self._compression == 1: + if self._blp_compression == 1: # Uncompressed or DirectX compression - if self._encoding == Encoding.UNCOMPRESSED: - data = self._read_bgra(palette, alpha) + if self._blp_encoding == Encoding.UNCOMPRESSED: + data = self._read_bgra(palette) - elif self._encoding == Encoding.DXT: + elif self._blp_encoding == Encoding.DXT: data = bytearray() - if self._alpha_encoding == AlphaEncoding.DXT1: - linesize = (self.state.xsize + 3) // 4 * 8 - for yb in range((self.state.ysize + 3) // 4): - for d in decode_dxt1(self._safe_read(linesize), alpha): + if self._blp_alpha_encoding == AlphaEncoding.DXT1: + linesize = (self.size[0] + 3) // 4 * 8 + for yb in range((self.size[1] + 3) // 4): + for d in decode_dxt1( + self._safe_read(linesize), alpha=bool(self._blp_alpha_depth) + ): data += d - elif self._alpha_encoding == AlphaEncoding.DXT3: - linesize = (self.state.xsize + 3) // 4 * 16 - for yb in range((self.state.ysize + 3) // 4): + elif self._blp_alpha_encoding == AlphaEncoding.DXT3: + linesize = (self.size[0] + 3) // 4 * 16 + for yb in range((self.size[1] + 3) // 4): for d in decode_dxt3(self._safe_read(linesize)): data += d - elif self._alpha_encoding == AlphaEncoding.DXT5: - linesize = (self.state.xsize + 3) // 4 * 16 - for yb in range((self.state.ysize + 3) // 4): + elif self._blp_alpha_encoding == AlphaEncoding.DXT5: + linesize = (self.size[0] + 3) // 4 * 16 + for yb in range((self.size[1] + 3) // 4): for d in decode_dxt5(self._safe_read(linesize)): data += d else: - msg = f"Unsupported alpha encoding {repr(self._alpha_encoding)}" + msg = f"Unsupported alpha encoding {repr(self._blp_alpha_encoding)}" raise BLPFormatError(msg) else: - msg = f"Unknown BLP encoding {repr(self._encoding)}" + msg = f"Unknown BLP encoding {repr(self._blp_encoding)}" raise BLPFormatError(msg) else: - msg = f"Unknown BLP compression {repr(self._compression)}" + msg = f"Unknown BLP compression {repr(self._blp_compression)}" raise BLPFormatError(msg) self.set_as_raw(data) @@ -470,23 +466,17 @@ def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: magic = b"BLP1" if im.encoderinfo.get("blp_version") == "BLP1" else b"BLP2" fp.write(magic) - assert im.palette is not None fp.write(struct.pack(" bool: - return prefix.startswith(b"BM") + return prefix[:2] == b"BM" def _dib_accept(prefix: bytes) -> bool: @@ -74,21 +72,16 @@ class BmpImageFile(ImageFile.ImageFile): for k, v in COMPRESSIONS.items(): vars()[k] = v - def _bitmap(self, header: int = 0, offset: int = 0) -> None: + def _bitmap(self, header=0, offset=0): """Read relevant info about the BMP""" - assert self.fp is not None read, seek = self.fp.read, self.fp.seek if header: seek(header) # read bmp header size @offset 14 (this is part of the header size) - file_info: dict[str, bool | int | tuple[int, ...]] = { - "header_size": i32(read(4)), - "direction": -1, - } + file_info = {"header_size": i32(read(4)), "direction": -1} # -------------------- If requested, read header at a specific position # read the rest of the bmp header, without its size - assert isinstance(file_info["header_size"], int) header_data = ImageFile._safe_read(self.fp, file_info["header_size"] - 4) # ------------------------------- Windows Bitmap v2, IBM OS/2 Bitmap v1 @@ -99,7 +92,7 @@ class BmpImageFile(ImageFile.ImageFile): file_info["height"] = i16(header_data, 2) file_info["planes"] = i16(header_data, 4) file_info["bits"] = i16(header_data, 6) - file_info["compression"] = self.COMPRESSIONS["RAW"] + file_info["compression"] = self.RAW file_info["palette_padding"] = 3 # --------------------------------------------- Windows Bitmap v3 to v5 @@ -129,9 +122,8 @@ class BmpImageFile(ImageFile.ImageFile): ) file_info["colors"] = i32(header_data, 28) file_info["palette_padding"] = 4 - assert isinstance(file_info["pixels_per_meter"], tuple) self.info["dpi"] = tuple(x / 39.3701 for x in file_info["pixels_per_meter"]) - if file_info["compression"] == self.COMPRESSIONS["BITFIELDS"]: + if file_info["compression"] == self.BITFIELDS: masks = ["r_mask", "g_mask", "b_mask"] if len(header_data) >= 48: if len(header_data) >= 52: @@ -152,10 +144,6 @@ class BmpImageFile(ImageFile.ImageFile): file_info["a_mask"] = 0x0 for mask in masks: file_info[mask] = i32(read(4)) - assert isinstance(file_info["r_mask"], int) - assert isinstance(file_info["g_mask"], int) - assert isinstance(file_info["b_mask"], int) - assert isinstance(file_info["a_mask"], int) file_info["rgb_mask"] = ( file_info["r_mask"], file_info["g_mask"], @@ -173,31 +161,27 @@ class BmpImageFile(ImageFile.ImageFile): # ------------------ Special case : header is reported 40, which # ---------------------- is shorter than real size for bpp >= 16 - assert isinstance(file_info["width"], int) - assert isinstance(file_info["height"], int) self._size = file_info["width"], file_info["height"] # ------- If color count was not found in the header, compute from bits - assert isinstance(file_info["bits"], int) file_info["colors"] = ( file_info["colors"] if file_info.get("colors", 0) else (1 << file_info["bits"]) ) - assert isinstance(file_info["colors"], int) if offset == 14 + file_info["header_size"] and file_info["bits"] <= 8: offset += 4 * file_info["colors"] # ---------------------- Check bit depth for unusual unsupported values - self._mode, raw_mode = BIT2MODE.get(file_info["bits"], ("", "")) - if not self.mode: + self._mode, raw_mode = BIT2MODE.get(file_info["bits"], (None, None)) + if self.mode is None: msg = f"Unsupported BMP pixel depth ({file_info['bits']})" raise OSError(msg) # ---------------- Process BMP with Bitfields compression (not palette) decoder_name = "raw" - if file_info["compression"] == self.COMPRESSIONS["BITFIELDS"]: - SUPPORTED: dict[int, list[tuple[int, ...]]] = { + if file_info["compression"] == self.BITFIELDS: + SUPPORTED = { 32: [ (0xFF0000, 0xFF00, 0xFF, 0x0), (0xFF000000, 0xFF0000, 0xFF00, 0x0), @@ -229,14 +213,12 @@ class BmpImageFile(ImageFile.ImageFile): file_info["bits"] == 32 and file_info["rgba_mask"] in SUPPORTED[file_info["bits"]] ): - assert isinstance(file_info["rgba_mask"], tuple) raw_mode = MASK_MODES[(file_info["bits"], file_info["rgba_mask"])] self._mode = "RGBA" if "A" in raw_mode else self.mode elif ( file_info["bits"] in (24, 16) and file_info["rgb_mask"] in SUPPORTED[file_info["bits"]] ): - assert isinstance(file_info["rgb_mask"], tuple) raw_mode = MASK_MODES[(file_info["bits"], file_info["rgb_mask"])] else: msg = "Unsupported BMP bitfields layout" @@ -244,15 +226,10 @@ class BmpImageFile(ImageFile.ImageFile): else: msg = "Unsupported BMP bitfields layout" raise OSError(msg) - elif file_info["compression"] == self.COMPRESSIONS["RAW"]: - if file_info["bits"] == 32 and ( - header == 22 or USE_RAW_ALPHA # 32-bit .cur offset - ): + elif file_info["compression"] == self.RAW: + if file_info["bits"] == 32 and header == 22: # 32-bit .cur offset raw_mode, self._mode = "BGRA", "RGBA" - elif file_info["compression"] in ( - self.COMPRESSIONS["RLE8"], - self.COMPRESSIONS["RLE4"], - ): + elif file_info["compression"] in (self.RLE8, self.RLE4): decoder_name = "bmp_rle" else: msg = f"Unsupported BMP compression ({file_info['compression']})" @@ -265,7 +242,6 @@ class BmpImageFile(ImageFile.ImageFile): msg = f"Unsupported BMP Palette size ({file_info['colors']})" raise OSError(msg) else: - assert isinstance(file_info["palette_padding"], int) padding = file_info["palette_padding"] palette = read(padding * file_info["colors"]) grayscale = True @@ -293,15 +269,14 @@ class BmpImageFile(ImageFile.ImageFile): # ---------------------------- Finally set the tile data for the plugin self.info["compression"] = file_info["compression"] - args: list[Any] = [raw_mode] + args = [raw_mode] if decoder_name == "bmp_rle": - args.append(file_info["compression"] == self.COMPRESSIONS["RLE4"]) + args.append(file_info["compression"] == self.RLE4) else: - assert isinstance(file_info["width"], int) args.append(((file_info["width"] * file_info["bits"] + 31) >> 3) & (~3)) args.append(file_info["direction"]) self.tile = [ - ImageFile._Tile( + ( decoder_name, (0, 0, file_info["width"], file_info["height"]), offset or self.fp.tell(), @@ -312,7 +287,6 @@ class BmpImageFile(ImageFile.ImageFile): def _open(self) -> None: """Open file, check magic number and read header""" # read 14 bytes: magic number, filesize, reserved, header final offset - assert self.fp is not None head_data = self.fp.read(14) # choke if the file does not have the required magic bytes if not _accept(head_data): @@ -327,7 +301,7 @@ class BmpImageFile(ImageFile.ImageFile): class BmpRleDecoder(ImageFile.PyDecoder): _pulls_fd = True - def decode(self, buffer: bytes | Image.SupportsArrayInterface) -> tuple[int, int]: + def decode(self, buffer: bytes) -> tuple[int, int]: assert self.fd is not None rle4 = self.args[1] data = bytearray() @@ -393,7 +367,7 @@ class BmpRleDecoder(ImageFile.PyDecoder): if self.fd.tell() % 2 != 0: self.fd.seek(1, os.SEEK_CUR) rawmode = "L" if self.mode == "L" else "P" - self.set_as_raw(bytes(data), rawmode, (0, self.args[-1])) + self.set_as_raw(bytes(data), (rawmode, 0, self.args[-1])) return -1, 0 @@ -447,9 +421,9 @@ def _save( image = stride * im.size[1] if im.mode == "1": - palette = b"".join(o8(i) * 3 + b"\x00" for i in (0, 255)) + palette = b"".join(o8(i) * 4 for i in (0, 255)) elif im.mode == "L": - palette = b"".join(o8(i) * 3 + b"\x00" for i in range(256)) + palette = b"".join(o8(i) * 4 for i in range(256)) elif im.mode == "P": palette = im.im.getpalette("RGB", "BGRX") colors = len(palette) // 4 @@ -490,9 +464,7 @@ def _save( if palette: fp.write(palette) - ImageFile._save( - im, fp, [ImageFile._Tile("raw", (0, 0) + im.size, 0, (rawmode, stride, -1))] - ) + ImageFile._save(im, fp, [("raw", (0, 0) + im.size, 0, (rawmode, stride, -1))]) # diff --git a/venv/Lib/site-packages/PIL/BufrStubImagePlugin.py b/venv/Lib/site-packages/PIL/BufrStubImagePlugin.py index 264564d..0ee2f65 100644 --- a/venv/Lib/site-packages/PIL/BufrStubImagePlugin.py +++ b/venv/Lib/site-packages/PIL/BufrStubImagePlugin.py @@ -10,7 +10,6 @@ # from __future__ import annotations -import os from typing import IO from . import Image, ImageFile @@ -33,7 +32,7 @@ def register_handler(handler: ImageFile.StubHandler | None) -> None: def _accept(prefix: bytes) -> bool: - return prefix.startswith((b"BUFR", b"ZCZC")) + return prefix[:4] == b"BUFR" or prefix[:4] == b"ZCZC" class BufrStubImageFile(ImageFile.StubImageFile): @@ -41,12 +40,13 @@ class BufrStubImageFile(ImageFile.StubImageFile): format_description = "BUFR" def _open(self) -> None: - assert self.fp is not None + offset = self.fp.tell() + if not _accept(self.fp.read(4)): msg = "Not a BUFR file" raise SyntaxError(msg) - self.fp.seek(-4, os.SEEK_CUR) + self.fp.seek(offset) # make something up self._mode = "F" diff --git a/venv/Lib/site-packages/PIL/ContainerIO.py b/venv/Lib/site-packages/PIL/ContainerIO.py index ec9e66c..0035296 100644 --- a/venv/Lib/site-packages/PIL/ContainerIO.py +++ b/venv/Lib/site-packages/PIL/ContainerIO.py @@ -16,11 +16,10 @@ from __future__ import annotations import io -from collections.abc import Iterable -from typing import IO, AnyStr, NoReturn +from typing import IO, AnyStr, Generic, Literal -class ContainerIO(IO[AnyStr]): +class ContainerIO(Generic[AnyStr]): """ A file object that provides read access to a part of an existing file (for example a TAR file). @@ -46,10 +45,7 @@ class ContainerIO(IO[AnyStr]): def isatty(self) -> bool: return False - def seekable(self) -> bool: - return True - - def seek(self, offset: int, mode: int = io.SEEK_SET) -> int: + def seek(self, offset: int, mode: Literal[0, 1, 2] = io.SEEK_SET) -> None: """ Move file pointer. @@ -57,7 +53,6 @@ class ContainerIO(IO[AnyStr]): :param mode: Starting position. Use 0 for beginning of region, 1 for current offset, and 2 for end of region. You cannot move the pointer outside the defined region. - :returns: Offset from start of region, in bytes. """ if mode == 1: self.pos = self.pos + offset @@ -68,7 +63,6 @@ class ContainerIO(IO[AnyStr]): # clamp self.pos = max(0, min(self.pos, self.length)) self.fh.seek(self.offset + self.pos) - return self.pos def tell(self) -> int: """ @@ -78,32 +72,27 @@ class ContainerIO(IO[AnyStr]): """ return self.pos - def readable(self) -> bool: - return True - - def read(self, n: int = -1) -> AnyStr: + def read(self, n: int = 0) -> AnyStr: """ Read data. - :param n: Number of bytes to read. If omitted, zero or negative, + :param n: Number of bytes to read. If omitted or zero, read until end of region. :returns: An 8-bit string. """ - if n > 0: + if n: n = min(n, self.length - self.pos) else: n = self.length - self.pos - if n <= 0: # EOF + if not n: # EOF return b"" if "b" in self.fh.mode else "" # type: ignore[return-value] self.pos = self.pos + n return self.fh.read(n) - def readline(self, n: int = -1) -> AnyStr: + def readline(self) -> AnyStr: """ Read a line of text. - :param n: Number of bytes to read. If omitted, zero or negative, - read until end of line. :returns: An 8-bit string. """ s: AnyStr = b"" if "b" in self.fh.mode else "" # type: ignore[assignment] @@ -113,16 +102,14 @@ class ContainerIO(IO[AnyStr]): if not c: break s = s + c - if c == newline_character or len(s) == n: + if c == newline_character: break return s - def readlines(self, n: int | None = -1) -> list[AnyStr]: + def readlines(self) -> list[AnyStr]: """ Read multiple lines of text. - :param n: Number of lines to read. If omitted, zero, negative or None, - read until end of region. :returns: A list of 8-bit strings. """ lines = [] @@ -131,43 +118,4 @@ class ContainerIO(IO[AnyStr]): if not s: break lines.append(s) - if len(lines) == n: - break return lines - - def writable(self) -> bool: - return False - - def write(self, b: AnyStr) -> NoReturn: - raise NotImplementedError() - - def writelines(self, lines: Iterable[AnyStr]) -> NoReturn: - raise NotImplementedError() - - def truncate(self, size: int | None = None) -> int: - raise NotImplementedError() - - def __enter__(self) -> ContainerIO[AnyStr]: - return self - - def __exit__(self, *args: object) -> None: - self.close() - - def __iter__(self) -> ContainerIO[AnyStr]: - return self - - def __next__(self) -> AnyStr: - line = self.readline() - if not line: - msg = "end of region" - raise StopIteration(msg) - return line - - def fileno(self) -> int: - return self.fh.fileno() - - def flush(self) -> None: - self.fh.flush() - - def close(self) -> None: - self.fh.close() diff --git a/venv/Lib/site-packages/PIL/CurImagePlugin.py b/venv/Lib/site-packages/PIL/CurImagePlugin.py index 9c188e0..85e2145 100644 --- a/venv/Lib/site-packages/PIL/CurImagePlugin.py +++ b/venv/Lib/site-packages/PIL/CurImagePlugin.py @@ -26,7 +26,7 @@ from ._binary import i32le as i32 def _accept(prefix: bytes) -> bool: - return prefix.startswith(b"\0\0\2\0") + return prefix[:4] == b"\0\0\2\0" ## @@ -38,7 +38,6 @@ class CurImageFile(BmpImagePlugin.BmpImageFile): format_description = "Windows Cursor" def _open(self) -> None: - assert self.fp is not None offset = self.fp.tell() # check magic @@ -64,7 +63,8 @@ class CurImageFile(BmpImagePlugin.BmpImageFile): # patch up the bitmap height self._size = self.size[0], self.size[1] // 2 - self.tile = [self.tile[0]._replace(extents=(0, 0) + self.size)] + d, e, o, a = self.tile[0] + self.tile[0] = d, (0, 0) + self.size, o, a # diff --git a/venv/Lib/site-packages/PIL/DcxImagePlugin.py b/venv/Lib/site-packages/PIL/DcxImagePlugin.py index d3f456d..f67f27d 100644 --- a/venv/Lib/site-packages/PIL/DcxImagePlugin.py +++ b/venv/Lib/site-packages/PIL/DcxImagePlugin.py @@ -24,7 +24,6 @@ from __future__ import annotations from . import Image from ._binary import i32le as i32 -from ._util import DeferredError from .PcxImagePlugin import PcxImageFile MAGIC = 0x3ADE68B1 # QUIZ: what's this value, then? @@ -45,7 +44,6 @@ class DcxImageFile(PcxImageFile): def _open(self) -> None: # Header - assert self.fp is not None s = self.fp.read(4) if not _accept(s): msg = "not a DCX file" @@ -68,8 +66,6 @@ class DcxImageFile(PcxImageFile): def seek(self, frame: int) -> None: if not self._seek_check(frame): return - if isinstance(self._fp, DeferredError): - raise self._fp.ex self.frame = frame self.fp = self._fp self.fp.seek(self._offset[frame]) diff --git a/venv/Lib/site-packages/PIL/DdsImagePlugin.py b/venv/Lib/site-packages/PIL/DdsImagePlugin.py index 312f602..a57e4ae 100644 --- a/venv/Lib/site-packages/PIL/DdsImagePlugin.py +++ b/venv/Lib/site-packages/PIL/DdsImagePlugin.py @@ -1,5 +1,5 @@ """ -A Pillow plugin for .dds files (S3TC-compressed aka DXTC) +A Pillow loader for .dds files (S3TC-compressed aka DXTC) Jerome Leclanche Documentation: @@ -12,6 +12,7 @@ https://creativecommons.org/publicdomain/zero/1.0/ from __future__ import annotations +import io import struct import sys from enum import IntEnum, IntFlag @@ -332,7 +333,6 @@ class DdsImageFile(ImageFile.ImageFile): format_description = "DirectDraw Surface" def _open(self) -> None: - assert self.fp is not None if not _accept(self.fp.read(4)): msg = "not a DDS file" raise SyntaxError(msg) @@ -340,20 +340,21 @@ class DdsImageFile(ImageFile.ImageFile): if header_size != 124: msg = f"Unsupported header size {repr(header_size)}" raise OSError(msg) - header = self.fp.read(header_size - 4) - if len(header) != 120: - msg = f"Incomplete header: {len(header)} bytes" + header_bytes = self.fp.read(header_size - 4) + if len(header_bytes) != 120: + msg = f"Incomplete header: {len(header_bytes)} bytes" raise OSError(msg) + header = io.BytesIO(header_bytes) - flags, height, width = struct.unpack("<3I", header[:12]) + flags, height, width = struct.unpack("<3I", header.read(12)) self._size = (width, height) extents = (0, 0) + self.size - pitch, depth, mipmaps = struct.unpack("<3I", header[12:24]) - struct.unpack("<11I", header[24:68]) # reserved + pitch, depth, mipmaps = struct.unpack("<3I", header.read(12)) + struct.unpack("<11I", header.read(44)) # reserved # pixel format - pfsize, pfflags, fourcc, bitcount = struct.unpack("<4I", header[68:84]) + pfsize, pfflags, fourcc, bitcount = struct.unpack("<4I", header.read(16)) n = 0 rawmode = None if pfflags & DDPF.RGB: @@ -365,8 +366,8 @@ class DdsImageFile(ImageFile.ImageFile): self._mode = "RGB" mask_count = 3 - masks = struct.unpack(f"<{mask_count}I", header[84 : 84 + mask_count * 4]) - self.tile = [ImageFile._Tile("dds_rgb", extents, 0, (bitcount, masks))] + masks = struct.unpack(f"<{mask_count}I", header.read(mask_count * 4)) + self.tile = [("dds_rgb", extents, 0, (bitcount, masks))] return elif pfflags & DDPF.LUMINANCE: if bitcount == 8: @@ -418,14 +419,6 @@ class DdsImageFile(ImageFile.ImageFile): self._mode = "RGBA" self.pixel_format = "BC1" n = 1 - elif dxgi_format in (DXGI_FORMAT.BC2_TYPELESS, DXGI_FORMAT.BC2_UNORM): - self._mode = "RGBA" - self.pixel_format = "BC2" - n = 2 - elif dxgi_format in (DXGI_FORMAT.BC3_TYPELESS, DXGI_FORMAT.BC3_UNORM): - self._mode = "RGBA" - self.pixel_format = "BC3" - n = 3 elif dxgi_format in (DXGI_FORMAT.BC4_TYPELESS, DXGI_FORMAT.BC4_UNORM): self._mode = "L" self.pixel_format = "BC4" @@ -488,7 +481,7 @@ class DdsImageFile(ImageFile.ImageFile): class DdsRgbDecoder(ImageFile.PyDecoder): _pulls_fd = True - def decode(self, buffer: bytes | Image.SupportsArrayInterface) -> tuple[int, int]: + def decode(self, buffer: bytes) -> tuple[int, int]: assert self.fd is not None bitcount, masks = self.args @@ -515,8 +508,6 @@ class DdsRgbDecoder(ImageFile.PyDecoder): # Remove the zero padding, and scale it to 8 bits data += o8( int(((masked_value >> mask_offsets[i]) / mask_totals[i]) * 255) - if mask_totals[i] - else 0 ) self.set_as_raw(data) return -1, 0 @@ -527,68 +518,30 @@ def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: msg = f"cannot write mode {im.mode} as DDS" raise OSError(msg) - flags = DDSD.CAPS | DDSD.HEIGHT | DDSD.WIDTH | DDSD.PIXELFORMAT - bitcount = len(im.getbands()) * 8 - pixel_format = im.encoderinfo.get("pixel_format") - args: tuple[int] | str - if pixel_format: - codec_name = "bcn" - flags |= DDSD.LINEARSIZE - pitch = (im.width + 3) * 4 - rgba_mask = [0, 0, 0, 0] - pixel_flags = DDPF.FOURCC - if pixel_format == "DXT1": - fourcc = D3DFMT.DXT1 - args = (1,) - elif pixel_format == "DXT3": - fourcc = D3DFMT.DXT3 - args = (2,) - elif pixel_format == "DXT5": - fourcc = D3DFMT.DXT5 - args = (3,) - else: - fourcc = D3DFMT.DX10 - if pixel_format == "BC2": - args = (2,) - dxgi_format = DXGI_FORMAT.BC2_TYPELESS - elif pixel_format == "BC3": - args = (3,) - dxgi_format = DXGI_FORMAT.BC3_TYPELESS - elif pixel_format == "BC5": - args = (5,) - dxgi_format = DXGI_FORMAT.BC5_TYPELESS - if im.mode != "RGB": - msg = "only RGB mode can be written as BC5" - raise OSError(msg) - else: - msg = f"cannot write pixel format {pixel_format}" - raise OSError(msg) - else: - codec_name = "raw" - flags |= DDSD.PITCH - pitch = (im.width * bitcount + 7) // 8 - - alpha = im.mode[-1] == "A" - if im.mode[0] == "L": - pixel_flags = DDPF.LUMINANCE - args = im.mode - if alpha: - rgba_mask = [0x000000FF, 0x000000FF, 0x000000FF] - else: - rgba_mask = [0xFF000000, 0xFF000000, 0xFF000000] - else: - pixel_flags = DDPF.RGB - args = im.mode[::-1] - rgba_mask = [0x00FF0000, 0x0000FF00, 0x000000FF] - - if alpha: - r, g, b, a = im.split() - im = Image.merge("RGBA", (a, r, g, b)) + alpha = im.mode[-1] == "A" + if im.mode[0] == "L": + pixel_flags = DDPF.LUMINANCE + rawmode = im.mode if alpha: - pixel_flags |= DDPF.ALPHAPIXELS - rgba_mask.append(0xFF000000 if alpha else 0) + rgba_mask = [0x000000FF, 0x000000FF, 0x000000FF] + else: + rgba_mask = [0xFF000000, 0xFF000000, 0xFF000000] + else: + pixel_flags = DDPF.RGB + rawmode = im.mode[::-1] + rgba_mask = [0x00FF0000, 0x0000FF00, 0x000000FF] + + if alpha: + r, g, b, a = im.split() + im = Image.merge("RGBA", (a, r, g, b)) + if alpha: + pixel_flags |= DDPF.ALPHAPIXELS + rgba_mask.append(0xFF000000 if alpha else 0) + + flags = DDSD.CAPS | DDSD.HEIGHT | DDSD.WIDTH | DDSD.PITCH | DDSD.PIXELFORMAT + bitcount = len(im.getbands()) * 8 + pitch = (im.width * bitcount + 7) // 8 - fourcc = D3DFMT.UNKNOWN fp.write( o32(DDS_MAGIC) + struct.pack( @@ -603,20 +556,17 @@ def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: ) + struct.pack("11I", *((0,) * 11)) # reserved # pfsize, pfflags, fourcc, bitcount - + struct.pack("<4I", 32, pixel_flags, fourcc, bitcount) + + struct.pack("<4I", 32, pixel_flags, 0, bitcount) + struct.pack("<4I", *rgba_mask) # dwRGBABitMask + struct.pack("<5I", DDSCAPS.TEXTURE, 0, 0, 0, 0) ) - if fourcc == D3DFMT.DX10: - fp.write( - # dxgi_format, 2D resource, misc, array size, straight alpha - struct.pack("<5I", dxgi_format, 3, 0, 0, 1) - ) - ImageFile._save(im, fp, [ImageFile._Tile(codec_name, (0, 0) + im.size, 0, args)]) + ImageFile._save( + im, fp, [ImageFile._Tile("raw", (0, 0) + im.size, 0, (rawmode, 0, 1))] + ) def _accept(prefix: bytes) -> bool: - return prefix.startswith(b"DDS ") + return prefix[:4] == b"DDS " Image.register_open(DdsImageFile.format, DdsImageFile, _accept) diff --git a/venv/Lib/site-packages/PIL/EpsImagePlugin.py b/venv/Lib/site-packages/PIL/EpsImagePlugin.py index 2effb81..f31b1c1 100644 --- a/venv/Lib/site-packages/PIL/EpsImagePlugin.py +++ b/venv/Lib/site-packages/PIL/EpsImagePlugin.py @@ -31,6 +31,7 @@ from typing import IO from . import Image, ImageFile from ._binary import i32le as i32 +from ._deprecate import deprecate # -------------------------------------------------------------------- @@ -65,24 +66,16 @@ def has_ghostscript() -> bool: return gs_binary is not False -def Ghostscript( - tile: list[ImageFile._Tile], - size: tuple[int, int], - fp: IO[bytes], - scale: int = 1, - transparency: bool = False, -) -> Image.core.ImagingCore: +def Ghostscript(tile, size, fp, scale=1, transparency=False): """Render an image using Ghostscript""" global gs_binary if not has_ghostscript(): msg = "Unable to locate Ghostscript on paths" raise OSError(msg) - assert isinstance(gs_binary, str) # Unpack decoder tile - args = tile[0].args - assert isinstance(args, tuple) - length, bbox = args + decoder, tile, offset, data = tile[0] + length, bbox = data # Hack to support hi-res rendering scale = int(scale) or 1 @@ -121,13 +114,7 @@ def Ghostscript( lengthfile -= len(s) f.write(s) - if transparency: - # "RGBA" - device = "pngalpha" - else: - # "pnmraw" automatically chooses between - # PBM ("1"), PGM ("L"), and PPM ("RGB"). - device = "pnmraw" + device = "pngalpha" if transparency else "ppmraw" # Build Ghostscript command command = [ @@ -157,9 +144,8 @@ def Ghostscript( startupinfo = subprocess.STARTUPINFO() startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW subprocess.check_call(command, startupinfo=startupinfo) - with Image.open(outfile) as out_im: - out_im.load() - return out_im.im.copy() + out_im = Image.open(outfile) + out_im.load() finally: try: os.unlink(outfile) @@ -168,11 +154,50 @@ def Ghostscript( except OSError: pass + im = out_im.im.copy() + out_im.close() + return im + + +class PSFile: + """ + Wrapper for bytesio object that treats either CR or LF as end of line. + This class is no longer used internally, but kept for backwards compatibility. + """ + + def __init__(self, fp): + deprecate( + "PSFile", + 11, + action="If you need the functionality of this class " + "you will need to implement it yourself.", + ) + self.fp = fp + self.char = None + + def seek(self, offset, whence=io.SEEK_SET): + self.char = None + self.fp.seek(offset, whence) + + def readline(self) -> str: + s = [self.char or b""] + self.char = None + + c = self.fp.read(1) + while (c not in b"\r\n") and len(c): + s.append(c) + c = self.fp.read(1) + + self.char = self.fp.read(1) + # line endings can be 1 or 2 of \r \n, in either order + if self.char in b"\r\n": + self.char = None + + return b"".join(s).decode("latin-1") + def _accept(prefix: bytes) -> bool: - return prefix.startswith(b"%!PS") or ( - len(prefix) >= 4 and i32(prefix) == 0xC6D3D0C5 - ) + return prefix[:4] == b"%!PS" or (len(prefix) >= 4 and i32(prefix) == 0xC6D3D0C5) ## @@ -189,18 +214,13 @@ class EpsImageFile(ImageFile.ImageFile): mode_map = {1: "L", 2: "LAB", 3: "RGB", 4: "CMYK"} def _open(self) -> None: - assert self.fp is not None (length, offset) = self._find_offset(self.fp) # go to offset - start of "%!PS" self.fp.seek(offset) self._mode = "RGB" - - # When reading header comments, the first comment is used. - # When reading trailer comments, the last comment is used. - bounding_box: list[int] | None = None - imagedata_size: tuple[int, int] | None = None + self._size = None byte_arr = bytearray(255) bytes_mv = memoryview(byte_arr) @@ -222,8 +242,8 @@ class EpsImageFile(ImageFile.ImageFile): msg = 'EPS header missing "%%BoundingBox" comment' raise SyntaxError(msg) - def read_comment(s: str) -> bool: - nonlocal bounding_box, reading_trailer_comments + def _read_comment(s: str) -> bool: + nonlocal reading_trailer_comments try: m = split.match(s) except re.error as e: @@ -238,12 +258,14 @@ class EpsImageFile(ImageFile.ImageFile): if k == "BoundingBox": if v == "(atend)": reading_trailer_comments = True - elif not bounding_box or (trailer_reached and reading_trailer_comments): + elif not self._size or (trailer_reached and reading_trailer_comments): try: # Note: The DSC spec says that BoundingBox # fields should be integers, but some drivers # put floating point values there anyway. - bounding_box = [int(float(i)) for i in v.split()] + box = [int(float(i)) for i in v.split()] + self._size = box[2] - box[0], box[3] - box[1] + self.tile = [("eps", (0, 0) + self.size, offset, (length, box))] except Exception: pass return True @@ -294,11 +316,11 @@ class EpsImageFile(ImageFile.ImageFile): continue s = str(bytes_mv[:bytes_read], "latin-1") - if not read_comment(s): + if not _read_comment(s): m = field.match(s) if m: k = m.group(1) - if k.startswith("PS-Adobe"): + if k[:8] == "PS-Adobe": self.info["PS-Adobe"] = k[9:] else: self.info[k] = "" @@ -313,12 +335,6 @@ class EpsImageFile(ImageFile.ImageFile): # Check for an "ImageData" descriptor # https://www.adobe.com/devnet-apps/photoshop/fileformatashtml/#50577413_pgfId-1035096 - # If we've already read an "ImageData" descriptor, - # don't read another one. - if imagedata_size: - bytes_read = 0 - continue - # Values: # columns # rows @@ -344,39 +360,23 @@ class EpsImageFile(ImageFile.ImageFile): else: break - # Parse the columns and rows after checking the bit depth and mode - # in case the bit depth and/or mode are invalid. - imagedata_size = columns, rows + self._size = columns, rows + return elif bytes_mv[:5] == b"%%EOF": break elif trailer_reached and reading_trailer_comments: # Load EPS trailer s = str(bytes_mv[:bytes_read], "latin-1") - read_comment(s) + _read_comment(s) elif bytes_mv[:9] == b"%%Trailer": trailer_reached = True - elif bytes_mv[:14] == b"%%BeginBinary:": - bytecount = int(byte_arr[14:bytes_read]) - self.fp.seek(bytecount, os.SEEK_CUR) bytes_read = 0 - # A "BoundingBox" is always required, - # even if an "ImageData" descriptor size exists. - if not bounding_box: + if not self._size: msg = "cannot determine EPS bounding box" raise OSError(msg) - # An "ImageData" size takes precedence over the "BoundingBox". - self._size = imagedata_size or ( - bounding_box[2] - bounding_box[0], - bounding_box[3] - bounding_box[1], - ) - - self.tile = [ - ImageFile._Tile("eps", (0, 0) + self.size, offset, (length, bounding_box)) - ] - - def _find_offset(self, fp: IO[bytes]) -> tuple[int, int]: + def _find_offset(self, fp): s = fp.read(4) if s == b"%!PS": @@ -399,12 +399,9 @@ class EpsImageFile(ImageFile.ImageFile): return length, offset - def load( - self, scale: int = 1, transparency: bool = False - ) -> Image.core.PixelAccess | None: + def load(self, scale=1, transparency=False): # Load EPS via Ghostscript if self.tile: - assert self.fp is not None self.im = Ghostscript(self.tile, self.size, self.fp, scale, transparency) self._mode = self.im.mode self._size = self.im.size @@ -461,7 +458,7 @@ def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes, eps: int = 1) - if hasattr(fp, "flush"): fp.flush() - ImageFile._save(im, fp, [ImageFile._Tile("eps", (0, 0) + im.size)]) + ImageFile._save(im, fp, [("eps", (0, 0) + im.size, 0, None)]) fp.write(b"\n%%%%EndBinary\n") fp.write(b"grestore end\n") diff --git a/venv/Lib/site-packages/PIL/ExifTags.py b/venv/Lib/site-packages/PIL/ExifTags.py index 2280d5c..39b4aa5 100644 --- a/venv/Lib/site-packages/PIL/ExifTags.py +++ b/venv/Lib/site-packages/PIL/ExifTags.py @@ -303,38 +303,38 @@ TAGS = { class GPS(IntEnum): - GPSVersionID = 0x00 - GPSLatitudeRef = 0x01 - GPSLatitude = 0x02 - GPSLongitudeRef = 0x03 - GPSLongitude = 0x04 - GPSAltitudeRef = 0x05 - GPSAltitude = 0x06 - GPSTimeStamp = 0x07 - GPSSatellites = 0x08 - GPSStatus = 0x09 - GPSMeasureMode = 0x0A - GPSDOP = 0x0B - GPSSpeedRef = 0x0C - GPSSpeed = 0x0D - GPSTrackRef = 0x0E - GPSTrack = 0x0F - GPSImgDirectionRef = 0x10 - GPSImgDirection = 0x11 - GPSMapDatum = 0x12 - GPSDestLatitudeRef = 0x13 - GPSDestLatitude = 0x14 - GPSDestLongitudeRef = 0x15 - GPSDestLongitude = 0x16 - GPSDestBearingRef = 0x17 - GPSDestBearing = 0x18 - GPSDestDistanceRef = 0x19 - GPSDestDistance = 0x1A - GPSProcessingMethod = 0x1B - GPSAreaInformation = 0x1C - GPSDateStamp = 0x1D - GPSDifferential = 0x1E - GPSHPositioningError = 0x1F + GPSVersionID = 0 + GPSLatitudeRef = 1 + GPSLatitude = 2 + GPSLongitudeRef = 3 + GPSLongitude = 4 + GPSAltitudeRef = 5 + GPSAltitude = 6 + GPSTimeStamp = 7 + GPSSatellites = 8 + GPSStatus = 9 + GPSMeasureMode = 10 + GPSDOP = 11 + GPSSpeedRef = 12 + GPSSpeed = 13 + GPSTrackRef = 14 + GPSTrack = 15 + GPSImgDirectionRef = 16 + GPSImgDirection = 17 + GPSMapDatum = 18 + GPSDestLatitudeRef = 19 + GPSDestLatitude = 20 + GPSDestLongitudeRef = 21 + GPSDestLongitude = 22 + GPSDestBearingRef = 23 + GPSDestBearing = 24 + GPSDestDistanceRef = 25 + GPSDestDistance = 26 + GPSProcessingMethod = 27 + GPSAreaInformation = 28 + GPSDateStamp = 29 + GPSDifferential = 30 + GPSHPositioningError = 31 """Maps EXIF GPS tags to tag names.""" @@ -342,41 +342,40 @@ GPSTAGS = {i.value: i.name for i in GPS} class Interop(IntEnum): - InteropIndex = 0x0001 - InteropVersion = 0x0002 - RelatedImageFileFormat = 0x1000 - RelatedImageWidth = 0x1001 - RelatedImageHeight = 0x1002 + InteropIndex = 1 + InteropVersion = 2 + RelatedImageFileFormat = 4096 + RelatedImageWidth = 4097 + RelatedImageHeight = 4098 class IFD(IntEnum): - Exif = 0x8769 - GPSInfo = 0x8825 - MakerNote = 0x927C - Makernote = 0x927C # Deprecated - Interop = 0xA005 + Exif = 34665 + GPSInfo = 34853 + Makernote = 37500 + Interop = 40965 IFD1 = -1 class LightSource(IntEnum): - Unknown = 0x00 - Daylight = 0x01 - Fluorescent = 0x02 - Tungsten = 0x03 - Flash = 0x04 - Fine = 0x09 - Cloudy = 0x0A - Shade = 0x0B - DaylightFluorescent = 0x0C - DayWhiteFluorescent = 0x0D - CoolWhiteFluorescent = 0x0E - WhiteFluorescent = 0x0F - StandardLightA = 0x11 - StandardLightB = 0x12 - StandardLightC = 0x13 - D55 = 0x14 - D65 = 0x15 - D75 = 0x16 - D50 = 0x17 - ISO = 0x18 - Other = 0xFF + Unknown = 0 + Daylight = 1 + Fluorescent = 2 + Tungsten = 3 + Flash = 4 + Fine = 9 + Cloudy = 10 + Shade = 11 + DaylightFluorescent = 12 + DayWhiteFluorescent = 13 + CoolWhiteFluorescent = 14 + WhiteFluorescent = 15 + StandardLightA = 17 + StandardLightB = 18 + StandardLightC = 19 + D55 = 20 + D65 = 21 + D75 = 22 + D50 = 23 + ISO = 24 + Other = 255 diff --git a/venv/Lib/site-packages/PIL/FitsImagePlugin.py b/venv/Lib/site-packages/PIL/FitsImagePlugin.py index a3fdc0e..4846054 100644 --- a/venv/Lib/site-packages/PIL/FitsImagePlugin.py +++ b/venv/Lib/site-packages/PIL/FitsImagePlugin.py @@ -17,7 +17,7 @@ from . import Image, ImageFile def _accept(prefix: bytes) -> bool: - return prefix.startswith(b"SIMPLE") + return prefix[:6] == b"SIMPLE" class FitsImageFile(ImageFile.ImageFile): @@ -67,7 +67,7 @@ class FitsImageFile(ImageFile.ImageFile): raise ValueError(msg) offset += self.fp.tell() - 80 - self.tile = [ImageFile._Tile(decoder_name, (0, 0) + self.size, offset, args)] + self.tile = [(decoder_name, (0, 0) + self.size, offset, args)] def _get_size( self, headers: dict[bytes, bytes], prefix: bytes @@ -126,7 +126,7 @@ class FitsImageFile(ImageFile.ImageFile): class FitsGzipDecoder(ImageFile.PyDecoder): _pulls_fd = True - def decode(self, buffer: bytes | Image.SupportsArrayInterface) -> tuple[int, int]: + def decode(self, buffer: bytes) -> tuple[int, int]: assert self.fd is not None value = gzip.decompress(self.fd.read()) diff --git a/venv/Lib/site-packages/PIL/FliImagePlugin.py b/venv/Lib/site-packages/PIL/FliImagePlugin.py index da1e8e9..dceb839 100644 --- a/venv/Lib/site-packages/PIL/FliImagePlugin.py +++ b/venv/Lib/site-packages/PIL/FliImagePlugin.py @@ -22,7 +22,6 @@ from . import Image, ImageFile, ImagePalette from ._binary import i16le as i16 from ._binary import i32le as i32 from ._binary import o8 -from ._util import DeferredError # # decoder @@ -30,7 +29,7 @@ from ._util import DeferredError def _accept(prefix: bytes) -> bool: return ( - len(prefix) >= 16 + len(prefix) >= 6 and i16(prefix, 4) in [0xAF11, 0xAF12] and i16(prefix, 14) in [0, 3] # flags ) @@ -46,16 +45,10 @@ class FliImageFile(ImageFile.ImageFile): format_description = "Autodesk FLI/FLC Animation" _close_exclusive_fp_after_loading = False - def _open(self) -> None: + def _open(self): # HEAD - assert self.fp is not None s = self.fp.read(128) - if not ( - _accept(s) - and s[20:22] == b"\x00" * 2 - and s[42:80] == b"\x00" * 38 - and s[88:] == b"\x00" * 40 - ): + if not (_accept(s) and s[20:22] == b"\x00\x00"): msg = "not an FLI/FLC file" raise SyntaxError(msg) @@ -83,13 +76,14 @@ class FliImageFile(ImageFile.ImageFile): if i16(s, 4) == 0xF100: # prefix chunk; ignore it - self.fp.seek(self.__offset + i32(s)) + self.__offset = self.__offset + i32(s) + self.fp.seek(self.__offset) s = self.fp.read(16) if i16(s, 4) == 0xF1FA: # look for palette chunk number_of_subchunks = i16(s, 6) - chunk_size: int | None = None + chunk_size = None for _ in range(number_of_subchunks): if chunk_size is not None: self.fp.seek(chunk_size - 6, os.SEEK_CUR) @@ -102,9 +96,8 @@ class FliImageFile(ImageFile.ImageFile): if not chunk_size: break - self.palette = ImagePalette.raw( - "RGB", b"".join(o8(r) + o8(g) + o8(b) for (r, g, b) in palette) - ) + palette = [o8(r) + o8(g) + o8(b) for (r, g, b) in palette] + self.palette = ImagePalette.raw("RGB", b"".join(palette)) # set things up to decode first frame self.__frame = -1 @@ -112,11 +105,10 @@ class FliImageFile(ImageFile.ImageFile): self.__rewind = self.fp.tell() self.seek(0) - def _palette(self, palette: list[tuple[int, int, int]], shift: int) -> None: + def _palette(self, palette, shift): # load palette i = 0 - assert self.fp is not None for e in range(i16(self.fp.read(2))): s = self.fp.read(2) i = i + s[0] @@ -141,8 +133,6 @@ class FliImageFile(ImageFile.ImageFile): self._seek(f) def _seek(self, frame: int) -> None: - if isinstance(self._fp, DeferredError): - raise self._fp.ex if frame == 0: self.__frame = -1 self._fp.seek(self.__rewind) @@ -168,7 +158,7 @@ class FliImageFile(ImageFile.ImageFile): framesize = i32(s) self.decodermaxblock = framesize - self.tile = [ImageFile._Tile("fli", (0, 0) + self.size, self.__offset)] + self.tile = [("fli", (0, 0) + self.size, self.__offset, None)] self.__offset += framesize diff --git a/venv/Lib/site-packages/PIL/FpxImagePlugin.py b/venv/Lib/site-packages/PIL/FpxImagePlugin.py index 2979712..c1927bd 100644 --- a/venv/Lib/site-packages/PIL/FpxImagePlugin.py +++ b/venv/Lib/site-packages/PIL/FpxImagePlugin.py @@ -42,7 +42,7 @@ MODES = { def _accept(prefix: bytes) -> bool: - return prefix.startswith(olefile.MAGIC) + return prefix[:8] == olefile.MAGIC ## @@ -53,20 +53,18 @@ class FpxImageFile(ImageFile.ImageFile): format = "FPX" format_description = "FlashPix" - def _open(self) -> None: + def _open(self): # # read the OLE directory and see if this is a likely # to be a FlashPix file - assert self.fp is not None try: self.ole = olefile.OleFileIO(self.fp) except OSError as e: msg = "not an FPX file; invalid OLE file" raise SyntaxError(msg) from e - root = self.ole.root - if not root or root.clsid != "56616700-C154-11CE-8553-00AA00A1F95B": + if self.ole.root.clsid != "56616700-C154-11CE-8553-00AA00A1F95B": msg = "not an FPX file; bad root CLSID" raise SyntaxError(msg) @@ -82,8 +80,6 @@ class FpxImageFile(ImageFile.ImageFile): # size (highest resolution) - assert isinstance(prop[0x1000002], int) - assert isinstance(prop[0x1000003], int) self._size = prop[0x1000002], prop[0x1000003] size = max(self.size) @@ -103,7 +99,8 @@ class FpxImageFile(ImageFile.ImageFile): s = prop[0x2000002 | id] - if not isinstance(s, bytes) or (bands := i32(s, 4)) > 4: + bands = i32(s, 4) + if bands > 4: msg = "Invalid number of bands" raise OSError(msg) @@ -167,18 +164,18 @@ class FpxImageFile(ImageFile.ImageFile): if compression == 0: self.tile.append( - ImageFile._Tile( + ( "raw", (x, y, x1, y1), i32(s, i) + 28, - self.rawmode, + (self.rawmode,), ) ) elif compression == 1: # FIXME: the fill decoder is not implemented self.tile.append( - ImageFile._Tile( + ( "fill", (x, y, x1, y1), i32(s, i) + 28, @@ -206,7 +203,7 @@ class FpxImageFile(ImageFile.ImageFile): jpegmode = rawmode self.tile.append( - ImageFile._Tile( + ( "jpeg", (x, y, x1, y1), i32(s, i) + 28, @@ -230,12 +227,11 @@ class FpxImageFile(ImageFile.ImageFile): if y >= ysize: break # isn't really required - assert self.fp is not None self.stream = stream self._fp = self.fp self.fp = None - def load(self) -> Image.core.PixelAccess | None: + def load(self): if not self.fp: self.fp = self.ole.openstream(self.stream[:2] + ["Subimage 0000 Data"]) diff --git a/venv/Lib/site-packages/PIL/FtexImagePlugin.py b/venv/Lib/site-packages/PIL/FtexImagePlugin.py index e4d836c..5acbb49 100644 --- a/venv/Lib/site-packages/PIL/FtexImagePlugin.py +++ b/venv/Lib/site-packages/PIL/FtexImagePlugin.py @@ -72,7 +72,6 @@ class FtexImageFile(ImageFile.ImageFile): format_description = "Texture File Format (IW2:EOC)" def _open(self) -> None: - assert self.fp is not None if not _accept(self.fp.read(4)): msg = "not an FTEX file" raise SyntaxError(msg) @@ -80,6 +79,8 @@ class FtexImageFile(ImageFile.ImageFile): self._size = struct.unpack("<2i", self.fp.read(8)) mipmap_count, format_count = struct.unpack("<2i", self.fp.read(8)) + self._mode = "RGB" + # Only support single-format files. # I don't know of any multi-format file. assert format_count == 1 @@ -92,10 +93,9 @@ class FtexImageFile(ImageFile.ImageFile): if format == Format.DXT1: self._mode = "RGBA" - self.tile = [ImageFile._Tile("bcn", (0, 0) + self.size, 0, (1,))] + self.tile = [("bcn", (0, 0) + self.size, 0, 1)] elif format == Format.UNCOMPRESSED: - self._mode = "RGB" - self.tile = [ImageFile._Tile("raw", (0, 0) + self.size, 0, "RGB")] + self.tile = [("raw", (0, 0) + self.size, 0, ("RGB", 0, 1))] else: msg = f"Invalid texture compression format: {repr(format)}" raise ValueError(msg) @@ -108,7 +108,7 @@ class FtexImageFile(ImageFile.ImageFile): def _accept(prefix: bytes) -> bool: - return prefix.startswith(MAGIC) + return prefix[:4] == MAGIC Image.register_open(FtexImageFile.format, FtexImageFile, _accept) diff --git a/venv/Lib/site-packages/PIL/GbrImagePlugin.py b/venv/Lib/site-packages/PIL/GbrImagePlugin.py index ec666c8..93e89b1 100644 --- a/venv/Lib/site-packages/PIL/GbrImagePlugin.py +++ b/venv/Lib/site-packages/PIL/GbrImagePlugin.py @@ -42,7 +42,6 @@ class GbrImageFile(ImageFile.ImageFile): format_description = "GIMP brush file" def _open(self) -> None: - assert self.fp is not None header_size = i32(self.fp.read(4)) if header_size < 20: msg = "not a GIMP brush" @@ -55,7 +54,7 @@ class GbrImageFile(ImageFile.ImageFile): width = i32(self.fp.read(4)) height = i32(self.fp.read(4)) color_depth = i32(self.fp.read(4)) - if width == 0 or height == 0: + if width <= 0 or height <= 0: msg = "not a GIMP brush" raise SyntaxError(msg) if color_depth not in (1, 4): @@ -72,7 +71,7 @@ class GbrImageFile(ImageFile.ImageFile): raise SyntaxError(msg) self.info["spacing"] = i32(self.fp.read(4)) - self.info["comment"] = self.fp.read(comment_length)[:-1] + comment = self.fp.read(comment_length)[:-1] if color_depth == 1: self._mode = "L" @@ -81,15 +80,16 @@ class GbrImageFile(ImageFile.ImageFile): self._size = width, height + self.info["comment"] = comment + # Image might not be small Image._decompression_bomb_check(self.size) # Data is an uncompressed block of w * h * bytes/pixel self._data_size = width * height * color_depth - def load(self) -> Image.core.PixelAccess | None: - if self._im is None: - assert self.fp is not None + def load(self): + if not self.im: self.im = Image.core.new(self.mode, self.size) self.frombytes(self.fp.read(self._data_size)) return Image.Image.load(self) diff --git a/venv/Lib/site-packages/PIL/GdImageFile.py b/venv/Lib/site-packages/PIL/GdImageFile.py index 891225c..88b87a2 100644 --- a/venv/Lib/site-packages/PIL/GdImageFile.py +++ b/venv/Lib/site-packages/PIL/GdImageFile.py @@ -56,7 +56,7 @@ class GdImageFile(ImageFile.ImageFile): msg = "Not a valid GD 2.x .gd file" raise SyntaxError(msg) - self._mode = "P" + self._mode = "L" # FIXME: "P" self._size = i16(s, 2), i16(s, 4) true_color = s[6] @@ -68,15 +68,15 @@ class GdImageFile(ImageFile.ImageFile): self.info["transparency"] = tindex self.palette = ImagePalette.raw( - "RGBX", s[7 + true_color_offset + 6 : 7 + true_color_offset + 6 + 256 * 4] + "XBGR", s[7 + true_color_offset + 4 : 7 + true_color_offset + 4 + 256 * 4] ) self.tile = [ - ImageFile._Tile( + ( "raw", (0, 0) + self.size, - 7 + true_color_offset + 6 + 256 * 4, - "L", + 7 + true_color_offset + 4 + 256 * 4, + ("L", 0, 1), ) ] diff --git a/venv/Lib/site-packages/PIL/GifImagePlugin.py b/venv/Lib/site-packages/PIL/GifImagePlugin.py index 76a0d4a..284128c 100644 --- a/venv/Lib/site-packages/PIL/GifImagePlugin.py +++ b/venv/Lib/site-packages/PIL/GifImagePlugin.py @@ -29,9 +29,10 @@ import itertools import math import os import subprocess +import sys from enum import IntEnum from functools import cached_property -from typing import Any, NamedTuple, cast +from typing import IO, TYPE_CHECKING, Any, List, Literal, NamedTuple, Union from . import ( Image, @@ -45,14 +46,9 @@ from . import ( from ._binary import i16le as i16 from ._binary import o8 from ._binary import o16le as o16 -from ._util import DeferredError -TYPE_CHECKING = False if TYPE_CHECKING: - from typing import IO, Literal - from . import _imaging - from ._typing import Buffer class LoadingStrategy(IntEnum): @@ -71,7 +67,7 @@ LOADING_STRATEGY = LoadingStrategy.RGB_AFTER_FIRST def _accept(prefix: bytes) -> bool: - return prefix.startswith((b"GIF87a", b"GIF89a")) + return prefix[:6] in [b"GIF87a", b"GIF89a"] ## @@ -87,7 +83,6 @@ class GifImageFile(ImageFile.ImageFile): global_palette = None def data(self) -> bytes | None: - assert self.fp is not None s = self.fp.read(1) if s and s[0]: return self.fp.read(s[0]) @@ -101,7 +96,6 @@ class GifImageFile(ImageFile.ImageFile): def _open(self) -> None: # Screen - assert self.fp is not None s = self.fp.read(13) if not _accept(s): msg = "not a GIF file" @@ -109,6 +103,7 @@ class GifImageFile(ImageFile.ImageFile): self.info["version"] = s[:6] self._size = i16(s, 6), i16(s, 8) + self.tile = [] flags = s[10] bits = (flags & 7) + 1 @@ -118,8 +113,8 @@ class GifImageFile(ImageFile.ImageFile): # check if palette contains colour indices p = self.fp.read(3 << bits) if self._is_palette_needed(p): - palette = ImagePalette.raw("RGB", p) - self.global_palette = self.palette = palette + p = ImagePalette.raw("RGB", p) + self.global_palette = self.palette = p self._fp = self.fp # FIXME: hack self.__rewind = self.fp.tell() @@ -160,7 +155,7 @@ class GifImageFile(ImageFile.ImageFile): if not self._seek_check(frame): return if frame < self.__frame: - self._im = None + self.im = None self._seek(0) last_frame = self.__frame @@ -173,8 +168,6 @@ class GifImageFile(ImageFile.ImageFile): raise EOFError(msg) from e def _seek(self, frame: int, update_image: bool = True) -> None: - if isinstance(self._fp, DeferredError): - raise self._fp.ex if frame == 0: # rewind self.__offset = 0 @@ -258,14 +251,14 @@ class GifImageFile(ImageFile.ImageFile): info["comment"] += b"\n" + comment else: info["comment"] = comment - s = b"" + s = None continue elif s[0] == 255 and frame == 0 and block is not None: # # application extension # info["extension"] = block, self.fp.tell() - if block.startswith(b"NETSCAPE2.0"): + if block[:11] == b"NETSCAPE2.0": block = self.data() if block and len(block) >= 3 and block[0] == 1: self.info["loop"] = i16(block, 1) @@ -301,7 +294,7 @@ class GifImageFile(ImageFile.ImageFile): bits = self.fp.read(1)[0] self.__offset = self.fp.tell() break - s = b"" + s = None if interlace is None: msg = "image not found in GIF frame" @@ -327,20 +320,18 @@ class GifImageFile(ImageFile.ImageFile): else: self._mode = "L" - if palette: - self.palette = palette - elif self.global_palette: + if not palette and self.global_palette: from copy import copy - self.palette = copy(self.global_palette) - else: - self.palette = None + palette = copy(self.global_palette) + self.palette = palette else: if self.mode == "P": if ( LOADING_STRATEGY != LoadingStrategy.RGB_AFTER_DIFFERENT_PALETTE_ONLY or palette ): + self.pyaccess = None if "transparency" in self.info: self.im.putpalettealpha(self.info["transparency"], 0) self.im = self.im.convert("RGBA", Image.Dither.FLOYDSTEINBERG) @@ -354,15 +345,12 @@ class GifImageFile(ImageFile.ImageFile): if self._frame_palette: if color * 3 + 3 > len(self._frame_palette.palette): color = 0 - return cast( - tuple[int, int, int], - tuple(self._frame_palette.palette[color * 3 : color * 3 + 3]), - ) + return tuple(self._frame_palette.palette[color * 3 : color * 3 + 3]) else: return (color, color, color) self.dispose = None - self.dispose_extent: tuple[int, int, int, int] | None = frame_dispose_extent + self.dispose_extent = frame_dispose_extent if self.dispose_extent and self.disposal_method >= 2: try: if self.disposal_method == 2: @@ -389,7 +377,7 @@ class GifImageFile(ImageFile.ImageFile): self.dispose = Image.core.fill(dispose_mode, dispose_size, color) else: # replace with previous contents - if self._im is not None: + if self.im is not None: # only dispose the extent in this frame self.dispose = self._crop(self.im, self.dispose_extent) elif frame_transparency is not None: @@ -417,7 +405,7 @@ class GifImageFile(ImageFile.ImageFile): elif self.mode not in ("RGB", "RGBA"): transparency = frame_transparency self.tile = [ - ImageFile._Tile( + ( "gif", (x0, y0, x1, y1), self.__offset, @@ -447,14 +435,7 @@ class GifImageFile(ImageFile.ImageFile): self.im = Image.core.fill("P", self.size, self._frame_transparency or 0) self.im.putpalette("RGB", *self._frame_palette.getdata()) else: - self._im = None - if not self._prev_im and self._im is not None and self.size != self.im.size: - expanded_im = Image.core.fill(self.im.mode, self.size) - if self._frame_palette: - expanded_im.putpalette("RGB", *self._frame_palette.getdata()) - expanded_im.paste(self.im, (0, 0) + self.im.size) - - self.im = expanded_im + self.im = None self._mode = temp_mode self._frame_palette = None @@ -472,23 +453,9 @@ class GifImageFile(ImageFile.ImageFile): return if not self._prev_im: return - if self.size != self._prev_im.size: - if self._frame_transparency is not None: - expanded_im = Image.core.fill("RGBA", self.size) - else: - expanded_im = Image.core.fill("P", self.size) - expanded_im.putpalette("RGB", "RGB", self.im.getpalette()) - expanded_im = expanded_im.convert("RGB") - expanded_im.paste(self._prev_im, (0, 0) + self._prev_im.size) - - self._prev_im = expanded_im - assert self._prev_im is not None if self._frame_transparency is not None: - if self.mode == "L": - frame_im = self.im.convert_transparent("LA", self._frame_transparency) - else: - self.im.putpalettealpha(self._frame_transparency, 0) - frame_im = self.im.convert("RGBA") + self.im.putpalettealpha(self._frame_transparency, 0) + frame_im = self.im.convert("RGBA") else: frame_im = self.im.convert("RGB") @@ -497,7 +464,7 @@ class GifImageFile(ImageFile.ImageFile): self.im = self._prev_im self._mode = self.im.mode - if frame_im.mode in ("LA", "RGBA"): + if frame_im.mode == "RGBA": self.im.paste(frame_im, self.dispose_extent, frame_im) else: self.im.paste(frame_im, self.dispose_extent) @@ -529,7 +496,6 @@ def _normalize_mode(im: Image.Image) -> Image.Image: return im if Image.getmodebase(im.mode) == "RGB": im = im.convert("P", palette=Image.Palette.ADAPTIVE) - assert im.palette is not None if im.palette.mode == "RGBA": for rgba in im.palette.colors: if rgba[3] == 0: @@ -539,7 +505,7 @@ def _normalize_mode(im: Image.Image) -> Image.Image: return im.convert("L") -_Palette = bytes | bytearray | list[int] | ImagePalette.ImagePalette +_Palette = Union[bytes, bytearray, List[int], ImagePalette.ImagePalette] def _normalize_palette( @@ -566,18 +532,16 @@ def _normalize_palette( if im.mode == "P": if not source_palette: - im_palette = im.getpalette(None) - assert im_palette is not None - source_palette = bytearray(im_palette) + source_palette = im.im.getpalette("RGB")[:768] else: # L-mode if not source_palette: source_palette = bytearray(i // 3 for i in range(768)) im.palette = ImagePalette.ImagePalette("RGB", palette=source_palette) - assert source_palette is not None + used_palette_colors: list[int] | None if palette: - used_palette_colors: list[int | None] = [] - assert im.palette is not None + used_palette_colors = [] + assert source_palette is not None for i in range(0, len(source_palette), 3): source_color = tuple(source_palette[i : i + 3]) index = im.palette.colors.get(source_color) @@ -590,25 +554,20 @@ def _normalize_palette( if j not in used_palette_colors: used_palette_colors[i] = j break - dest_map: list[int] = [] - for index in used_palette_colors: - assert index is not None - dest_map.append(index) - im = im.remap_palette(dest_map) + im = im.remap_palette(used_palette_colors) else: - optimized_palette_colors = _get_optimize(im, info) - if optimized_palette_colors is not None: - im = im.remap_palette(optimized_palette_colors, source_palette) + used_palette_colors = _get_optimize(im, info) + if used_palette_colors is not None: + im = im.remap_palette(used_palette_colors, source_palette) if "transparency" in info: try: - info["transparency"] = optimized_palette_colors.index( + info["transparency"] = used_palette_colors.index( info["transparency"] ) except ValueError: del info["transparency"] return im - assert im.palette is not None im.palette.palette = source_palette return im @@ -620,8 +579,7 @@ def _write_single_frame( ) -> None: im_out = _normalize_mode(im) for k, v in im_out.info.items(): - if isinstance(k, str): - im.encoderinfo.setdefault(k, v) + im.encoderinfo.setdefault(k, v) im_out = _normalize_palette(im_out, palette, im.encoderinfo) for s in _get_global_header(im_out, im.encoderinfo): @@ -634,9 +592,7 @@ def _write_single_frame( _write_local_header(fp, im, (0, 0), flags) im_out.encoderconfig = (8, get_interlace(im)) - ImageFile._save( - im_out, fp, [ImageFile._Tile("gif", (0, 0) + im.size, 0, RAWMODE[im_out.mode])] - ) + ImageFile._save(im_out, fp, [("gif", (0, 0) + im.size, 0, RAWMODE[im_out.mode])]) fp.write(b"\0") # end of image data @@ -644,10 +600,7 @@ def _write_single_frame( def _getbbox( base_im: Image.Image, im_frame: Image.Image ) -> tuple[Image.Image, tuple[int, int, int, int] | None]: - palette_bytes = [ - bytes(im.palette.palette) if im.palette else b"" for im in (base_im, im_frame) - ] - if palette_bytes[0] != palette_bytes[1]: + if _get_palette_bytes(im_frame) != _get_palette_bytes(base_im): im_frame = im_frame.convert("RGBA") base_im = base_im.convert("RGBA") delta = ImageChops.subtract_modulo(im_frame, base_im) @@ -678,8 +631,7 @@ def _write_multiple_frames( for k, v in im_frame.info.items(): if k == "transparency": continue - if isinstance(k, str): - im.encoderinfo.setdefault(k, v) + im.encoderinfo.setdefault(k, v) encoderinfo = im.encoderinfo.copy() if "transparency" in im_frame.info: @@ -703,24 +655,16 @@ def _write_multiple_frames( im_frames[-1].encoderinfo["duration"] += encoderinfo["duration"] continue if im_frames[-1].encoderinfo.get("disposal") == 2: - # To appear correctly in viewers using a convention, - # only consider transparency, and not background color - color = im.encoderinfo.get( - "transparency", im.info.get("transparency") - ) - if color is not None: - if background_im is None: - background = _get_background(im_frame, color) - background_im = Image.new("P", im_frame.size, background) - first_palette = im_frames[0].im.palette - assert first_palette is not None - background_im.putpalette(first_palette, first_palette.mode) - bbox = _getbbox(background_im, im_frame)[1] - else: - bbox = (0, 0) + im_frame.size + if background_im is None: + color = im.encoderinfo.get( + "transparency", im.info.get("transparency", (0, 0, 0)) + ) + background = _get_background(im_frame, color) + background_im = Image.new("P", im_frame.size, background) + background_im.putpalette(im_frames[0].im.palette) + bbox = _getbbox(background_im, im_frame)[1] elif encoderinfo.get("optimize") and im_frame.mode != "1": if "transparency" not in encoderinfo: - assert im_frame.palette is not None try: encoderinfo["transparency"] = ( im_frame.palette._new_color_index(im_frame) @@ -753,7 +697,7 @@ def _write_multiple_frames( if delta.mode == "P": # Convert to L without considering palette delta_l = Image.new("L", delta.size) - delta_l.putdata(delta.get_flattened_data()) + delta_l.putdata(delta.getdata()) delta = delta_l mask = ImageMath.lambda_eval( lambda args: args["convert"](args["im"] * 255, "1"), @@ -783,8 +727,7 @@ def _write_multiple_frames( if not palette: frame_data.encoderinfo["include_color_table"] = True - if frame_data.bbox != (0, 0) + im_frame.size: - im_frame = im_frame.crop(frame_data.bbox) + im_frame = im_frame.crop(frame_data.bbox) offset = frame_data.bbox[:2] _write_frame_data(fp, im_frame, offset, frame_data.encoderinfo) return True @@ -959,7 +902,6 @@ def _get_optimize(im: Image.Image, info: dict[str, Any]) -> list[int] | None: if optimise or max(used_palette_colors) >= len(used_palette_colors): return used_palette_colors - assert im.palette is not None num_palette_colors = len(im.palette.palette) // Image.getmodebands( im.palette.mode ) @@ -1009,13 +951,7 @@ def _get_palette_bytes(im: Image.Image) -> bytes: :param im: Image object :returns: Bytes, len<=768 suitable for inclusion in gif header """ - if not im.palette: - return b"" - - palette = bytes(im.palette.palette) - if im.palette.mode == "RGBA": - palette = b"".join(palette[i * 4 : i * 4 + 3] for i in range(len(palette) // 3)) - return palette + return im.palette.palette if im.palette else b"" def _get_background( @@ -1028,7 +964,6 @@ def _get_background( # WebPImagePlugin stores an RGBA value in info["background"] # So it must be converted to the same format as GifImagePlugin's # info["background"] - a global color table index - assert im.palette is not None try: background = im.palette.getcolor(info_background, im) except ValueError as e: @@ -1120,9 +1055,7 @@ def _write_frame_data( _write_local_header(fp, im_frame, offset, 0) ImageFile._save( - im_frame, - fp, - [ImageFile._Tile("gif", (0, 0) + im_frame.size, 0, RAWMODE[im_frame.mode])], + im_frame, fp, [("gif", (0, 0) + im_frame.size, 0, RAWMODE[im_frame.mode])] ) fp.write(b"\0") # end of image data @@ -1188,9 +1121,18 @@ def getdata( class Collector(BytesIO): data = [] - def write(self, data: Buffer) -> int: - self.data.append(data) - return len(data) + if sys.version_info >= (3, 12): + from collections.abc import Buffer + + def write(self, data: Buffer) -> int: + self.data.append(data) + return len(data) + + else: + + def write(self, data: Any) -> int: + self.data.append(data) + return len(data) im.load() # make sure raster data is available diff --git a/venv/Lib/site-packages/PIL/GimpGradientFile.py b/venv/Lib/site-packages/PIL/GimpGradientFile.py index 5f26918..220eac5 100644 --- a/venv/Lib/site-packages/PIL/GimpGradientFile.py +++ b/venv/Lib/site-packages/PIL/GimpGradientFile.py @@ -21,14 +21,10 @@ See the GIMP distribution for more information.) from __future__ import annotations from math import log, pi, sin, sqrt +from typing import IO, Callable from ._binary import o8 -TYPE_CHECKING = False -if TYPE_CHECKING: - from collections.abc import Callable - from typing import IO - EPSILON = 1e-10 """""" # Enable auto-doc for data member @@ -120,7 +116,7 @@ class GimpGradientFile(GradientFile): """File handler for GIMP's gradient format.""" def __init__(self, fp: IO[bytes]) -> None: - if not fp.readline().startswith(b"GIMP Gradient"): + if fp.readline()[:13] != b"GIMP Gradient": msg = "not a GIMP gradient file" raise SyntaxError(msg) diff --git a/venv/Lib/site-packages/PIL/GimpPaletteFile.py b/venv/Lib/site-packages/PIL/GimpPaletteFile.py index 016257d..4cad0eb 100644 --- a/venv/Lib/site-packages/PIL/GimpPaletteFile.py +++ b/venv/Lib/site-packages/PIL/GimpPaletteFile.py @@ -16,11 +16,9 @@ from __future__ import annotations import re -from io import BytesIO +from typing import IO -TYPE_CHECKING = False -if TYPE_CHECKING: - from typing import IO +from ._binary import o8 class GimpPaletteFile: @@ -28,18 +26,14 @@ class GimpPaletteFile: rawmode = "RGB" - def _read(self, fp: IO[bytes], limit: bool = True) -> None: - if not fp.readline().startswith(b"GIMP Palette"): + def __init__(self, fp: IO[bytes]) -> None: + palette = [o8(i) * 3 for i in range(256)] + + if fp.readline()[:12] != b"GIMP Palette": msg = "not a GIMP palette file" raise SyntaxError(msg) - palette: list[int] = [] - i = 0 - while True: - if limit and i == 256 + 3: - break - - i += 1 + for i in range(256): s = fp.readline() if not s: break @@ -47,29 +41,18 @@ class GimpPaletteFile: # skip fields and comment lines if re.match(rb"\w+:|#", s): continue - if limit and len(s) > 100: + if len(s) > 100: msg = "bad palette file" raise SyntaxError(msg) - v = s.split(maxsplit=3) - if len(v) < 3: + v = tuple(map(int, s.split()[:3])) + if len(v) != 3: msg = "bad palette entry" raise ValueError(msg) - palette += (int(v[i]) for i in range(3)) - if limit and len(palette) == 768: - break + palette[i] = o8(v[0]) + o8(v[1]) + o8(v[2]) - self.palette = bytes(palette) - - def __init__(self, fp: IO[bytes]) -> None: - self._read(fp) - - @classmethod - def frombytes(cls, data: bytes) -> GimpPaletteFile: - self = cls.__new__(cls) - self._read(BytesIO(data), False) - return self + self.palette = b"".join(palette) def getpalette(self) -> tuple[bytes, str]: return self.palette, self.rawmode diff --git a/venv/Lib/site-packages/PIL/GribStubImagePlugin.py b/venv/Lib/site-packages/PIL/GribStubImagePlugin.py index 146a6fa..e9aa084 100644 --- a/venv/Lib/site-packages/PIL/GribStubImagePlugin.py +++ b/venv/Lib/site-packages/PIL/GribStubImagePlugin.py @@ -10,7 +10,6 @@ # from __future__ import annotations -import os from typing import IO from . import Image, ImageFile @@ -33,7 +32,7 @@ def register_handler(handler: ImageFile.StubHandler | None) -> None: def _accept(prefix: bytes) -> bool: - return len(prefix) >= 8 and prefix.startswith(b"GRIB") and prefix[7] == 1 + return prefix[:4] == b"GRIB" and prefix[7] == 1 class GribStubImageFile(ImageFile.StubImageFile): @@ -41,12 +40,13 @@ class GribStubImageFile(ImageFile.StubImageFile): format_description = "GRIB" def _open(self) -> None: - assert self.fp is not None + offset = self.fp.tell() + if not _accept(self.fp.read(8)): msg = "Not a GRIB file" raise SyntaxError(msg) - self.fp.seek(-8, os.SEEK_CUR) + self.fp.seek(offset) # make something up self._mode = "F" diff --git a/venv/Lib/site-packages/PIL/Hdf5StubImagePlugin.py b/venv/Lib/site-packages/PIL/Hdf5StubImagePlugin.py index 1523e95..cc9e73d 100644 --- a/venv/Lib/site-packages/PIL/Hdf5StubImagePlugin.py +++ b/venv/Lib/site-packages/PIL/Hdf5StubImagePlugin.py @@ -10,7 +10,6 @@ # from __future__ import annotations -import os from typing import IO from . import Image, ImageFile @@ -33,7 +32,7 @@ def register_handler(handler: ImageFile.StubHandler | None) -> None: def _accept(prefix: bytes) -> bool: - return prefix.startswith(b"\x89HDF\r\n\x1a\n") + return prefix[:8] == b"\x89HDF\r\n\x1a\n" class HDF5StubImageFile(ImageFile.StubImageFile): @@ -41,12 +40,13 @@ class HDF5StubImageFile(ImageFile.StubImageFile): format_description = "HDF5" def _open(self) -> None: - assert self.fp is not None + offset = self.fp.tell() + if not _accept(self.fp.read(8)): msg = "Not an HDF file" raise SyntaxError(msg) - self.fp.seek(-8, os.SEEK_CUR) + self.fp.seek(offset) # make something up self._mode = "F" diff --git a/venv/Lib/site-packages/PIL/IcnsImagePlugin.py b/venv/Lib/site-packages/PIL/IcnsImagePlugin.py index 058861d..2a89d49 100644 --- a/venv/Lib/site-packages/PIL/IcnsImagePlugin.py +++ b/venv/Lib/site-packages/PIL/IcnsImagePlugin.py @@ -34,13 +34,11 @@ MAGIC = b"icns" HEADERSIZE = 8 -def nextheader(fobj: IO[bytes]) -> tuple[bytes, int]: +def nextheader(fobj): return struct.unpack(">4sI", fobj.read(HEADERSIZE)) -def read_32t( - fobj: IO[bytes], start_length: tuple[int, int], size: tuple[int, int, int] -) -> dict[str, Image.Image]: +def read_32t(fobj, start_length, size): # The 128x128 icon seems to have an extra header for some reason. (start, length) = start_length fobj.seek(start) @@ -51,9 +49,7 @@ def read_32t( return read_32(fobj, (start + 4, length - 4), size) -def read_32( - fobj: IO[bytes], start_length: tuple[int, int], size: tuple[int, int, int] -) -> dict[str, Image.Image]: +def read_32(fobj, start_length, size): """ Read a 32bit RGB icon resource. Seems to be either uncompressed or an RLE packbits-like scheme. @@ -76,14 +72,14 @@ def read_32( byte = fobj.read(1) if not byte: break - byte_int = byte[0] - if byte_int & 0x80: - blocksize = byte_int - 125 + byte = byte[0] + if byte & 0x80: + blocksize = byte - 125 byte = fobj.read(1) for i in range(blocksize): data.append(byte) else: - blocksize = byte_int + 1 + blocksize = byte + 1 data.append(fobj.read(blocksize)) bytesleft -= blocksize if bytesleft <= 0: @@ -96,9 +92,7 @@ def read_32( return {"RGB": im} -def read_mk( - fobj: IO[bytes], start_length: tuple[int, int], size: tuple[int, int, int] -) -> dict[str, Image.Image]: +def read_mk(fobj, start_length, size): # Alpha masks seem to be uncompressed start = start_length[0] fobj.seek(start) @@ -108,21 +102,18 @@ def read_mk( return {"A": band} -def read_png_or_jpeg2000( - fobj: IO[bytes], start_length: tuple[int, int], size: tuple[int, int, int] -) -> dict[str, Image.Image]: +def read_png_or_jpeg2000(fobj, start_length, size): (start, length) = start_length fobj.seek(start) sig = fobj.read(12) - - im: Image.Image - if sig.startswith(b"\x89PNG\x0d\x0a\x1a\x0a"): + if sig[:8] == b"\x89PNG\x0d\x0a\x1a\x0a": fobj.seek(start) im = PngImagePlugin.PngImageFile(fobj) Image._decompression_bomb_check(im.size) return {"RGBA": im} elif ( - sig.startswith((b"\xff\x4f\xff\x51", b"\x0d\x0a\x87\x0a")) + sig[:4] == b"\xff\x4f\xff\x51" + or sig[:4] == b"\x0d\x0a\x87\x0a" or sig == b"\x00\x00\x00\x0cjP \x0d\x0a\x87\x0a" ): if not enable_jpeg2k: @@ -173,12 +164,12 @@ class IcnsFile: ], } - def __init__(self, fobj: IO[bytes]) -> None: + def __init__(self, fobj): """ fobj is a file-like object as an icns resource """ # signature : (start, length) - self.dct = {} + self.dct = dct = {} self.fobj = fobj sig, filesize = nextheader(fobj) if not _accept(sig): @@ -192,11 +183,11 @@ class IcnsFile: raise SyntaxError(msg) i += HEADERSIZE blocksize -= HEADERSIZE - self.dct[sig] = (i, blocksize) + dct[sig] = (i, blocksize) fobj.seek(blocksize, io.SEEK_CUR) i += blocksize - def itersizes(self) -> list[tuple[int, int, int]]: + def itersizes(self): sizes = [] for size, fmts in self.SIZES.items(): for fmt, reader in fmts: @@ -205,14 +196,14 @@ class IcnsFile: break return sizes - def bestsize(self) -> tuple[int, int, int]: + def bestsize(self): sizes = self.itersizes() if not sizes: msg = "No 32bit icon resources found" raise SyntaxError(msg) return max(sizes) - def dataforsize(self, size: tuple[int, int, int]) -> dict[str, Image.Image]: + def dataforsize(self, size): """ Get an icon resource as {channel: array}. Note that the arrays are bottom-up like windows bitmaps and will likely @@ -225,20 +216,18 @@ class IcnsFile: dct.update(reader(self.fobj, desc, size)) return dct - def getimage( - self, size: tuple[int, int] | tuple[int, int, int] | None = None - ) -> Image.Image: + def getimage(self, size=None): if size is None: size = self.bestsize() - elif len(size) == 2: + if len(size) == 2: size = (size[0], size[1], 1) channels = self.dataforsize(size) - im = channels.get("RGBA") + im = channels.get("RGBA", None) if im: return im - im = channels["RGB"].copy() + im = channels.get("RGB").copy() try: im.putalpha(channels["A"]) except KeyError: @@ -265,7 +254,6 @@ class IcnsImageFile(ImageFile.ImageFile): format_description = "Mac OS icns resource" def _open(self) -> None: - assert self.fp is not None self.icns = IcnsFile(self.fp) self._mode = "RGBA" self.info["sizes"] = self.icns.itersizes() @@ -276,30 +264,39 @@ class IcnsImageFile(ImageFile.ImageFile): ) @property - def size(self) -> tuple[int, int]: + def size(self): return self._size @size.setter - def size(self, value: tuple[int, int]) -> None: - # Check that a matching size exists, - # or that there is a scale that would create a size that matches - for size in self.info["sizes"]: - simple_size = size[0] * size[2], size[1] * size[2] - scale = simple_size[0] // value[0] - if simple_size[1] / value[1] == scale: - self._size = value - return - msg = "This is not one of the allowed sizes of this image" - raise ValueError(msg) + def size(self, value): + info_size = value + if info_size not in self.info["sizes"] and len(info_size) == 2: + info_size = (info_size[0], info_size[1], 1) + if ( + info_size not in self.info["sizes"] + and len(info_size) == 3 + and info_size[2] == 1 + ): + simple_sizes = [ + (size[0] * size[2], size[1] * size[2]) for size in self.info["sizes"] + ] + if value in simple_sizes: + info_size = self.info["sizes"][simple_sizes.index(value)] + if info_size not in self.info["sizes"]: + msg = "This is not one of the allowed sizes of this image" + raise ValueError(msg) + self._size = value - def load(self, scale: int | None = None) -> Image.core.PixelAccess | None: - if scale is not None: - width, height = self.size[:2] - self.size = width * scale, height * scale - self.best_size = width, height, scale + def load(self): + if len(self.size) == 3: + self.best_size = self.size + self.size = ( + self.best_size[0] * self.best_size[2], + self.best_size[1] * self.best_size[2], + ) px = Image.Image.load(self) - if self._im is not None and self.im.size == self.size: + if self.im is not None and self.im.size == self.size: # Already loaded return px self.load_prepare() @@ -377,7 +374,7 @@ def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: def _accept(prefix: bytes) -> bool: - return prefix.startswith(MAGIC) + return prefix[:4] == MAGIC Image.register_open(IcnsImageFile.format, IcnsImageFile, _accept) diff --git a/venv/Lib/site-packages/PIL/IcoImagePlugin.py b/venv/Lib/site-packages/PIL/IcoImagePlugin.py index 8dd57ff..227fcf3 100644 --- a/venv/Lib/site-packages/PIL/IcoImagePlugin.py +++ b/venv/Lib/site-packages/PIL/IcoImagePlugin.py @@ -17,20 +17,6 @@ # . # https://code.google.com/archive/p/casadebender/wikis/Win32IconImagePlugin.wiki # -# Copyright 2008 Bryan Davis -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - # Icon format references: # * https://en.wikipedia.org/wiki/ICO_(file_format) # * https://msdn.microsoft.com/en-us/library/ms997538.aspx @@ -39,7 +25,7 @@ from __future__ import annotations import warnings from io import BytesIO from math import ceil, log -from typing import IO, NamedTuple +from typing import IO from . import BmpImagePlugin, Image, ImageFile, PngImagePlugin from ._binary import i16le as i16 @@ -111,9 +97,7 @@ def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: if bits != 32: and_mask = Image.new("1", size) ImageFile._save( - and_mask, - image_io, - [ImageFile._Tile("raw", (0, 0) + size, 0, ("1", 0, -1))], + and_mask, image_io, [("raw", (0, 0) + size, 0, ("1", 0, -1))] ) else: frame.save(image_io, "png") @@ -132,25 +116,11 @@ def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: def _accept(prefix: bytes) -> bool: - return prefix.startswith(_MAGIC) - - -class IconHeader(NamedTuple): - width: int - height: int - nb_color: int - reserved: int - planes: int - bpp: int - size: int - offset: int - dim: tuple[int, int] - square: int - color_depth: int + return prefix[:4] == _MAGIC class IcoFile: - def __init__(self, buf: IO[bytes]) -> None: + def __init__(self, buf): """ Parse image from file-like object containing ico file data """ @@ -171,48 +141,55 @@ class IcoFile: for i in range(self.nb_items): s = buf.read(16) - # See Wikipedia - width = s[0] or 256 - height = s[1] or 256 + icon_header = { + "width": s[0], + "height": s[1], + "nb_color": s[2], # No. of colors in image (0 if >=8bpp) + "reserved": s[3], + "planes": i16(s, 4), + "bpp": i16(s, 6), + "size": i32(s, 8), + "offset": i32(s, 12), + } - # No. of colors in image (0 if >=8bpp) - nb_color = s[2] - bpp = i16(s, 6) - icon_header = IconHeader( - width=width, - height=height, - nb_color=nb_color, - reserved=s[3], - planes=i16(s, 4), - bpp=i16(s, 6), - size=i32(s, 8), - offset=i32(s, 12), - dim=(width, height), - square=width * height, - # See Wikipedia notes about color depth. - # We need this just to differ images with equal sizes - color_depth=bpp or (nb_color != 0 and ceil(log(nb_color, 2))) or 256, + # See Wikipedia + for j in ("width", "height"): + if not icon_header[j]: + icon_header[j] = 256 + + # See Wikipedia notes about color depth. + # We need this just to differ images with equal sizes + icon_header["color_depth"] = ( + icon_header["bpp"] + or ( + icon_header["nb_color"] != 0 + and ceil(log(icon_header["nb_color"], 2)) + ) + or 256 ) + icon_header["dim"] = (icon_header["width"], icon_header["height"]) + icon_header["square"] = icon_header["width"] * icon_header["height"] + self.entry.append(icon_header) - self.entry = sorted(self.entry, key=lambda x: x.color_depth) + self.entry = sorted(self.entry, key=lambda x: x["color_depth"]) # ICO images are usually squares - self.entry = sorted(self.entry, key=lambda x: x.square, reverse=True) + self.entry = sorted(self.entry, key=lambda x: x["square"], reverse=True) - def sizes(self) -> set[tuple[int, int]]: + def sizes(self): """ - Get a set of all available icon sizes and color depths. + Get a list of all available icon sizes and color depths. """ - return {(h.width, h.height) for h in self.entry} + return {(h["width"], h["height"]) for h in self.entry} - def getentryindex(self, size: tuple[int, int], bpp: int | bool = False) -> int: + def getentryindex(self, size, bpp=False): for i, h in enumerate(self.entry): - if size == h.dim and (bpp is False or bpp == h.color_depth): + if size == h["dim"] and (bpp is False or bpp == h["color_depth"]): return i return 0 - def getimage(self, size: tuple[int, int], bpp: int | bool = False) -> Image.Image: + def getimage(self, size, bpp=False): """ Get an image from the icon """ @@ -225,9 +202,9 @@ class IcoFile: header = self.entry[idx] - self.buf.seek(header.offset) + self.buf.seek(header["offset"]) data = self.buf.read(8) - self.buf.seek(header.offset) + self.buf.seek(header["offset"]) im: Image.Image if data[:8] == PngImagePlugin._MAGIC: @@ -242,10 +219,11 @@ class IcoFile: # change tile dimension to only encompass XOR image im._size = (im.size[0], int(im.size[1] / 2)) d, e, o, a = im.tile[0] - im.tile[0] = ImageFile._Tile(d, (0, 0) + im.size, o, a) + im.tile[0] = d, (0, 0) + im.size, o, a # figure out where AND mask image starts - if header.bpp == 32: + bpp = header["bpp"] + if 32 == bpp: # 32-bit color depth icon image allows semitransparent areas # PIL's DIB format ignores transparency bits, recover them. # The DIB is packed in BGRX byte order where X is the alpha @@ -257,19 +235,13 @@ class IcoFile: alpha_bytes = self.buf.read(im.size[0] * im.size[1] * 4)[3::4] # convert to an 8bpp grayscale image - try: - mask = Image.frombuffer( - "L", # 8bpp - im.size, # (w, h) - alpha_bytes, # source chars - "raw", # raw decoder - ("L", 0, -1), # 8bpp inverted, unpadded, reversed - ) - except ValueError: - if ImageFile.LOAD_TRUNCATED_IMAGES: - mask = None - else: - raise + mask = Image.frombuffer( + "L", # 8bpp + im.size, # (w, h) + alpha_bytes, # source chars + "raw", # raw decoder + ("L", 0, -1), # 8bpp inverted, unpadded, reversed + ) else: # get AND image from end of bitmap w = im.size[0] @@ -281,32 +253,25 @@ class IcoFile: # padded row size * height / bits per char total_bytes = int((w * im.size[1]) / 8) - and_mask_offset = header.offset + header.size - total_bytes + and_mask_offset = header["offset"] + header["size"] - total_bytes self.buf.seek(and_mask_offset) mask_data = self.buf.read(total_bytes) # convert raw data to image - try: - mask = Image.frombuffer( - "1", # 1 bpp - im.size, # (w, h) - mask_data, # source chars - "raw", # raw decoder - ("1;I", int(w / 8), -1), # 1bpp inverted, padded, reversed - ) - except ValueError: - if ImageFile.LOAD_TRUNCATED_IMAGES: - mask = None - else: - raise + mask = Image.frombuffer( + "1", # 1 bpp + im.size, # (w, h) + mask_data, # source chars + "raw", # raw decoder + ("1;I", int(w / 8), -1), # 1bpp inverted, padded, reversed + ) # now we have two images, im is XOR image and mask is AND image # apply mask image as alpha channel - if mask: - im = im.convert("RGBA") - im.putalpha(mask) + im = im.convert("RGBA") + im.putalpha(mask) return im @@ -340,31 +305,31 @@ class IcoImageFile(ImageFile.ImageFile): format_description = "Windows Icon" def _open(self) -> None: - assert self.fp is not None self.ico = IcoFile(self.fp) self.info["sizes"] = self.ico.sizes() - self.size = self.ico.entry[0].dim + self.size = self.ico.entry[0]["dim"] self.load() @property - def size(self) -> tuple[int, int]: + def size(self): return self._size @size.setter - def size(self, value: tuple[int, int]) -> None: + def size(self, value): if value not in self.info["sizes"]: msg = "This is not one of the allowed sizes of this image" raise ValueError(msg) self._size = value - def load(self) -> Image.core.PixelAccess | None: - if self._im is not None and self.im.size == self.size: + def load(self): + if self.im is not None and self.im.size == self.size: # Already loaded return Image.Image.load(self) im = self.ico.getimage(self.size) # if tile is PNG, it won't really be loaded yet im.load() self.im = im.im + self.pyaccess = None self._mode = im.mode if im.palette: self.palette = im.palette @@ -377,7 +342,6 @@ class IcoImageFile(ImageFile.ImageFile): self.info["sizes"] = set(sizes) self.size = im.size - return Image.Image.load(self) def load_seek(self, pos: int) -> None: # Flag the ImageFile.Parser so that it diff --git a/venv/Lib/site-packages/PIL/ImImagePlugin.py b/venv/Lib/site-packages/PIL/ImImagePlugin.py index ef54f16..2fb7ecd 100644 --- a/venv/Lib/site-packages/PIL/ImImagePlugin.py +++ b/venv/Lib/site-packages/PIL/ImImagePlugin.py @@ -31,7 +31,6 @@ import re from typing import IO, Any from . import Image, ImageFile, ImagePalette -from ._util import DeferredError # -------------------------------------------------------------------- # Standard tags @@ -125,7 +124,6 @@ class ImImageFile(ImageFile.ImageFile): # Quick rejection: if there's not an LF among the first # 100 bytes, this is (probably) not a text header. - assert self.fp is not None if b"\n" not in self.fp.read(100): msg = "not an IM file" raise SyntaxError(msg) @@ -147,7 +145,7 @@ class ImImageFile(ImageFile.ImageFile): if s == b"\r": continue - if not s or s == b"\0" or s == b"\x1a": + if not s or s == b"\0" or s == b"\x1A": break # FIXME: this may read whole file if not a text file @@ -157,9 +155,9 @@ class ImImageFile(ImageFile.ImageFile): msg = "not an IM file" raise SyntaxError(msg) - if s.endswith(b"\r\n"): + if s[-2:] == b"\r\n": s = s[:-2] - elif s.endswith(b"\n"): + elif s[-1:] == b"\n": s = s[:-1] try: @@ -211,7 +209,7 @@ class ImImageFile(ImageFile.ImageFile): self._mode = self.info[MODE] # Skip forward to start of image data - while s and not s.startswith(b"\x1a"): + while s and s[:1] != b"\x1A": s = self.fp.read(1) if not s: msg = "File truncated" @@ -249,17 +247,13 @@ class ImImageFile(ImageFile.ImageFile): self._fp = self.fp # FIXME: hack - if self.rawmode.startswith("F;"): + if self.rawmode[:2] == "F;": # ifunc95 formats try: # use bit decoder (if necessary) bits = int(self.rawmode[2:]) if bits not in [8, 16, 32]: - self.tile = [ - ImageFile._Tile( - "bit", (0, 0) + self.size, offs, (bits, 8, 3, 0, -1) - ) - ] + self.tile = [("bit", (0, 0) + self.size, offs, (bits, 8, 3, 0, -1))] return except ValueError: pass @@ -269,17 +263,13 @@ class ImImageFile(ImageFile.ImageFile): # ever stumbled upon such a file ;-) size = self.size[0] * self.size[1] self.tile = [ - ImageFile._Tile("raw", (0, 0) + self.size, offs, ("G", 0, -1)), - ImageFile._Tile("raw", (0, 0) + self.size, offs + size, ("R", 0, -1)), - ImageFile._Tile( - "raw", (0, 0) + self.size, offs + 2 * size, ("B", 0, -1) - ), + ("raw", (0, 0) + self.size, offs, ("G", 0, -1)), + ("raw", (0, 0) + self.size, offs + size, ("R", 0, -1)), + ("raw", (0, 0) + self.size, offs + 2 * size, ("B", 0, -1)), ] else: # LabEye/IFUNC files - self.tile = [ - ImageFile._Tile("raw", (0, 0) + self.size, offs, (self.rawmode, 0, -1)) - ] + self.tile = [("raw", (0, 0) + self.size, offs, (self.rawmode, 0, -1))] @property def n_frames(self) -> int: @@ -292,8 +282,6 @@ class ImImageFile(ImageFile.ImageFile): def seek(self, frame: int) -> None: if not self._seek_check(frame): return - if isinstance(self._fp, DeferredError): - raise self._fp.ex self.frame = frame @@ -307,9 +295,7 @@ class ImImageFile(ImageFile.ImageFile): self.fp = self._fp - self.tile = [ - ImageFile._Tile("raw", (0, 0) + self.size, offs, (self.rawmode, 0, -1)) - ] + self.tile = [("raw", (0, 0) + self.size, offs, (self.rawmode, 0, -1))] def tell(self) -> int: return self.frame @@ -361,7 +347,7 @@ def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: name = "".join([name[: 92 - len(ext)], ext]) fp.write(f"Name: {name}\r\n".encode("ascii")) - fp.write(f"Image size (x*y): {im.size[0]}*{im.size[1]}\r\n".encode("ascii")) + fp.write(("Image size (x*y): %d*%d\r\n" % im.size).encode("ascii")) fp.write(f"File size (no of images): {frames}\r\n".encode("ascii")) if im.mode in ["P", "PA"]: fp.write(b"Lut: 1\r\n") @@ -374,9 +360,7 @@ def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: palette += im_palette[colors * i : colors * (i + 1)] palette += b"\x00" * (256 - colors) fp.write(palette) # 768 bytes - ImageFile._save( - im, fp, [ImageFile._Tile("raw", (0, 0) + im.size, 0, (rawmode, 0, -1))] - ) + ImageFile._save(im, fp, [("raw", (0, 0) + im.size, 0, (rawmode, 0, -1))]) # diff --git a/venv/Lib/site-packages/PIL/Image.py b/venv/Lib/site-packages/PIL/Image.py index 57ebea6..d41c065 100644 --- a/venv/Lib/site-packages/PIL/Image.py +++ b/venv/Lib/site-packages/PIL/Image.py @@ -38,9 +38,19 @@ import struct import sys import tempfile import warnings -from collections.abc import MutableMapping +from collections.abc import Callable, MutableMapping from enum import IntEnum -from typing import IO, Protocol, cast +from types import ModuleType +from typing import ( + IO, + TYPE_CHECKING, + Any, + Literal, + Protocol, + Sequence, + Tuple, + cast, +) # VERSION was removed in Pillow 6.0.0. # PILLOW_VERSION was removed in Pillow 9.0.0. @@ -55,6 +65,7 @@ from . import ( ) from ._binary import i32le, o32be, o32le from ._deprecate import deprecate +from ._typing import StrOrBytesPath, TypeGuard from ._util import DeferredError, is_path ElementTree: ModuleType | None @@ -63,12 +74,6 @@ try: except ImportError: ElementTree = None -TYPE_CHECKING = False -if TYPE_CHECKING: - from collections.abc import Callable, Iterator, Sequence - from types import ModuleType - from typing import Any, Literal - logger = logging.getLogger(__name__) @@ -103,6 +108,7 @@ try: raise ImportError(msg) except ImportError as v: + core = DeferredError.new(ImportError("The _imaging C module is not installed.")) # Explanations for ways that we know we might have an import error if str(v).startswith("Module use of python"): # The _imaging C module is present, but not compiled for @@ -119,6 +125,28 @@ except ImportError as v: raise +USE_CFFI_ACCESS = False +cffi: ModuleType | None +try: + import cffi +except ImportError: + cffi = None + + +def isImageType(t: Any) -> TypeGuard[Image]: + """ + Checks if an object is an image object. + + .. warning:: + + This function is for internal use only. + + :param t: object to check if it's an image + :returns: True if the object is an image + """ + return hasattr(t, "im") + + # # Constants @@ -200,15 +228,8 @@ if hasattr(core, "DEFAULT_STRATEGY"): # -------------------------------------------------------------------- # Registries -TYPE_CHECKING = False if TYPE_CHECKING: - import mmap - from xml.etree.ElementTree import Element - - from IPython.lib.pretty import PrettyPrinter - - from . import ImageFile, ImageFilter, ImagePalette, ImageQt, TiffImagePlugin - from ._typing import CapsuleType, NumpyArray, StrOrBytesPath + from . import ImageFile, PyAccess ID: list[str] = [] OPEN: dict[ str, @@ -230,9 +251,9 @@ ENCODERS: dict[str, type[ImageFile.PyEncoder]] = {} _ENDIAN = "<" if sys.byteorder == "little" else ">" -def _conv_type_shape(im: Image) -> tuple[tuple[int, ...], str]: +def _conv_type_shape(im): m = ImageMode.getmode(im.mode) - shape: tuple[int, ...] = (im.height, im.width) + shape = (im.height, im.width) extra = len(m.bands) if extra != 1: shape += (extra,) @@ -454,53 +475,43 @@ def _getencoder( # Simple expression analyzer -class ImagePointTransform: - """ - Used with :py:meth:`~PIL.Image.Image.point` for single band images with more than - 8 bits, this represents an affine transformation, where the value is multiplied by - ``scale`` and ``offset`` is added. - """ - - def __init__(self, scale: float, offset: float) -> None: +class _E: + def __init__(self, scale, offset) -> None: self.scale = scale self.offset = offset - def __neg__(self) -> ImagePointTransform: - return ImagePointTransform(-self.scale, -self.offset) + def __neg__(self): + return _E(-self.scale, -self.offset) - def __add__(self, other: ImagePointTransform | float) -> ImagePointTransform: - if isinstance(other, ImagePointTransform): - return ImagePointTransform( - self.scale + other.scale, self.offset + other.offset - ) - return ImagePointTransform(self.scale, self.offset + other) + def __add__(self, other): + if isinstance(other, _E): + return _E(self.scale + other.scale, self.offset + other.offset) + return _E(self.scale, self.offset + other) __radd__ = __add__ - def __sub__(self, other: ImagePointTransform | float) -> ImagePointTransform: + def __sub__(self, other): return self + -other - def __rsub__(self, other: ImagePointTransform | float) -> ImagePointTransform: + def __rsub__(self, other): return other + -self - def __mul__(self, other: ImagePointTransform | float) -> ImagePointTransform: - if isinstance(other, ImagePointTransform): + def __mul__(self, other): + if isinstance(other, _E): return NotImplemented - return ImagePointTransform(self.scale * other, self.offset * other) + return _E(self.scale * other, self.offset * other) __rmul__ = __mul__ - def __truediv__(self, other: ImagePointTransform | float) -> ImagePointTransform: - if isinstance(other, ImagePointTransform): + def __truediv__(self, other): + if isinstance(other, _E): return NotImplemented - return ImagePointTransform(self.scale / other, self.offset / other) + return _E(self.scale / other, self.offset / other) -def _getscaleoffset( - expr: Callable[[ImagePointTransform], ImagePointTransform | float], -) -> tuple[float, float]: - a = expr(ImagePointTransform(1, 0)) - return (a.scale, a.offset) if isinstance(a, ImagePointTransform) else (0, a) +def _getscaleoffset(expr): + a = expr(_E(1, 0)) + return (a.scale, a.offset) if isinstance(a, _E) else (0, a) # -------------------------------------------------------------------- @@ -529,26 +540,17 @@ class Image: format_description: str | None = None _close_exclusive_fp_after_loading = True - def __init__(self) -> None: + def __init__(self): # FIXME: take "new" parameters / other image? - self._im: core.ImagingCore | DeferredError | None = None + # FIXME: turn mode and size into delegating properties? + self.im = None self._mode = "" self._size = (0, 0) - self.palette: ImagePalette.ImagePalette | None = None - self.info: dict[str | tuple[int, int], Any] = {} + self.palette = None + self.info = {} self.readonly = 0 - self._exif: Exif | None = None - - @property - def im(self) -> core.ImagingCore: - if isinstance(self._im, DeferredError): - raise self._im.ex - assert self._im is not None - return self._im - - @im.setter - def im(self, im: core.ImagingCore) -> None: - self._im = im + self.pyaccess = None + self._exif = None @property def width(self) -> int: @@ -566,14 +568,6 @@ class Image: def mode(self) -> str: return self._mode - @property - def readonly(self) -> int: - return (self._im and self._im.readonly) or self._readonly - - @readonly.setter - def readonly(self, readonly: int) -> None: - self._readonly = readonly - def _new(self, im: core.ImagingCore) -> Image: new = Image() new.im = im @@ -590,14 +584,27 @@ class Image: return new # Context manager support - def __enter__(self) -> Image: + def __enter__(self): return self - def __exit__(self, *args: object) -> None: - pass + def _close_fp(self): + if getattr(self, "_fp", False): + if self._fp != self.fp: + self._fp.close() + self._fp = DeferredError(ValueError("Operation on closed image")) + if self.fp: + self.fp.close() + + def __exit__(self, *args): + if hasattr(self, "fp"): + if getattr(self, "_exclusive_fp", False): + self._close_fp() + self.fp = None def close(self) -> None: """ + Closes the file pointer, if possible. + This operation will destroy the image core and release its memory. The image data will be unusable afterward. @@ -606,19 +613,25 @@ class Image: :py:meth:`~PIL.Image.Image.load` method. See :ref:`file-handling` for more information. """ + if hasattr(self, "fp"): + try: + self._close_fp() + self.fp = None + except Exception as msg: + logger.debug("Error closing: %s", msg) + if getattr(self, "map", None): - if sys.platform == "win32" and hasattr(sys, "pypy_version_info"): - self.map.close() - self.map: mmap.mmap | None = None + self.map = None # Instead of simply setting to None, we're setting up a # deferred error that will better explain that the core image # object is gone. - self._im = DeferredError(ValueError("Operation on closed image")) + self.im = DeferredError(ValueError("Operation on closed image")) def _copy(self) -> None: self.load() self.im = self.im.copy() + self.pyaccess = None self.readonly = 0 def _ensure_mutable(self) -> None: @@ -664,20 +677,29 @@ class Image: ) def __repr__(self) -> str: - return ( - f"<{self.__class__.__module__}.{self.__class__.__name__} " - f"image mode={self.mode} size={self.size[0]}x{self.size[1]} " - f"at 0x{id(self):X}>" + return "<%s.%s image mode=%s size=%dx%d at 0x%X>" % ( + self.__class__.__module__, + self.__class__.__name__, + self.mode, + self.size[0], + self.size[1], + id(self), ) - def _repr_pretty_(self, p: PrettyPrinter, cycle: bool) -> None: + def _repr_pretty_(self, p, cycle) -> None: """IPython plain text display support""" # Same as __repr__ but without unpredictable id(self), # to keep Jupyter notebook `text/plain` output stable. p.text( - f"<{self.__class__.__module__}.{self.__class__.__name__} " - f"image mode={self.mode} size={self.size[0]}x{self.size[1]}>" + "<%s.%s image mode=%s size=%dx%d>" + % ( + self.__class__.__module__, + self.__class__.__name__, + self.mode, + self.size[0], + self.size[1], + ) ) def _repr_image(self, image_format: str, **kwargs: Any) -> bytes | None: @@ -708,35 +730,37 @@ class Image: return self._repr_image("JPEG") @property - def __array_interface__(self) -> dict[str, str | bytes | int | tuple[int, ...]]: + def __array_interface__(self): # numpy array interface support - new: dict[str, str | bytes | int | tuple[int, ...]] = {"version": 3} - if self.mode == "1": - # Binary images need to be extended from bits to bytes - # See: https://github.com/python-pillow/Pillow/issues/350 - new["data"] = self.tobytes("raw", "L") - else: - new["data"] = self.tobytes() + new = {"version": 3} + try: + if self.mode == "1": + # Binary images need to be extended from bits to bytes + # See: https://github.com/python-pillow/Pillow/issues/350 + new["data"] = self.tobytes("raw", "L") + else: + new["data"] = self.tobytes() + except Exception as e: + if not isinstance(e, (MemoryError, RecursionError)): + try: + import numpy + from packaging.version import parse as parse_version + except ImportError: + pass + else: + if parse_version(numpy.__version__) < parse_version("1.23"): + warnings.warn(str(e)) + raise new["shape"], new["typestr"] = _conv_type_shape(self) return new - def __arrow_c_schema__(self) -> object: - self.load() - return self.im.__arrow_c_schema__() - - def __arrow_c_array__( - self, requested_schema: object | None = None - ) -> tuple[object, object]: - self.load() - return (self.im.__arrow_c_schema__(), self.im.__arrow_c_array__()) - - def __getstate__(self) -> list[Any]: + def __getstate__(self): im_data = self.tobytes() # load image first return [self.info, self.mode, self.size, self.getpalette(), im_data] - def __setstate__(self, state: list[Any]) -> None: + def __setstate__(self, state) -> None: Image.__init__(self) - info, mode, size, palette, data = state[:5] + info, mode, size, palette, data = state self.info = info self._mode = mode self._size = size @@ -751,20 +775,18 @@ class Image: .. warning:: - This method returns raw image data derived from Pillow's internal - storage. For compressed image data (e.g. PNG, JPEG) use - :meth:`~.save`, with a BytesIO parameter for in-memory data. + This method returns the raw image data from the internal + storage. For compressed image data (e.g. PNG, JPEG) use + :meth:`~.save`, with a BytesIO parameter for in-memory + data. - :param encoder_name: What encoder to use. + :param encoder_name: What encoder to use. The default is to + use the standard "raw" encoder. - The default is to use the standard "raw" encoder. - To see how this packs pixel data into the returned - bytes, see :file:`libImaging/Pack.c`. - - A list of C encoders can be seen under codecs - section of the function array in - :file:`_imaging.c`. Python encoders are registered - within the relevant plugins. + A list of C encoders can be seen under + codecs section of the function array in + :file:`_imaging.c`. Python encoders are + registered within the relevant plugins. :param args: Extra arguments to the encoder. :returns: A :py:class:`bytes` object. """ @@ -786,9 +808,7 @@ class Image: e = _getencoder(self.mode, encoder_name, encoder_args) e.setimage(self.im) - from . import ImageFile - - bufsize = max(ImageFile.MAXBLOCK, self.size[0] * 4) # see RawEncode.c + bufsize = max(65536, self.size[0] * 4) # see RawEncode.c output = [] while True: @@ -829,10 +849,7 @@ class Image: ) def frombytes( - self, - data: bytes | bytearray | SupportsArrayInterface, - decoder_name: str = "raw", - *args: Any, + self, data: bytes | bytearray, decoder_name: str = "raw", *args: Any ) -> None: """ Loads this image with pixel data from a bytes object. @@ -865,7 +882,7 @@ class Image: msg = "cannot decode image data" raise ValueError(msg) - def load(self) -> core.PixelAccess | None: + def load(self) -> core.PixelAccess | PyAccess.PyAccess | None: """ Allocates storage for the image and loads the pixel data. In normal cases, you don't need to call this method, since the @@ -878,9 +895,9 @@ class Image: operations. See :ref:`file-handling` for more information. :returns: An image access object. - :rtype: :py:class:`.PixelAccess` + :rtype: :py:class:`.PixelAccess` or :py:class:`.PyAccess` """ - if self._im is not None and self.palette and self.palette.dirty: + if self.im is not None and self.palette and self.palette.dirty: # realize palette mode, arr = self.palette.getdata() self.im.putpalette(self.palette.mode, mode, arr) @@ -897,7 +914,15 @@ class Image: self.palette.mode, self.palette.mode ) - if self._im is not None: + if self.im is not None: + if cffi and USE_CFFI_ACCESS: + if self.pyaccess: + return self.pyaccess + from . import PyAccess + + self.pyaccess = PyAccess.new(self, self.readonly) + if self.pyaccess: + return self.pyaccess return self.im.pixel_access(self.readonly) return None @@ -964,6 +989,9 @@ class Image: :returns: An :py:class:`~PIL.Image.Image` object. """ + if mode in ("BGR;15", "BGR;16", "BGR;24"): + deprecate(mode, 12) + self.load() has_transparency = "transparency" in self.info @@ -999,19 +1027,13 @@ class Image: elif len(mode) == 3: transparency = tuple( convert_transparency(matrix[i * 4 : i * 4 + 4], transparency) - for i in range(len(transparency)) + for i in range(0, len(transparency)) ) new_im.info["transparency"] = transparency return new_im - if self.mode == "RGBA": - if mode == "P": - return self.quantize(colors) - elif mode == "PA": - r, g, b, a = self.split() - rgb = merge("RGB", (r, g, b)) - p = rgb.quantize(colors) - return merge("PA", (p, a)) + if mode == "P" and self.mode == "RGBA": + return self.quantize(colors) trns = None delete_trns = False @@ -1041,11 +1063,9 @@ class Image: # use existing conversions trns_im = new(self.mode, (1, 1)) if self.mode == "P": - assert self.palette is not None - trns_im.putpalette(self.palette, self.palette.mode) + trns_im.putpalette(self.palette) if isinstance(t, tuple): err = "Couldn't allocate a palette color for transparency" - assert trns_im.palette is not None try: t = trns_im.palette.getcolor(t, self) except ValueError as e: @@ -1095,7 +1115,7 @@ class Image: if trns is not None: try: new_im.info["transparency"] = new_im.palette.getcolor( - cast(tuple[int, ...], trns), # trns was converted to RGB + cast(Tuple[int, ...], trns), # trns was converted to RGB new_im, ) except Exception: @@ -1106,23 +1126,17 @@ class Image: return new_im if "LAB" in (self.mode, mode): - im = self - if mode == "LAB": - if im.mode not in ("RGB", "RGBA", "RGBX"): - im = im.convert("RGBA") - other_mode = im.mode - else: - other_mode = mode + other_mode = mode if self.mode == "LAB" else self.mode if other_mode in ("RGB", "RGBA", "RGBX"): from . import ImageCms srgb = ImageCms.createProfile("sRGB") lab = ImageCms.createProfile("LAB") - profiles = [lab, srgb] if im.mode == "LAB" else [srgb, lab] + profiles = [lab, srgb] if self.mode == "LAB" else [srgb, lab] transform = ImageCms.buildTransform( - profiles[0], profiles[1], im.mode, mode + profiles[0], profiles[1], self.mode, mode ) - return transform.apply(im) + return transform.apply(self) # colorspace conversion if dither is None: @@ -1143,7 +1157,7 @@ class Image: raise ValueError(msg) from e new_im = self._new(im) - if mode in ("P", "PA") and palette != Palette.ADAPTIVE: + if mode == "P" and palette != Palette.ADAPTIVE: from . import ImagePalette new_im.palette = ImagePalette.ImagePalette("RGB", im.getpalette("RGB")) @@ -1153,9 +1167,7 @@ class Image: if trns is not None: if new_im.mode == "P" and new_im.palette: try: - new_im.info["transparency"] = new_im.palette.getcolor( - cast(tuple[int, ...], trns), new_im # trns was converted to RGB - ) + new_im.info["transparency"] = new_im.palette.getcolor(trns, new_im) except ValueError as e: del new_im.info["transparency"] if str(e) != "cannot allocate more than 256 colors": @@ -1173,7 +1185,7 @@ class Image: colors: int = 256, method: int | None = None, kmeans: int = 0, - palette: Image | None = None, + palette=None, dither: Dither = Dither.FLOYDSTEINBERG, ) -> Image: """ @@ -1233,7 +1245,6 @@ class Image: raise ValueError(msg) im = self.im.convert("P", dither, palette.im) new_im = self._new(im) - assert palette.palette is not None new_im.palette = palette.palette.copy() return new_im @@ -1246,8 +1257,8 @@ class Image: from . import ImagePalette mode = im.im.getpalettemode() - palette_data = im.im.getpalette(mode, mode)[: colors * len(mode)] - im.palette = ImagePalette.ImagePalette(mode, palette_data) + palette = im.im.getpalette(mode, mode)[: colors * len(mode)] + im.palette = ImagePalette.ImagePalette(mode, palette) return im @@ -1337,6 +1348,15 @@ class Image: """ pass + def _expand(self, xmargin: int, ymargin: int | None = None) -> Image: + if ymargin is None: + ymargin = xmargin + self.load() + return self._new(self.im.expand(xmargin, ymargin)) + + if TYPE_CHECKING: + from . import ImageFilter + def filter(self, filter: ImageFilter.Filter | type[ImageFilter.Filter]) -> Image: """ Filters this image using the given filter. For a list of @@ -1393,9 +1413,7 @@ class Image: self.load() return self.im.getbbox(alpha_only) - def getcolors( - self, maxcolors: int = 256 - ) -> list[tuple[int, tuple[int, ...]]] | list[tuple[int, float]] | None: + def getcolors(self, maxcolors: int = 256): """ Returns a list of colors used in this image. @@ -1412,13 +1430,13 @@ class Image: self.load() if self.mode in ("1", "L", "P"): h = self.im.histogram() - out: list[tuple[int, float]] = [(h[i], i) for i in range(256) if h[i]] + out = [(h[i], i) for i in range(256) if h[i]] if len(out) > maxcolors: return None return out return self.im.getcolors(maxcolors) - def getdata(self, band: int | None = None) -> core.ImagingCore: + def getdata(self, band: int | None = None): """ Returns the contents of this image as a sequence object containing pixel values. The sequence object is flattened, so @@ -1435,31 +1453,12 @@ class Image: value (e.g. 0 to get the "R" band from an "RGB" image). :returns: A sequence-like object. """ - deprecate("Image.Image.getdata", 14, "get_flattened_data") self.load() if band is not None: return self.im.getband(band) return self.im # could be abused - def get_flattened_data( - self, band: int | None = None - ) -> tuple[tuple[int, ...], ...] | tuple[float, ...]: - """ - Returns the contents of this image as a tuple containing pixel values. - The sequence object is flattened, so that values for line one follow - directly after the values of line zero, and so on. - - :param band: What band to return. The default is to return - all bands. To return a single band, pass in the index - value (e.g. 0 to get the "R" band from an "RGB" image). - :returns: A tuple containing pixel values. - """ - self.load() - if band is not None: - return tuple(self.im.getband(band)) - return tuple(self.im) - def getextrema(self) -> tuple[float, float] | tuple[tuple[int, int], ...]: """ Gets the minimum and maximum pixel values for each band in @@ -1475,7 +1474,7 @@ class Image: return tuple(self.im.getband(i).getextrema() for i in range(self.im.bands)) return self.im.getextrema() - def getxmp(self) -> dict[str, Any]: + def getxmp(self): """ Returns a dictionary containing the XMP tags. Requires defusedxml to be installed. @@ -1486,8 +1485,8 @@ class Image: def get_name(tag: str) -> str: return re.sub("^{[^}]+}", "", tag) - def get_value(element: Element) -> str | dict[str, Any] | None: - value: dict[str, Any] = {get_name(k): v for k, v in element.attrib.items()} + def get_value(element): + value = {get_name(k): v for k, v in element.attrib.items()} children = list(element) if children: for child in children: @@ -1511,7 +1510,7 @@ class Image: return {} if "xmp" not in self.info: return {} - root = ElementTree.fromstring(self.info["xmp"].rstrip(b"\x00 ")) + root = ElementTree.fromstring(self.info["xmp"].rstrip(b"\x00")) return {get_name(root.tag): get_value(root)} def getexif(self) -> Exif: @@ -1533,13 +1532,8 @@ class Image: "".join(self.info["Raw profile type exif"].split("\n")[3:]) ) elif hasattr(self, "tag_v2"): - from . import TiffImagePlugin - - assert isinstance(self, TiffImagePlugin.TiffImageFile) self._exif.bigtiff = self.tag_v2._bigtiff self._exif.endian = self.tag_v2._endian - - assert self.fp is not None self._exif.load_from_fp(self.fp, self.tag_v2._offset) if exif_info is not None: self._exif.load(exif_info) @@ -1547,11 +1541,8 @@ class Image: # XMP tags if ExifTags.Base.Orientation not in self._exif: xmp_tags = self.info.get("XML:com.adobe.xmp") - pattern: str | bytes = r'tiff:Orientation(="|>)([0-9])' - if not xmp_tags and (xmp_tags := self.info.get("xmp")): - pattern = rb'tiff:Orientation(="|>)([0-9])' if xmp_tags: - match = re.search(pattern, xmp_tags) + match = re.search(r'tiff:Orientation(="|>)([0-9])', xmp_tags) if match: self._exif[ExifTags.Base.Orientation] = int(match[2]) @@ -1564,12 +1555,50 @@ class Image: self.getexif() def get_child_images(self) -> list[ImageFile.ImageFile]: - from . import ImageFile + child_images = [] + exif = self.getexif() + ifds = [] + if ExifTags.Base.SubIFDs in exif: + subifd_offsets = exif[ExifTags.Base.SubIFDs] + if subifd_offsets: + if not isinstance(subifd_offsets, tuple): + subifd_offsets = (subifd_offsets,) + for subifd_offset in subifd_offsets: + ifds.append((exif._get_ifd_dict(subifd_offset), subifd_offset)) + ifd1 = exif.get_ifd(ExifTags.IFD.IFD1) + if ifd1 and ifd1.get(513): + ifds.append((ifd1, exif._info.next)) - deprecate("Image.Image.get_child_images", 13) - return ImageFile.ImageFile.get_child_images(self) # type: ignore[arg-type] + offset = None + for ifd, ifd_offset in ifds: + current_offset = self.fp.tell() + if offset is None: + offset = current_offset - def getim(self) -> CapsuleType: + fp = self.fp + thumbnail_offset = ifd.get(513) + if thumbnail_offset is not None: + thumbnail_offset += getattr(self, "_exif_offset", 0) + self.fp.seek(thumbnail_offset) + data = self.fp.read(ifd.get(514)) + fp = io.BytesIO(data) + + with open(fp) as im: + from . import TiffImagePlugin + + if thumbnail_offset is None and isinstance( + im, TiffImagePlugin.TiffImageFile + ): + im._frame_pos = [ifd_offset] + im._seek(0) + im.load() + child_images.append(im) + + if offset is not None: + self.fp.seek(offset) + return child_images + + def getim(self): """ Returns a capsule that points to the internal image memory. @@ -1613,15 +1642,11 @@ class Image: :returns: A boolean. """ - if ( + return ( self.mode in ("LA", "La", "PA", "RGBA", "RGBa") + or (self.mode == "P" and self.palette.mode.endswith("A")) or "transparency" in self.info - ): - return True - if self.mode == "P": - assert self.palette is not None - return self.palette.mode.endswith("A") - return False + ) def apply_transparency(self) -> None: """ @@ -1660,6 +1685,8 @@ class Image: """ self.load() + if self.pyaccess: + return self.pyaccess.getpixel(xy) return self.im.getpixel(tuple(xy)) def getprojection(self) -> tuple[list[int], list[int]]: @@ -1674,9 +1701,7 @@ class Image: x, y = self.im.getprojection() return list(x), list(y) - def histogram( - self, mask: Image | None = None, extrema: tuple[float, float] | None = None - ) -> list[int]: + def histogram(self, mask: Image | None = None, extrema=None) -> list[int]: """ Returns a histogram for the image. The histogram is returned as a list of pixel counts, one for each pixel value in the source @@ -1702,14 +1727,12 @@ class Image: mask.load() return self.im.histogram((0, 0), mask.im) if self.mode in ("I", "F"): - return self.im.histogram( - extrema if extrema is not None else self.getextrema() - ) + if extrema is None: + extrema = self.getextrema() + return self.im.histogram(extrema) return self.im.histogram() - def entropy( - self, mask: Image | None = None, extrema: tuple[float, float] | None = None - ) -> float: + def entropy(self, mask=None, extrema=None): """ Calculates and returns the entropy for the image. @@ -1730,9 +1753,9 @@ class Image: mask.load() return self.im.entropy((0, 0), mask.im) if self.mode in ("I", "F"): - return self.im.entropy( - extrema if extrema is not None else self.getextrema() - ) + if extrema is None: + extrema = self.getextrema() + return self.im.entropy(extrema) return self.im.entropy() def paste( @@ -1753,10 +1776,9 @@ class Image: details). Instead of an image, the source can be a integer or tuple - containing pixel values. The method then fills the region - with the given color. When creating RGB images, you can - also use color strings as supported by the ImageColor module. See - :ref:`colors` for more information. + containing pixel values. The method then fills the region + with the given color. When creating RGB images, you can + also use color strings as supported by the ImageColor module. If a mask is given, this method updates only the regions indicated by the mask. You can use either "1", "L", "LA", "RGBA" @@ -1781,22 +1803,23 @@ class Image: :param mask: An optional mask image. """ - if isinstance(box, Image): + if isImageType(box): if mask is not None: msg = "If using second argument as mask, third argument must be None" raise ValueError(msg) # abbreviated paste(im, mask) syntax mask = box box = None + assert not isinstance(box, Image) if box is None: box = (0, 0) if len(box) == 2: # upper left corner given; get size from image or mask - if isinstance(im, Image): + if isImageType(im): size = im.size - elif isinstance(mask, Image): + elif isImageType(mask): size = mask.size else: # FIXME: use self.size here? @@ -1804,28 +1827,26 @@ class Image: raise ValueError(msg) box += (box[0] + size[0], box[1] + size[1]) - source: core.ImagingCore | str | float | tuple[float, ...] if isinstance(im, str): from . import ImageColor - source = ImageColor.getcolor(im, self.mode) - elif isinstance(im, Image): + im = ImageColor.getcolor(im, self.mode) + + elif isImageType(im): im.load() if self.mode != im.mode: if self.mode != "RGB" or im.mode not in ("LA", "RGBA", "RGBa"): # should use an adapter for this! im = im.convert(self.mode) - source = im.im - else: - source = im + im = im.im self._ensure_mutable() if mask: mask.load() - self.im.paste(source, box, mask.im) + self.im.paste(im, box, mask.im) else: - self.im.paste(source, box) + self.im.paste(im, box) def alpha_composite( self, im: Image, dest: Sequence[int] = (0, 0), source: Sequence[int] = (0, 0) @@ -1885,13 +1906,7 @@ class Image: def point( self, - lut: ( - Sequence[float] - | NumpyArray - | Callable[[int], float] - | Callable[[ImagePointTransform], ImagePointTransform | float] - | ImagePointHandler - ), + lut: Sequence[float] | Callable[[int], float] | ImagePointHandler, mode: str | None = None, ) -> Image: """ @@ -1908,7 +1923,7 @@ class Image: object:: class Example(Image.ImagePointHandler): - def point(self, im: Image) -> Image: + def point(self, data): # Return result :param mode: Output mode (default is same as input). This can only be used if the source image has mode "L" or "P", and the output has mode "1" or the @@ -1927,10 +1942,10 @@ class Image: # check if the function can be used with point_transform # UNDONE wiredfool -- I think this prevents us from ever doing # a gamma function point transform on > 8bit images. - scale, offset = _getscaleoffset(lut) # type: ignore[arg-type] + scale, offset = _getscaleoffset(lut) return self._new(self.im.point_transform(scale, offset)) # for other modes, convert the function to a table - flatLut = [lut(i) for i in range(256)] * self.im.bands # type: ignore[arg-type] + flatLut = [lut(i) for i in range(256)] * self.im.bands else: flatLut = lut @@ -1968,6 +1983,7 @@ class Image: msg = "alpha channel could not be added" raise ValueError(msg) from e # sanity check self.im = im + self.pyaccess = None self._mode = self.im.mode except KeyError as e: msg = "illegal image mode" @@ -1978,7 +1994,7 @@ class Image: else: band = 3 - if isinstance(alpha, Image): + if isImageType(alpha): # alpha layer if alpha.mode not in ("1", "L"): msg = "illegal image mode" @@ -1988,6 +2004,7 @@ class Image: alpha = alpha.convert("L") else: # constant alpha + alpha = cast(int, alpha) # see python/typing#1013 try: self.im.fillband(band, alpha) except (AttributeError, ValueError): @@ -2000,7 +2017,7 @@ class Image: def putdata( self, - data: Sequence[float] | Sequence[Sequence[int]] | core.ImagingCore | NumpyArray, + data: Sequence[float] | Sequence[Sequence[int]], scale: float = 1.0, offset: float = 0.0, ) -> None: @@ -2012,8 +2029,7 @@ class Image: sequence ends. The scale and offset values are used to adjust the sequence values: **pixel = value*scale + offset**. - :param data: A flattened sequence object. See :ref:`colors` for more - information about values. + :param data: A flattened sequence object. :param scale: An optional scale value. The default is 1.0. :param offset: An optional offset value. The default is 0.0. """ @@ -2022,11 +2038,7 @@ class Image: self.im.putdata(data, scale, offset) - def putpalette( - self, - data: ImagePalette.ImagePalette | bytes | Sequence[int], - rawmode: str = "RGB", - ) -> None: + def putpalette(self, data, rawmode="RGB") -> None: """ Attaches a palette to this image. The image must be a "P", "PA", "L" or "LA" image. @@ -2051,11 +2063,7 @@ class Image: msg = "illegal image mode" raise ValueError(msg) if isinstance(data, ImagePalette.ImagePalette): - if data.rawmode is not None: - palette = ImagePalette.raw(data.rawmode, data.palette) - else: - palette = ImagePalette.ImagePalette(palette=data.palette) - palette.dirty = 1 + palette = ImagePalette.raw(data.rawmode, data.palette) else: if not isinstance(data, bytes): data = bytes(data) @@ -2072,7 +2080,7 @@ class Image: Modifies the pixel at the given position. The color is given as a single numerical value for single-band images, and a tuple for multi-band images. In addition to this, RGB and RGBA tuples are - accepted for P and PA images. See :ref:`colors` for more information. + accepted for P and PA images. Note that this method is relatively slow. For more extensive changes, use :py:meth:`~PIL.Image.Image.paste` or the :py:mod:`~PIL.ImageDraw` @@ -2089,7 +2097,12 @@ class Image: :param value: The pixel value. """ - self._ensure_mutable() + if self.readonly: + self._copy() + self.load() + + if self.pyaccess: + return self.pyaccess.putpixel(xy, value) if ( self.mode in ("P", "PA") @@ -2100,14 +2113,11 @@ class Image: if self.mode == "PA": alpha = value[3] if len(value) == 4 else 255 value = value[:3] - assert self.palette is not None - palette_index = self.palette.getcolor(tuple(value), self) + palette_index = self.palette.getcolor(value, self) value = (palette_index, alpha) if self.mode == "PA" else palette_index return self.im.putpixel(xy, value) - def remap_palette( - self, dest_map: list[int], source_palette: bytes | bytearray | None = None - ) -> Image: + def remap_palette(self, dest_map, source_palette=None): """ Rewrites the image to reorder the palette. @@ -2135,9 +2145,6 @@ class Image: source_palette = self.im.getpalette(palette_mode, palette_mode) else: # L-mode source_palette = bytearray(i // 3 for i in range(768)) - elif len(source_palette) > 768: - bands = 4 - palette_mode = "RGBA" palette_bytes = b"" new_positions = [0] * 256 @@ -2195,12 +2202,7 @@ class Image: return m_im - def _get_safe_box( - self, - size: tuple[int, int], - resample: Resampling, - box: tuple[float, float, float, float], - ) -> tuple[int, int, int, int]: + def _get_safe_box(self, size, resample, box): """Expands the box so it includes adjacent pixels that may be used by resampling with the given resampling filter. """ @@ -2219,7 +2221,7 @@ class Image: def resize( self, - size: tuple[int, int] | list[int] | NumpyArray, + size: tuple[int, int], resample: int | None = None, box: tuple[float, float, float, float] | None = None, reducing_gap: float | None = None, @@ -2227,13 +2229,15 @@ class Image: """ Returns a resized copy of this image. - :param size: The requested size in pixels, as a tuple or array: + :param size: The requested size in pixels, as a 2-tuple: (width, height). :param resample: An optional resampling filter. This can be one of :py:data:`Resampling.NEAREST`, :py:data:`Resampling.BOX`, :py:data:`Resampling.BILINEAR`, :py:data:`Resampling.HAMMING`, :py:data:`Resampling.BICUBIC` or :py:data:`Resampling.LANCZOS`. If the image has mode "1" or "P", it is always set to + :py:data:`Resampling.NEAREST`. If the image mode specifies a number + of bits, such as "I;16", then the default filter is :py:data:`Resampling.NEAREST`. Otherwise, the default filter is :py:data:`Resampling.BICUBIC`. See: :ref:`concept-filters`. :param box: An optional 4-tuple of floats providing @@ -2256,7 +2260,8 @@ class Image: """ if resample is None: - resample = Resampling.BICUBIC + type_special = ";" in self.mode + resample = Resampling.NEAREST if type_special else Resampling.BICUBIC elif resample not in ( Resampling.NEAREST, Resampling.BILINEAR, @@ -2285,10 +2290,10 @@ class Image: msg = "reducing_gap must be 1.0 or greater" raise ValueError(msg) + self.load() if box is None: box = (0, 0) + self.size - size = tuple(size) if self.size == size and box == (0, 0) + self.size: return self.copy() @@ -2306,7 +2311,7 @@ class Image: factor_x = int((box[2] - box[0]) / size[0] / reducing_gap) or 1 factor_y = int((box[3] - box[1]) / size[1] / reducing_gap) or 1 if factor_x > 1 or factor_y > 1: - reduce_box = self._get_safe_box(size, cast(Resampling, resample), box) + reduce_box = self._get_safe_box(size, resample, box) factor = (factor_x, factor_y) self = ( self.reduce(factor, box=reduce_box) @@ -2442,7 +2447,7 @@ class Image: 0.0, ] - def transform(x: float, y: float, matrix: list[float]) -> tuple[float, float]: + def transform(x, y, matrix): (a, b, c, d, e, f) = matrix return a * x + b * y + c, d * x + e * y + f @@ -2457,9 +2462,9 @@ class Image: xx = [] yy = [] for x, y in ((0, 0), (w, 0), (w, h), (0, h)): - transformed_x, transformed_y = transform(x, y, matrix) - xx.append(transformed_x) - yy.append(transformed_y) + x, y = transform(x, y, matrix) + xx.append(x) + yy.append(y) nw = math.ceil(max(xx)) - math.floor(min(xx)) nh = math.ceil(max(yy)) - math.floor(min(yy)) @@ -2497,21 +2502,7 @@ class Image: format to use is determined from the filename extension. If a file object was used instead of a filename, this parameter should always be used. - :param params: Extra parameters to the image writer. These can also be - set on the image itself through ``encoderinfo``. This is useful when - saving multiple images:: - - # Saving XMP data to a single image - from PIL import Image - red = Image.new("RGB", (1, 1), "#f00") - red.save("out.mpo", xmp=b"test") - - # Saving XMP data to the second frame of an image - from PIL import Image - black = Image.new("RGB", (1, 1)) - red = Image.new("RGB", (1, 1), "#f00") - red.encoderinfo = {"xmp": b"test"} - black.save("out.mpo", save_all=True, append_images=[red]) + :param params: Extra parameters to the image writer. :returns: None :exception ValueError: If the output format could not be determined from the file name. Use the format option to solve this. @@ -2522,7 +2513,7 @@ class Image: filename: str | bytes = "" open_fp = False if is_path(fp): - filename = os.fspath(fp) + filename = os.path.realpath(os.fspath(fp)) open_fp = True elif fp == sys.stdout: try: @@ -2531,7 +2522,14 @@ class Image: pass if not filename and hasattr(fp, "name") and is_path(fp.name): # only set the name for metadata purposes - filename = os.fspath(fp.name) + filename = os.path.realpath(os.fspath(fp.name)) + + # may mutate self! + self._ensure_mutable() + + save_all = params.pop("save_all", False) + self.encoderinfo = params + self.encoderconfig: tuple[Any, ...] = () preinit() @@ -2547,29 +2545,9 @@ class Image: msg = f"unknown file extension: {ext}" raise ValueError(msg) from e - from . import ImageFile - - # may mutate self! - if isinstance(self, ImageFile.ImageFile) and os.path.abspath( - filename - ) == os.path.abspath(self.filename): - self._ensure_mutable() - else: - self.load() - - save_all = params.pop("save_all", None) - self._default_encoderinfo = params - encoderinfo = getattr(self, "encoderinfo", {}) - self._attach_default_encoderinfo(self) - self.encoderconfig: tuple[Any, ...] = () - if format.upper() not in SAVE: init() - if save_all or ( - save_all is None - and params.get("append_images") - and format.upper() in SAVE_ALL - ): + if save_all: save_handler = SAVE_ALL[format.upper()] else: save_handler = SAVE[format.upper()] @@ -2597,16 +2575,9 @@ class Image: except PermissionError: pass raise - finally: - self.encoderinfo = encoderinfo if open_fp: fp.close() - def _attach_default_encoderinfo(self, im: Image) -> dict[str, Any]: - encoderinfo = getattr(self, "encoderinfo", {}) - self.encoderinfo = {**im._default_encoderinfo, **encoderinfo} - return encoderinfo - def seek(self, frame: int) -> None: """ Seeks to the given frame in this sequence file. If you seek @@ -2649,9 +2620,7 @@ class Image: :param title: Optional title to use for the image window, where possible. """ - from . import ImageShow - - ImageShow.show(self, title) + _show(self, title=title) def split(self) -> tuple[Image, ...]: """ @@ -2753,7 +2722,7 @@ class Image: provided_size = tuple(map(math.floor, size)) def preserve_aspect_ratio() -> tuple[int, int] | None: - def round_aspect(number: float, key: Callable[[int], float]) -> int: + def round_aspect(number, key): return max(min(math.floor(number), math.ceil(number), key=key), 1) x, y = provided_size @@ -2769,18 +2738,27 @@ class Image: ) return x, y - preserved_size = preserve_aspect_ratio() - if preserved_size is None: - return - final_size = preserved_size - box = None + final_size: tuple[int, int] if reducing_gap is not None: + preserved_size = preserve_aspect_ratio() + if preserved_size is None: + return + final_size = preserved_size + res = self.draft( None, (int(size[0] * reducing_gap), int(size[1] * reducing_gap)) ) if res is not None: box = res[1] + if box is None: + self.load() + + # load() may have changed the size of the image + preserved_size = preserve_aspect_ratio() + if preserved_size is None: + return + final_size = preserved_size if self.size != final_size: im = self.resize(final_size, resample, box=box, reducing_gap=reducing_gap) @@ -2790,6 +2768,7 @@ class Image: self._mode = self.im.mode self.readonly = 0 + self.pyaccess = None # FIXME: the different transform methods need further explanation # instead of bloating the method docs, add a separate chapter. @@ -2888,14 +2867,8 @@ class Image: return im def __transformer( - self, - box: tuple[int, int, int, int], - image: Image, - method: Transform, - data: Sequence[float], - resample: int = Resampling.NEAREST, - fill: bool = True, - ) -> None: + self, box, image, method, data, resample=Resampling.NEAREST, fill=1 + ): w = box[2] - box[0] h = box[3] - box[1] @@ -2944,12 +2917,11 @@ class Image: Resampling.BICUBIC, ): if resample in (Resampling.BOX, Resampling.HAMMING, Resampling.LANCZOS): - unusable: dict[int, str] = { + msg = { Resampling.BOX: "Image.Resampling.BOX", Resampling.HAMMING: "Image.Resampling.HAMMING", Resampling.LANCZOS: "Image.Resampling.LANCZOS", - } - msg = unusable[resample] + f" ({resample}) cannot be used." + }[resample] + f" ({resample}) cannot be used." else: msg = f"Unknown resampling filter ({resample})." @@ -2996,7 +2968,7 @@ class Image: self.load() return self._new(self.im.effect_spread(distance)) - def toqimage(self) -> ImageQt.ImageQt: + def toqimage(self): """Returns a QImage copy of this image""" from . import ImageQt @@ -3005,7 +2977,7 @@ class Image: raise ImportError(msg) return ImageQt.toqimage(self) - def toqpixmap(self) -> ImageQt.QPixmap: + def toqpixmap(self): """Returns a QPixmap copy of this image""" from . import ImageQt @@ -3019,7 +2991,7 @@ class Image: # Abstract handlers. -class ImagePointHandler(abc.ABC): +class ImagePointHandler: """ Used as a mixin by point transforms (for use with :py:meth:`~PIL.Image.Image.point`) @@ -3030,7 +3002,7 @@ class ImagePointHandler(abc.ABC): pass -class ImageTransformHandler(abc.ABC): +class ImageTransformHandler: """ Used as a mixin by geometry transforms (for use with :py:meth:`~PIL.Image.Image.transform`) @@ -3049,6 +3021,15 @@ class ImageTransformHandler(abc.ABC): # -------------------------------------------------------------------- # Factories +# +# Debugging + + +def _wedge() -> Image: + """Create grayscale wedge (for debugging only)""" + + return Image()._new(core.wedge("L")) + def _check_size(size: Any) -> None: """ @@ -3080,15 +3061,18 @@ def new( :param mode: The mode to use for the new image. See: :ref:`concept-modes`. :param size: A 2-tuple, containing (width, height) in pixels. - :param color: What color to use for the image. Default is black. If given, - this should be a single integer or floating point value for single-band - modes, and a tuple for multi-band modes (one value per band). When - creating RGB or HSV images, you can also use color strings as supported - by the ImageColor module. See :ref:`colors` for more information. If the - color is None, the image is not initialised. + :param color: What color to use for the image. Default is black. + If given, this should be a single integer or floating point value + for single-band modes, and a tuple for multi-band modes (one value + per band). When creating RGB or HSV images, you can also use color + strings as supported by the ImageColor module. If the color is + None, the image is not initialised. :returns: An :py:class:`~PIL.Image.Image` object. """ + if mode in ("BGR;15", "BGR;16", "BGR;24"): + deprecate(mode, 12) + _check_size(size) if color is None: @@ -3108,7 +3092,7 @@ def new( and isinstance(color, (list, tuple)) and all(isinstance(i, int) for i in color) ): - color_ints: tuple[int, ...] = cast(tuple[int, ...], tuple(color)) + color_ints: tuple[int, ...] = cast(Tuple[int, ...], tuple(color)) if len(color_ints) == 3 or len(color_ints) == 4: # RGB or RGBA value for a P image from . import ImagePalette @@ -3121,7 +3105,7 @@ def new( def frombytes( mode: str, size: tuple[int, int], - data: bytes | bytearray | SupportsArrayInterface, + data: bytes | bytearray, decoder_name: str = "raw", *args: Any, ) -> Image: @@ -3165,11 +3149,7 @@ def frombytes( def frombuffer( - mode: str, - size: tuple[int, int], - data: bytes | SupportsArrayInterface, - decoder_name: str = "raw", - *args: Any, + mode: str, size: tuple[int, int], data, decoder_name: str = "raw", *args: Any ) -> Image: """ Creates an image memory referencing pixel data in a byte buffer. @@ -3236,18 +3216,6 @@ class SupportsArrayInterface(Protocol): raise NotImplementedError() -class SupportsArrowArrayInterface(Protocol): - """ - An object that has an ``__arrow_c_array__`` method corresponding to the arrow c - data interface. - """ - - def __arrow_c_array__( - self, requested_schema: "PyCapsule" = None # type: ignore[name-defined] # noqa: F821, UP037 - ) -> tuple["PyCapsule", "PyCapsule"]: # type: ignore[name-defined] # noqa: F821, UP037 - raise NotImplementedError() - - def fromarray(obj: SupportsArrayInterface, mode: str | None = None) -> Image: """ Creates an image memory from an object exporting the array interface @@ -3276,10 +3244,19 @@ def fromarray(obj: SupportsArrayInterface, mode: str | None = None) -> Image: transferred. This means that P and PA mode images will lose their palette. :param obj: Object with array interface - :param mode: Optional mode to use when reading ``obj``. Since pixel values do not - contain information about palettes or color spaces, this can be used to place - grayscale L mode data within a P mode image, or read RGB data as YCbCr for - example. + :param mode: Optional mode to use when reading ``obj``. Will be determined from + type if ``None``. + + This will not be used to convert the data after reading, but will be used to + change how the data is read:: + + from PIL import Image + import numpy as np + a = np.full((1, 1), 300) + im = Image.fromarray(a, mode="L") + im.getpixel((0, 0)) # 44 + im = Image.fromarray(a, mode="RGB") + im.getpixel((0, 0)) # (44, 1, 0) See: :ref:`concept-modes` for general information about modes. :returns: An image object. @@ -3290,28 +3267,20 @@ def fromarray(obj: SupportsArrayInterface, mode: str | None = None) -> Image: shape = arr["shape"] ndim = len(shape) strides = arr.get("strides", None) - try: - typekey = (1, 1) + shape[2:], arr["typestr"] - except KeyError as e: - if mode is not None: - typekey = None - color_modes: list[str] = [] - else: + if mode is None: + try: + typekey = (1, 1) + shape[2:], arr["typestr"] + except KeyError as e: msg = "Cannot handle this data type" raise TypeError(msg) from e - if typekey is not None: try: - typemode, rawmode, color_modes = _fromarray_typemap[typekey] + mode, rawmode = _fromarray_typemap[typekey] except KeyError as e: typekey_shape, typestr = typekey msg = f"Cannot handle this data type: {typekey_shape}, {typestr}" raise TypeError(msg) from e - if mode is not None: - if mode != typemode and mode not in color_modes: - deprecate("'mode' parameter for changing data types", 13) - rawmode = mode else: - mode = typemode + rawmode = mode if mode in ["1", "L", "I", "P", "F"]: ndmax = 2 elif mode == "RGB": @@ -3335,59 +3304,7 @@ def fromarray(obj: SupportsArrayInterface, mode: str | None = None) -> Image: return frombuffer(mode, size, obj, "raw", rawmode, 0, 1) -def fromarrow( - obj: SupportsArrowArrayInterface, mode: str, size: tuple[int, int] -) -> Image: - """Creates an image with zero-copy shared memory from an object exporting - the arrow_c_array interface protocol:: - - from PIL import Image - import pyarrow as pa - arr = pa.array([0]*(5*5*4), type=pa.uint8()) - im = Image.fromarrow(arr, 'RGBA', (5, 5)) - - If the data representation of the ``obj`` is not compatible with - Pillow internal storage, a ValueError is raised. - - Pillow images can also be converted to Arrow objects:: - - from PIL import Image - import pyarrow as pa - im = Image.open('hopper.jpg') - arr = pa.array(im) - - As with array support, when converting Pillow images to arrays, - only pixel values are transferred. This means that P and PA mode - images will lose their palette. - - :param obj: Object with an arrow_c_array interface - :param mode: Image mode. - :param size: Image size. This must match the storage of the arrow object. - :returns: An Image object - - Note that according to the Arrow spec, both the producer and the - consumer should consider the exported array to be immutable, as - unsynchronized updates will potentially cause inconsistent data. - - See: :ref:`arrow-support` for more detailed information - - .. versionadded:: 11.2.1 - - """ - if not hasattr(obj, "__arrow_c_array__"): - msg = "arrow_c_array interface not found" - raise ValueError(msg) - - (schema_capsule, array_capsule) = obj.__arrow_c_array__() - _im = core.new_arrow(mode, size, schema_capsule, array_capsule) - if _im: - return Image()._new(_im) - - msg = "new_arrow returned None without an exception" - raise ValueError(msg) - - -def fromqimage(im: ImageQt.QImage) -> ImageFile.ImageFile: +def fromqimage(im): """Creates an image instance from a QImage image""" from . import ImageQt @@ -3397,7 +3314,7 @@ def fromqimage(im: ImageQt.QImage) -> ImageFile.ImageFile: return ImageQt.fromqimage(im) -def fromqpixmap(im: ImageQt.QPixmap) -> ImageFile.ImageFile: +def fromqpixmap(im): """Creates an image instance from a QPixmap image""" from . import ImageQt @@ -3408,29 +3325,29 @@ def fromqpixmap(im: ImageQt.QPixmap) -> ImageFile.ImageFile: _fromarray_typemap = { - # (shape, typestr) => mode, rawmode, color modes + # (shape, typestr) => mode, rawmode # first two members of shape are set to one - ((1, 1), "|b1"): ("1", "1;8", []), - ((1, 1), "|u1"): ("L", "L", ["P"]), - ((1, 1), "|i1"): ("I", "I;8", []), - ((1, 1), "u2"): ("I", "I;16B", []), - ((1, 1), "i2"): ("I", "I;16BS", []), - ((1, 1), "u4"): ("I", "I;32B", []), - ((1, 1), "i4"): ("I", "I;32BS", []), - ((1, 1), "f4"): ("F", "F;32BF", []), - ((1, 1), "f8"): ("F", "F;64BF", []), - ((1, 1, 2), "|u1"): ("LA", "LA", ["La", "PA"]), - ((1, 1, 3), "|u1"): ("RGB", "RGB", ["YCbCr", "LAB", "HSV"]), - ((1, 1, 4), "|u1"): ("RGBA", "RGBA", ["RGBa", "RGBX", "CMYK"]), + ((1, 1), "|b1"): ("1", "1;8"), + ((1, 1), "|u1"): ("L", "L"), + ((1, 1), "|i1"): ("I", "I;8"), + ((1, 1), "u2"): ("I", "I;16B"), + ((1, 1), "i2"): ("I", "I;16BS"), + ((1, 1), "u4"): ("I", "I;32B"), + ((1, 1), "i4"): ("I", "I;32BS"), + ((1, 1), "f4"): ("F", "F;32BF"), + ((1, 1), "f8"): ("F", "F;64BF"), + ((1, 1, 2), "|u1"): ("LA", "LA"), + ((1, 1, 3), "|u1"): ("RGB", "RGB"), + ((1, 1, 4), "|u1"): ("RGBA", "RGBA"), # shortcuts: - ((1, 1), f"{_ENDIAN}i4"): ("I", "I", []), - ((1, 1), f"{_ENDIAN}f4"): ("F", "F", []), + ((1, 1), f"{_ENDIAN}i4"): ("I", "I"), + ((1, 1), f"{_ENDIAN}f4"): ("F", "F"), } @@ -3508,7 +3425,9 @@ def open( exclusive_fp = False filename: str | bytes = "" if is_path(fp): - filename = os.fspath(fp) + filename = os.path.realpath(os.fspath(fp)) + + if filename: fp = builtins.open(filename, "rb") exclusive_fp = True else: @@ -3587,8 +3506,9 @@ def alpha_composite(im1: Image, im2: Image) -> Image: """ Alpha composite im2 over im1. - :param im1: The first image. Must have mode RGBA or LA. - :param im2: The second image. Must have the same mode and size as the first image. + :param im1: The first image. Must have mode RGBA. + :param im2: The second image. Must have mode RGBA, and the same size as + the first image. :returns: An :py:class:`~PIL.Image.Image` object. """ @@ -3637,7 +3557,7 @@ def composite(image1: Image, image2: Image, mask: Image) -> Image: return image -def eval(image: Image, *args: Callable[[int], float]) -> Image: +def eval(image, *args): """ Applies the function (which should take one argument) to each pixel in the given image. If the image has more than one band, the same @@ -3686,10 +3606,7 @@ def merge(mode: str, bands: Sequence[Image]) -> Image: def register_open( id: str, - factory: ( - Callable[[IO[bytes], str | bytes], ImageFile.ImageFile] - | type[ImageFile.ImageFile] - ), + factory: Callable[[IO[bytes], str | bytes], ImageFile.ImageFile], accept: Callable[[bytes], bool | str] | None = None, ) -> None: """ @@ -3814,7 +3731,6 @@ def register_encoder(name: str, encoder: type[ImageFile.PyEncoder]) -> None: def _show(image: Image, **options: Any) -> None: from . import ImageShow - deprecate("Image._show", 13, "ImageShow.show") ImageShow.show(image, **options) @@ -3936,7 +3852,7 @@ class Exif(_ExifBase): gps_ifd = exif.get_ifd(ExifTags.IFD.GPSInfo) print(gps_ifd) - Other IFDs include ``ExifTags.IFD.Exif``, ``ExifTags.IFD.MakerNote``, + Other IFDs include ``ExifTags.IFD.Exif``, ``ExifTags.IFD.Makernote``, ``ExifTags.IFD.Interop`` and ``ExifTags.IFD.IFD1``. :py:mod:`~PIL.ExifTags` also has enum classes to provide names for data:: @@ -3945,18 +3861,18 @@ class Exif(_ExifBase): print(gps_ifd[ExifTags.GPS.GPSDateStamp]) # 1999:99:99 99:99:99 """ - endian: str | None = None + endian = None bigtiff = False _loaded = False - def __init__(self) -> None: - self._data: dict[int, Any] = {} - self._hidden_data: dict[int, Any] = {} - self._ifds: dict[int, dict[int, Any]] = {} - self._info: TiffImagePlugin.ImageFileDirectory_v2 | None = None - self._loaded_exif: bytes | None = None + def __init__(self): + self._data = {} + self._hidden_data = {} + self._ifds = {} + self._info = None + self._loaded_exif = None - def _fixup(self, value: Any) -> Any: + def _fixup(self, value): try: if len(value) == 1 and isinstance(value, tuple): return value[0] @@ -3964,29 +3880,27 @@ class Exif(_ExifBase): pass return value - def _fixup_dict(self, src_dict: dict[int, Any]) -> dict[int, Any]: + def _fixup_dict(self, src_dict): # Helper function # returns a dict with any single item tuples/lists as individual values return {k: self._fixup(v) for k, v in src_dict.items()} - def _get_ifd_dict( - self, offset: int, group: int | None = None - ) -> dict[int, Any] | None: + def _get_ifd_dict(self, offset, group=None): try: # an offset pointer to the location of the nested embedded IFD. # It should be a long, but may be corrupted. self.fp.seek(offset) except (KeyError, TypeError): - return None + pass else: from . import TiffImagePlugin info = TiffImagePlugin.ImageFileDirectory_v2(self.head, group=group) info.load(self.fp) - return self._fixup_dict(dict(info)) + return self._fixup_dict(info) - def _get_head(self) -> bytes: - version = b"\x2b" if self.bigtiff else b"\x2a" + def _get_head(self): + version = b"\x2B" if self.bigtiff else b"\x2A" if self.endian == "<": head = b"II" + version + b"\x00" + o32le(8) else: @@ -3996,7 +3910,7 @@ class Exif(_ExifBase): head += b"\x00\x00\x00\x00" return head - def load(self, data: bytes) -> None: + def load(self, data): # Extract EXIF information. This is highly experimental, # and is likely to be replaced with something better in a future # version. @@ -4009,13 +3923,13 @@ class Exif(_ExifBase): self._data.clear() self._hidden_data.clear() self._ifds.clear() - while data and data.startswith(b"Exif\x00\x00"): + if data and data.startswith(b"Exif\x00\x00"): data = data[6:] if not data: self._info = None return - self.fp: IO[bytes] = io.BytesIO(data) + self.fp = io.BytesIO(data) self.head = self.fp.read(8) # process dictionary from . import TiffImagePlugin @@ -4025,7 +3939,7 @@ class Exif(_ExifBase): self.fp.seek(self._info.next) self._info.load(self.fp) - def load_from_fp(self, fp: IO[bytes], offset: int | None = None) -> None: + def load_from_fp(self, fp, offset=None): self._loaded_exif = None self._data.clear() self._hidden_data.clear() @@ -4048,7 +3962,7 @@ class Exif(_ExifBase): self.fp.seek(offset) self._info.load(self.fp) - def _get_merged_dict(self) -> dict[int, Any]: + def _get_merged_dict(self): merged_dict = dict(self) # get EXIF extension @@ -4070,9 +3984,6 @@ class Exif(_ExifBase): head = self._get_head() ifd = TiffImagePlugin.ImageFileDirectory_v2(ifh=head) - for tag, ifd_dict in self._ifds.items(): - if tag not in self: - ifd[tag] = ifd_dict for tag, value in self.items(): if tag in [ ExifTags.IFD.Exif, @@ -4089,32 +4000,28 @@ class Exif(_ExifBase): ifd[tag] = value return b"Exif\x00\x00" + head + ifd.tobytes(offset) - def get_ifd(self, tag: int) -> dict[int, Any]: + def get_ifd(self, tag): if tag not in self._ifds: if tag == ExifTags.IFD.IFD1: if self._info is not None and self._info.next != 0: - ifd = self._get_ifd_dict(self._info.next) - if ifd is not None: - self._ifds[tag] = ifd + self._ifds[tag] = self._get_ifd_dict(self._info.next) elif tag in [ExifTags.IFD.Exif, ExifTags.IFD.GPSInfo]: offset = self._hidden_data.get(tag, self.get(tag)) if offset is not None: - ifd = self._get_ifd_dict(offset, tag) - if ifd is not None: - self._ifds[tag] = ifd - elif tag in [ExifTags.IFD.Interop, ExifTags.IFD.MakerNote]: + self._ifds[tag] = self._get_ifd_dict(offset, tag) + elif tag in [ExifTags.IFD.Interop, ExifTags.IFD.Makernote]: if ExifTags.IFD.Exif not in self._ifds: self.get_ifd(ExifTags.IFD.Exif) tag_data = self._ifds[ExifTags.IFD.Exif][tag] - if tag == ExifTags.IFD.MakerNote: + if tag == ExifTags.IFD.Makernote: from .TiffImagePlugin import ImageFileDirectory_v2 - if tag_data.startswith(b"FUJIFILM"): + if tag_data[:8] == b"FUJIFILM": ifd_offset = i32le(tag_data, 8) ifd_data = tag_data[ifd_offset:] makernote = {} - for i in range(struct.unpack("H", tag_data[:2])[0]): + for i in range(0, struct.unpack(">H", tag_data[:2])[0]): ifd_tag, typ, count, data = struct.unpack( ">HHL4s", tag_data[i * 12 + 2 : (i + 1) * 12 + 2] ) @@ -4158,9 +4065,7 @@ class Exif(_ExifBase): (offset,) = struct.unpack(">L", data) self.fp.seek(offset) - camerainfo: dict[str, int | bytes] = { - "ModelID": self.fp.read(4) - } + camerainfo = {"ModelID": self.fp.read(4)} self.fp.read(4) # Seconds since 2000 @@ -4176,24 +4081,22 @@ class Exif(_ExifBase): ][1] camerainfo["Parallax"] = handler( ImageFileDirectory_v2(), parallax, False - )[0] + ) self.fp.read(4) camerainfo["Category"] = self.fp.read(2) - makernote = {0x1101: camerainfo} + makernote = {0x1101: dict(self._fixup_dict(camerainfo))} self._ifds[tag] = makernote else: # Interop - ifd = self._get_ifd_dict(tag_data, tag) - if ifd is not None: - self._ifds[tag] = ifd - ifd = self._ifds.setdefault(tag, {}) + self._ifds[tag] = self._get_ifd_dict(tag_data, tag) + ifd = self._ifds.get(tag, {}) if tag == ExifTags.IFD.Exif and self._hidden_data: ifd = { k: v for (k, v) in ifd.items() - if k not in (ExifTags.IFD.Interop, ExifTags.IFD.MakerNote) + if k not in (ExifTags.IFD.Interop, ExifTags.IFD.Makernote) } return ifd @@ -4217,16 +4120,16 @@ class Exif(_ExifBase): keys.update(self._info) return len(keys) - def __getitem__(self, tag: int) -> Any: + def __getitem__(self, tag): if self._info is not None and tag not in self._data and tag in self._info: self._data[tag] = self._fixup(self._info[tag]) del self._info[tag] return self._data[tag] - def __contains__(self, tag: object) -> bool: + def __contains__(self, tag) -> bool: return tag in self._data or (self._info is not None and tag in self._info) - def __setitem__(self, tag: int, value: Any) -> None: + def __setitem__(self, tag, value) -> None: if self._info is not None and tag in self._info: del self._info[tag] self._data[tag] = value @@ -4236,10 +4139,8 @@ class Exif(_ExifBase): del self._info[tag] else: del self._data[tag] - if tag in self._ifds: - del self._ifds[tag] - def __iter__(self) -> Iterator[int]: + def __iter__(self): keys = set(self._data) if self._info is not None: keys.update(self._info) diff --git a/venv/Lib/site-packages/PIL/ImageCms.py b/venv/Lib/site-packages/PIL/ImageCms.py index 513e28a..ec10230 100644 --- a/venv/Lib/site-packages/PIL/ImageCms.py +++ b/venv/Lib/site-packages/PIL/ImageCms.py @@ -25,16 +25,12 @@ from enum import IntEnum, IntFlag from functools import reduce from typing import Any, Literal, SupportsFloat, SupportsInt, Union -from . import Image +from . import Image, __version__ from ._deprecate import deprecate from ._typing import SupportsRead try: from . import _imagingcms as core - - _CmsProfileCompatible = Union[ - str, SupportsRead[bytes], core.CmsProfile, "ImageCmsProfile" - ] except ImportError as ex: # Allow error import for doc purposes, but error out when accessing # anything in core. @@ -108,6 +104,20 @@ pyCMS _VERSION = "1.0.0 pil" +def __getattr__(name: str) -> Any: + if name == "DESCRIPTION": + deprecate("PIL.ImageCms.DESCRIPTION", 12) + return _DESCRIPTION + elif name == "VERSION": + deprecate("PIL.ImageCms.VERSION", 12) + return _VERSION + elif name == "FLAGS": + deprecate("PIL.ImageCms.FLAGS", 12, "PIL.ImageCms.Flags") + return _FLAGS + msg = f"module '{__name__}' has no attribute '{name}'" + raise AttributeError(msg) + + # --------------------------------------------------------------------. @@ -234,7 +244,6 @@ class ImageCmsProfile: low-level profile object """ - self.filename: str | None = None if isinstance(profile, str): if sys.platform == "win32": @@ -243,24 +252,22 @@ class ImageCmsProfile: profile_bytes_path.decode("ascii") except UnicodeDecodeError: with open(profile, "rb") as f: - self.profile = core.profile_frombytes(f.read()) + self._set(core.profile_frombytes(f.read())) return - self.filename = profile - self.profile = core.profile_open(profile) + self._set(core.profile_open(profile), profile) elif hasattr(profile, "read"): - self.profile = core.profile_frombytes(profile.read()) + self._set(core.profile_frombytes(profile.read())) elif isinstance(profile, core.CmsProfile): - self.profile = profile + self._set(profile) else: msg = "Invalid type for Profile" # type: ignore[unreachable] raise TypeError(msg) - def __getattr__(self, name: str) -> Any: - if name in ("product_name", "product_info"): - deprecate(f"ImageCms.ImageCmsProfile.{name}", 13) - return None - msg = f"'{self.__class__.__name__}' object has no attribute '{name}'" - raise AttributeError(msg) + def _set(self, profile: core.CmsProfile, filename: str | None = None) -> None: + self.profile = profile + self.filename = filename + self.product_name = None # profile.product_name + self.product_info = None # profile.product_info def tobytes(self) -> bytes: """ @@ -292,6 +299,31 @@ class ImageCmsTransform(Image.ImagePointHandler): proof_intent: Intent = Intent.ABSOLUTE_COLORIMETRIC, flags: Flags = Flags.NONE, ): + supported_modes = ( + "RGB", + "RGBA", + "RGBX", + "CMYK", + "I;16", + "I;16L", + "I;16B", + "YCbCr", + "LAB", + "L", + "1", + ) + for mode in (input_mode, output_mode): + if mode not in supported_modes: + deprecate( + mode, + 12, + { + "L;16": "I;16 or I;16L", + "L:16B": "I;16B", + "YCCA": "YCbCr", + "YCC": "YCbCr", + }.get(mode), + ) if proof is None: self.transform = core.buildTransform( input.profile, output.profile, input_mode, output_mode, intent, flags @@ -317,17 +349,19 @@ class ImageCmsTransform(Image.ImagePointHandler): return self.apply(im) def apply(self, im: Image.Image, imOut: Image.Image | None = None) -> Image.Image: + im.load() if imOut is None: imOut = Image.new(self.output_mode, im.size, None) - self.transform.apply(im.getim(), imOut.getim()) + self.transform.apply(im.im.id, imOut.im.id) imOut.info["icc_profile"] = self.output_profile.tobytes() return imOut def apply_in_place(self, im: Image.Image) -> Image.Image: + im.load() if im.mode != self.output_mode: msg = "mode mismatch" raise ValueError(msg) # wrong output mode - self.transform.apply(im.getim(), im.getim()) + self.transform.apply(im.im.id, im.im.id) im.info["icc_profile"] = self.output_profile.tobytes() return im @@ -357,6 +391,10 @@ def get_display_profile(handle: SupportsInt | None = None) -> ImageCmsProfile | # pyCMS compatible layer # --------------------------------------------------------------------. +_CmsProfileCompatible = Union[ + str, SupportsRead[bytes], core.CmsProfile, ImageCmsProfile +] + class PyCMSError(Exception): """(pyCMS) Exception class. @@ -1074,3 +1112,16 @@ def isIntentSupported( return -1 except (AttributeError, OSError, TypeError, ValueError) as v: raise PyCMSError(v) from v + + +def versions() -> tuple[str, str | None, str, str]: + """ + (pyCMS) Fetches versions. + """ + + deprecate( + "PIL.ImageCms.versions()", + 12, + '(PIL.features.version("littlecms2"), sys.version, PIL.__version__)', + ) + return _VERSION, core.littlecms_version, sys.version.split()[0], __version__ diff --git a/venv/Lib/site-packages/PIL/ImageDraw.py b/venv/Lib/site-packages/PIL/ImageDraw.py index 8bcf2d8..244d3d5 100644 --- a/venv/Lib/site-packages/PIL/ImageDraw.py +++ b/venv/Lib/site-packages/PIL/ImageDraw.py @@ -32,23 +32,26 @@ from __future__ import annotations import math +import numbers import struct -from collections.abc import Sequence -from typing import cast +from types import ModuleType +from typing import TYPE_CHECKING, AnyStr, Callable, List, Sequence, Tuple, Union, cast -from . import Image, ImageColor, ImageText - -TYPE_CHECKING = False -if TYPE_CHECKING: - from collections.abc import Callable - from types import ModuleType - from typing import Any, AnyStr - - from . import ImageDraw2, ImageFont - from ._typing import Coords, _Ink +from . import Image, ImageColor +from ._deprecate import deprecate +from ._typing import Coords # experimental access to the outline API -Outline: Callable[[], Image.core._Outline] = Image.core.outline +Outline: Callable[[], Image.core._Outline] | None +try: + Outline = Image.core.outline +except AttributeError: + Outline = None + +if TYPE_CHECKING: + from . import ImageDraw2, ImageFont + +_Ink = Union[float, Tuple[int, ...], str] """ A simple 2D drawing interface for PIL images. @@ -74,7 +77,9 @@ class ImageDraw: must be the same as the image mode. If omitted, the mode defaults to the mode of the image. """ - im._ensure_mutable() + im.load() + if im.readonly: + im._copy() # make it writeable blend = 0 if mode is None: mode = im.mode @@ -154,13 +159,13 @@ class ImageDraw: if ink is not None: if isinstance(ink, str): ink = ImageColor.getcolor(ink, self.mode) - if self.palette and isinstance(ink, tuple): + if self.palette and not isinstance(ink, numbers.Number): ink = self.palette.getcolor(ink, self._image) result_ink = self.draw.draw_ink(ink) if fill is not None: if isinstance(fill, str): fill = ImageColor.getcolor(fill, self.mode) - if self.palette and isinstance(fill, tuple): + if self.palette and not isinstance(fill, numbers.Number): fill = self.palette.getcolor(fill, self._image) result_fill = self.draw.draw_ink(fill) return result_ink, result_fill @@ -363,10 +368,22 @@ class ImageDraw: # use the fill as a mask mask = Image.new("1", self.im.size) mask_ink = self._getink(1)[0] - draw = Draw(mask) + + fill_im = mask.copy() + draw = Draw(fill_im) draw.draw.draw_polygon(xy, mask_ink, 1) - self.draw.draw_polygon(xy, ink, 0, width * 2 - 1, mask.im) + ink_im = mask.copy() + draw = Draw(ink_im) + width = width * 2 - 1 + draw.draw.draw_polygon(xy, mask_ink, 0, width) + + mask.paste(ink_im, mask=fill_im) + + im = Image.new(self.mode, self.im.size) + draw = Draw(im) + draw.draw.draw_polygon(xy, ink, 0, width) + self.im.paste(im.im, (0, 0) + im.size, mask.im) def regular_polygon( self, @@ -487,7 +504,7 @@ class ImageDraw: if full_x: self.draw.draw_rectangle((x0, y0 + r + 1, x1, y1 - r - 1), fill_ink, 1) - elif x1 - r - 1 > x0 + r + 1: + else: self.draw.draw_rectangle((x0 + r + 1, y0, x1 - r - 1, y1), fill_ink, 1) if not full_x and not full_y: left = [x0, y0, x0 + r, y1] @@ -535,42 +552,68 @@ class ImageDraw: right[3] -= r + 1 self.draw.draw_rectangle(right, ink, 1) + def _multiline_check(self, text: AnyStr) -> bool: + split_character = "\n" if isinstance(text, str) else b"\n" + + return split_character in text + + def _multiline_split(self, text: AnyStr) -> list[AnyStr]: + return text.split("\n" if isinstance(text, str) else b"\n") + + def _multiline_spacing(self, font, spacing, stroke_width): + return ( + self.textbbox((0, 0), "A", font, stroke_width=stroke_width)[3] + + stroke_width + + spacing + ) + def text( self, xy: tuple[float, float], - text: AnyStr | ImageText.Text, - fill: _Ink | None = None, + text: str, + fill=None, font: ( ImageFont.ImageFont | ImageFont.FreeTypeFont | ImageFont.TransposedFont | None ) = None, - anchor: str | None = None, - spacing: float = 4, - align: str = "left", - direction: str | None = None, - features: list[str] | None = None, - language: str | None = None, - stroke_width: float = 0, - stroke_fill: _Ink | None = None, - embedded_color: bool = False, - *args: Any, - **kwargs: Any, + anchor=None, + spacing=4, + align="left", + direction=None, + features=None, + language=None, + stroke_width=0, + stroke_fill=None, + embedded_color=False, + *args, + **kwargs, ) -> None: """Draw text.""" - if isinstance(text, ImageText.Text): - image_text = text - else: - if font is None: - font = self._getfont(kwargs.get("font_size")) - image_text = ImageText.Text( - text, font, self.mode, spacing, direction, features, language + if embedded_color and self.mode not in ("RGB", "RGBA"): + msg = "Embedded color supported only in RGB and RGBA modes" + raise ValueError(msg) + + if font is None: + font = self._getfont(kwargs.get("font_size")) + + if self._multiline_check(text): + return self.multiline_text( + xy, + text, + fill, + font, + anchor, + spacing, + align, + direction, + features, + language, + stroke_width, + stroke_fill, + embedded_color, ) - if embedded_color: - image_text.embed_color() - if stroke_width: - image_text.stroke(stroke_width, stroke_fill) def getink(fill: _Ink | None) -> int: ink, fill_ink = self._getink(fill) @@ -579,83 +622,75 @@ class ImageDraw: return fill_ink return ink - ink = getink(fill) - if ink is None: - return - - stroke_ink = None - if image_text.stroke_width: - stroke_ink = ( - getink(image_text.stroke_fill) - if image_text.stroke_fill is not None - else ink - ) - - for xy, anchor, line in image_text._split(xy, anchor, align): - - def draw_text(ink: int, stroke_width: float = 0) -> None: - mode = self.fontmode - if stroke_width == 0 and embedded_color: - mode = "RGBA" - coord = [] - for i in range(2): - coord.append(int(xy[i])) - start = (math.modf(xy[0])[0], math.modf(xy[1])[0]) + def draw_text(ink, stroke_width=0, stroke_offset=None) -> None: + mode = self.fontmode + if stroke_width == 0 and embedded_color: + mode = "RGBA" + coord = [] + start = [] + for i in range(2): + coord.append(int(xy[i])) + start.append(math.modf(xy[i])[0]) + try: + mask, offset = font.getmask2( # type: ignore[union-attr,misc] + text, + mode, + direction=direction, + features=features, + language=language, + stroke_width=stroke_width, + anchor=anchor, + ink=ink, + start=start, + *args, + **kwargs, + ) + coord = [coord[0] + offset[0], coord[1] + offset[1]] + except AttributeError: try: - mask, offset = image_text.font.getmask2( # type: ignore[union-attr,misc] - line, + mask = font.getmask( # type: ignore[misc] + text, mode, - direction=direction, - features=features, - language=language, - stroke_width=stroke_width, - stroke_filled=True, - anchor=anchor, - ink=ink, + direction, + features, + language, + stroke_width, + anchor, + ink, start=start, *args, **kwargs, ) - coord = [coord[0] + offset[0], coord[1] + offset[1]] - except AttributeError: - try: - mask = image_text.font.getmask( # type: ignore[misc] - line, - mode, - direction, - features, - language, - stroke_width, - anchor, - ink, - start=start, - *args, - **kwargs, - ) - except TypeError: - mask = image_text.font.getmask(line) - if mode == "RGBA": - # image_text.font.getmask2(mode="RGBA") - # returns color in RGB bands and mask in A - # extract mask and set text alpha - color, mask = mask, mask.getband(3) - ink_alpha = struct.pack("i", ink)[3] - color.fillband(3, ink_alpha) - x, y = coord - if self.im is not None: - self.im.paste( - color, (x, y, x + mask.size[0], y + mask.size[1]), mask - ) - else: - self.draw.draw_bitmap(coord, mask, ink) + except TypeError: + mask = font.getmask(text) + if stroke_offset: + coord = [coord[0] + stroke_offset[0], coord[1] + stroke_offset[1]] + if mode == "RGBA": + # font.getmask2(mode="RGBA") returns color in RGB bands and mask in A + # extract mask and set text alpha + color, mask = mask, mask.getband(3) + ink_alpha = struct.pack("i", ink)[3] + color.fillband(3, ink_alpha) + x, y = coord + if self.im is not None: + self.im.paste( + color, (x, y, x + mask.size[0], y + mask.size[1]), mask + ) + else: + self.draw.draw_bitmap(coord, mask, ink) + + ink = getink(fill) + if ink is not None: + stroke_ink = None + if stroke_width: + stroke_ink = getink(stroke_fill) if stroke_fill is not None else ink if stroke_ink is not None: # Draw stroked text - draw_text(stroke_ink, image_text.stroke_width) + draw_text(stroke_ink, stroke_width) # Draw normal text - if ink != stroke_ink: - draw_text(ink) + draw_text(ink, 0) else: # Only draw normal text draw_text(ink) @@ -663,142 +698,272 @@ class ImageDraw: def multiline_text( self, xy: tuple[float, float], - text: AnyStr, - fill: _Ink | None = None, + text: str, + fill=None, font: ( ImageFont.ImageFont | ImageFont.FreeTypeFont | ImageFont.TransposedFont | None ) = None, - anchor: str | None = None, - spacing: float = 4, - align: str = "left", - direction: str | None = None, - features: list[str] | None = None, - language: str | None = None, - stroke_width: float = 0, - stroke_fill: _Ink | None = None, - embedded_color: bool = False, + anchor=None, + spacing=4, + align="left", + direction=None, + features=None, + language=None, + stroke_width=0, + stroke_fill=None, + embedded_color=False, *, - font_size: float | None = None, + font_size=None, ) -> None: - return self.text( - xy, - text, - fill, - font, - anchor, - spacing, - align, - direction, - features, - language, - stroke_width, - stroke_fill, - embedded_color, - font_size=font_size, - ) + if direction == "ttb": + msg = "ttb direction is unsupported for multiline text" + raise ValueError(msg) + + if anchor is None: + anchor = "la" + elif len(anchor) != 2: + msg = "anchor must be a 2 character string" + raise ValueError(msg) + elif anchor[1] in "tb": + msg = "anchor not supported for multiline text" + raise ValueError(msg) + + if font is None: + font = self._getfont(font_size) + + widths = [] + max_width: float = 0 + lines = self._multiline_split(text) + line_spacing = self._multiline_spacing(font, spacing, stroke_width) + for line in lines: + line_width = self.textlength( + line, font, direction=direction, features=features, language=language + ) + widths.append(line_width) + max_width = max(max_width, line_width) + + top = xy[1] + if anchor[1] == "m": + top -= (len(lines) - 1) * line_spacing / 2.0 + elif anchor[1] == "d": + top -= (len(lines) - 1) * line_spacing + + for idx, line in enumerate(lines): + left = xy[0] + width_difference = max_width - widths[idx] + + # first align left by anchor + if anchor[0] == "m": + left -= width_difference / 2.0 + elif anchor[0] == "r": + left -= width_difference + + # then align by align parameter + if align == "left": + pass + elif align == "center": + left += width_difference / 2.0 + elif align == "right": + left += width_difference + else: + msg = 'align must be "left", "center" or "right"' + raise ValueError(msg) + + self.text( + (left, top), + line, + fill, + font, + anchor, + direction=direction, + features=features, + language=language, + stroke_width=stroke_width, + stroke_fill=stroke_fill, + embedded_color=embedded_color, + ) + top += line_spacing def textlength( self, - text: AnyStr, + text: str, font: ( ImageFont.ImageFont | ImageFont.FreeTypeFont | ImageFont.TransposedFont | None ) = None, - direction: str | None = None, - features: list[str] | None = None, - language: str | None = None, - embedded_color: bool = False, + direction=None, + features=None, + language=None, + embedded_color=False, *, - font_size: float | None = None, + font_size=None, ) -> float: """Get the length of a given string, in pixels with 1/64 precision.""" + if self._multiline_check(text): + msg = "can't measure length of multiline text" + raise ValueError(msg) + if embedded_color and self.mode not in ("RGB", "RGBA"): + msg = "Embedded color supported only in RGB and RGBA modes" + raise ValueError(msg) + if font is None: font = self._getfont(font_size) - image_text = ImageText.Text( - text, - font, - self.mode, - direction=direction, - features=features, - language=language, - ) - if embedded_color: - image_text.embed_color() - return image_text.get_length() + mode = "RGBA" if embedded_color else self.fontmode + return font.getlength(text, mode, direction, features, language) def textbbox( self, - xy: tuple[float, float], - text: AnyStr, - font: ( - ImageFont.ImageFont - | ImageFont.FreeTypeFont - | ImageFont.TransposedFont - | None - ) = None, - anchor: str | None = None, - spacing: float = 4, - align: str = "left", - direction: str | None = None, - features: list[str] | None = None, - language: str | None = None, - stroke_width: float = 0, - embedded_color: bool = False, + xy, + text, + font=None, + anchor=None, + spacing=4, + align="left", + direction=None, + features=None, + language=None, + stroke_width=0, + embedded_color=False, *, - font_size: float | None = None, - ) -> tuple[float, float, float, float]: + font_size=None, + ) -> tuple[int, int, int, int]: """Get the bounding box of a given string, in pixels.""" + if embedded_color and self.mode not in ("RGB", "RGBA"): + msg = "Embedded color supported only in RGB and RGBA modes" + raise ValueError(msg) + if font is None: font = self._getfont(font_size) - image_text = ImageText.Text( - text, font, self.mode, spacing, direction, features, language + + if self._multiline_check(text): + return self.multiline_textbbox( + xy, + text, + font, + anchor, + spacing, + align, + direction, + features, + language, + stroke_width, + embedded_color, + ) + + mode = "RGBA" if embedded_color else self.fontmode + bbox = font.getbbox( + text, mode, direction, features, language, stroke_width, anchor ) - if embedded_color: - image_text.embed_color() - if stroke_width: - image_text.stroke(stroke_width) - return image_text.get_bbox(xy, anchor, align) + return bbox[0] + xy[0], bbox[1] + xy[1], bbox[2] + xy[0], bbox[3] + xy[1] def multiline_textbbox( self, - xy: tuple[float, float], - text: AnyStr, - font: ( - ImageFont.ImageFont - | ImageFont.FreeTypeFont - | ImageFont.TransposedFont - | None - ) = None, - anchor: str | None = None, - spacing: float = 4, - align: str = "left", - direction: str | None = None, - features: list[str] | None = None, - language: str | None = None, - stroke_width: float = 0, - embedded_color: bool = False, + xy, + text, + font=None, + anchor=None, + spacing=4, + align="left", + direction=None, + features=None, + language=None, + stroke_width=0, + embedded_color=False, *, - font_size: float | None = None, - ) -> tuple[float, float, float, float]: - return self.textbbox( - xy, - text, - font, - anchor, - spacing, - align, - direction, - features, - language, - stroke_width, - embedded_color, - font_size=font_size, - ) + font_size=None, + ) -> tuple[int, int, int, int]: + if direction == "ttb": + msg = "ttb direction is unsupported for multiline text" + raise ValueError(msg) + + if anchor is None: + anchor = "la" + elif len(anchor) != 2: + msg = "anchor must be a 2 character string" + raise ValueError(msg) + elif anchor[1] in "tb": + msg = "anchor not supported for multiline text" + raise ValueError(msg) + + if font is None: + font = self._getfont(font_size) + + widths = [] + max_width: float = 0 + lines = self._multiline_split(text) + line_spacing = self._multiline_spacing(font, spacing, stroke_width) + for line in lines: + line_width = self.textlength( + line, + font, + direction=direction, + features=features, + language=language, + embedded_color=embedded_color, + ) + widths.append(line_width) + max_width = max(max_width, line_width) + + top = xy[1] + if anchor[1] == "m": + top -= (len(lines) - 1) * line_spacing / 2.0 + elif anchor[1] == "d": + top -= (len(lines) - 1) * line_spacing + + bbox: tuple[int, int, int, int] | None = None + + for idx, line in enumerate(lines): + left = xy[0] + width_difference = max_width - widths[idx] + + # first align left by anchor + if anchor[0] == "m": + left -= width_difference / 2.0 + elif anchor[0] == "r": + left -= width_difference + + # then align by align parameter + if align == "left": + pass + elif align == "center": + left += width_difference / 2.0 + elif align == "right": + left += width_difference + else: + msg = 'align must be "left", "center" or "right"' + raise ValueError(msg) + + bbox_line = self.textbbox( + (left, top), + line, + font, + anchor, + direction=direction, + features=features, + language=language, + stroke_width=stroke_width, + embedded_color=embedded_color, + ) + if bbox is None: + bbox = bbox_line + else: + bbox = ( + min(bbox[0], bbox_line[0]), + min(bbox[1], bbox_line[1]), + max(bbox[2], bbox_line[2]), + max(bbox[3], bbox_line[3]), + ) + + top += line_spacing + + if bbox is None: + return xy[0], xy[1], xy[0], xy[1] + return bbox def Draw(im: Image.Image, mode: str | None = None) -> ImageDraw: @@ -818,11 +983,16 @@ def Draw(im: Image.Image, mode: str | None = None) -> ImageDraw: return ImageDraw(im, mode) -def getdraw(im: Image.Image | None = None) -> tuple[ImageDraw2.Draw | None, ModuleType]: +def getdraw( + im: Image.Image | None = None, hints: list[str] | None = None +) -> tuple[ImageDraw2.Draw | None, ModuleType]: """ :param im: The image to draw in. + :param hints: An optional list of hints. Deprecated. :returns: A (drawing context, drawing resource factory) tuple. """ + if hints is not None: + deprecate("'hints' parameter", 12) from . import ImageDraw2 draw = ImageDraw2.Draw(im) if im is not None else None @@ -954,7 +1124,7 @@ def _compute_regular_polygon_vertices( msg = "bounding_circle should only contain numeric data" raise ValueError(msg) - *centroid, polygon_radius = cast(list[float], list(bounding_circle)) + *centroid, polygon_radius = cast(List[float], list(bounding_circle)) elif len(bounding_circle) == 2 and isinstance(bounding_circle[0], (list, tuple)): if not all( isinstance(i, (int, float)) for i in bounding_circle[0] @@ -966,7 +1136,7 @@ def _compute_regular_polygon_vertices( msg = "bounding_circle centre should contain 2D coordinates (e.g. (x, y))" raise ValueError(msg) - centroid = cast(list[float], list(bounding_circle[0])) + centroid = cast(List[float], list(bounding_circle[0])) polygon_radius = cast(float, bounding_circle[1]) else: msg = ( @@ -1010,7 +1180,7 @@ def _compute_regular_polygon_vertices( degrees = 360 / n_sides # Start with the bottom left polygon vertex current_angle = (270 - 0.5 * degrees) + rotation - for _ in range(n_sides): + for _ in range(0, n_sides): angles.append(current_angle) current_angle += degrees if current_angle > 360: @@ -1033,4 +1203,4 @@ def _color_diff( first = color1 if isinstance(color1, tuple) else (color1,) second = color2 if isinstance(color2, tuple) else (color2,) - return sum(abs(first[i] - second[i]) for i in range(len(second))) + return sum(abs(first[i] - second[i]) for i in range(0, len(second))) diff --git a/venv/Lib/site-packages/PIL/ImageDraw2.py b/venv/Lib/site-packages/PIL/ImageDraw2.py index 3d68658..e89a78b 100644 --- a/venv/Lib/site-packages/PIL/ImageDraw2.py +++ b/venv/Lib/site-packages/PIL/ImageDraw2.py @@ -24,10 +24,10 @@ """ from __future__ import annotations -from typing import Any, AnyStr, BinaryIO +from typing import BinaryIO from . import Image, ImageColor, ImageDraw, ImageFont, ImagePath -from ._typing import Coords, StrOrBytesPath +from ._typing import StrOrBytesPath class Pen: @@ -74,19 +74,12 @@ class Draw: image = Image.new(image, size, color) self.draw = ImageDraw.Draw(image) self.image = image - self.transform: tuple[float, float, float, float, float, float] | None = None + self.transform = None def flush(self) -> Image.Image: return self.image - def render( - self, - op: str, - xy: Coords, - pen: Pen | Brush | None, - brush: Brush | Pen | None = None, - **kwargs: Any, - ) -> None: + def render(self, op, xy, pen, brush=None): # handle color arguments outline = fill = None width = 1 @@ -102,89 +95,63 @@ class Draw: fill = pen.color # handle transformation if self.transform: - path = ImagePath.Path(xy) - path.transform(self.transform) - xy = path + xy = ImagePath.Path(xy) + xy.transform(self.transform) # render the item - if op in ("arc", "line"): - kwargs.setdefault("fill", outline) - else: - kwargs.setdefault("fill", fill) - kwargs.setdefault("outline", outline) if op == "line": - kwargs.setdefault("width", width) - getattr(self.draw, op)(xy, **kwargs) + self.draw.line(xy, fill=outline, width=width) + else: + getattr(self.draw, op)(xy, fill=fill, outline=outline) - def settransform(self, offset: tuple[float, float]) -> None: + def settransform(self, offset): """Sets a transformation offset.""" (xoffset, yoffset) = offset self.transform = (1, 0, xoffset, 0, 1, yoffset) - def arc( - self, - xy: Coords, - pen: Pen | Brush | None, - start: float, - end: float, - *options: Any, - ) -> None: + def arc(self, xy, start, end, *options): """ Draws an arc (a portion of a circle outline) between the start and end angles, inside the given bounding box. .. seealso:: :py:meth:`PIL.ImageDraw.ImageDraw.arc` """ - self.render("arc", xy, pen, *options, start=start, end=end) + self.render("arc", xy, start, end, *options) - def chord( - self, - xy: Coords, - pen: Pen | Brush | None, - start: float, - end: float, - *options: Any, - ) -> None: + def chord(self, xy, start, end, *options): """ Same as :py:meth:`~PIL.ImageDraw2.Draw.arc`, but connects the end points with a straight line. .. seealso:: :py:meth:`PIL.ImageDraw.ImageDraw.chord` """ - self.render("chord", xy, pen, *options, start=start, end=end) + self.render("chord", xy, start, end, *options) - def ellipse(self, xy: Coords, pen: Pen | Brush | None, *options: Any) -> None: + def ellipse(self, xy, *options): """ Draws an ellipse inside the given bounding box. .. seealso:: :py:meth:`PIL.ImageDraw.ImageDraw.ellipse` """ - self.render("ellipse", xy, pen, *options) + self.render("ellipse", xy, *options) - def line(self, xy: Coords, pen: Pen | Brush | None, *options: Any) -> None: + def line(self, xy, *options): """ Draws a line between the coordinates in the ``xy`` list. .. seealso:: :py:meth:`PIL.ImageDraw.ImageDraw.line` """ - self.render("line", xy, pen, *options) + self.render("line", xy, *options) - def pieslice( - self, - xy: Coords, - pen: Pen | Brush | None, - start: float, - end: float, - *options: Any, - ) -> None: + def pieslice(self, xy, start, end, *options): """ Same as arc, but also draws straight lines between the end points and the center of the bounding box. .. seealso:: :py:meth:`PIL.ImageDraw.ImageDraw.pieslice` """ - self.render("pieslice", xy, pen, *options, start=start, end=end) + self.render("pieslice", xy, start, end, *options) - def polygon(self, xy: Coords, pen: Pen | Brush | None, *options: Any) -> None: + def polygon(self, xy, *options): """ Draws a polygon. @@ -195,31 +162,28 @@ class Draw: .. seealso:: :py:meth:`PIL.ImageDraw.ImageDraw.polygon` """ - self.render("polygon", xy, pen, *options) + self.render("polygon", xy, *options) - def rectangle(self, xy: Coords, pen: Pen | Brush | None, *options: Any) -> None: + def rectangle(self, xy, *options): """ Draws a rectangle. .. seealso:: :py:meth:`PIL.ImageDraw.ImageDraw.rectangle` """ - self.render("rectangle", xy, pen, *options) + self.render("rectangle", xy, *options) - def text(self, xy: tuple[float, float], text: AnyStr, font: Font) -> None: + def text(self, xy, text, font): """ Draws the string at the given position. .. seealso:: :py:meth:`PIL.ImageDraw.ImageDraw.text` """ if self.transform: - path = ImagePath.Path(xy) - path.transform(self.transform) - xy = path + xy = ImagePath.Path(xy) + xy.transform(self.transform) self.draw.text(xy, text, font=font.font, fill=font.color) - def textbbox( - self, xy: tuple[float, float], text: AnyStr, font: Font - ) -> tuple[float, float, float, float]: + def textbbox(self, xy, text, font): """ Returns bounding box (in pixels) of given text. @@ -228,12 +192,11 @@ class Draw: .. seealso:: :py:meth:`PIL.ImageDraw.ImageDraw.textbbox` """ if self.transform: - path = ImagePath.Path(xy) - path.transform(self.transform) - xy = path + xy = ImagePath.Path(xy) + xy.transform(self.transform) return self.draw.textbbox(xy, text, font=font.font) - def textlength(self, text: AnyStr, font: Font) -> float: + def textlength(self, text, font): """ Returns length (in pixels) of given text. This is the amount by which following text should be offset. diff --git a/venv/Lib/site-packages/PIL/ImageEnhance.py b/venv/Lib/site-packages/PIL/ImageEnhance.py index 0e7e6dd..d7e99a9 100644 --- a/venv/Lib/site-packages/PIL/ImageEnhance.py +++ b/venv/Lib/site-packages/PIL/ImageEnhance.py @@ -55,9 +55,7 @@ class Color(_Enhance): if "A" in image.getbands(): self.intermediate_mode = "LA" - if self.intermediate_mode != image.mode: - image = image.convert(self.intermediate_mode).convert(image.mode) - self.degenerate = image + self.degenerate = image.convert(self.intermediate_mode).convert(image.mode) class Contrast(_Enhance): @@ -70,15 +68,11 @@ class Contrast(_Enhance): def __init__(self, image: Image.Image) -> None: self.image = image - if image.mode != "L": - image = image.convert("L") - mean = int(ImageStat.Stat(image).mean[0] + 0.5) - self.degenerate = Image.new("L", image.size, mean) - if self.degenerate.mode != self.image.mode: - self.degenerate = self.degenerate.convert(self.image.mode) + mean = int(ImageStat.Stat(image.convert("L")).mean[0] + 0.5) + self.degenerate = Image.new("L", image.size, mean).convert(image.mode) - if "A" in self.image.getbands(): - self.degenerate.putalpha(self.image.getchannel("A")) + if "A" in image.getbands(): + self.degenerate.putalpha(image.getchannel("A")) class Brightness(_Enhance): diff --git a/venv/Lib/site-packages/PIL/ImageFile.py b/venv/Lib/site-packages/PIL/ImageFile.py index 3390dfa..69e7ee5 100644 --- a/venv/Lib/site-packages/PIL/ImageFile.py +++ b/venv/Lib/site-packages/PIL/ImageFile.py @@ -31,33 +31,15 @@ from __future__ import annotations import abc import io import itertools -import logging -import os import struct -from typing import IO, Any, NamedTuple, cast +import sys +from typing import IO, Any, NamedTuple -from . import ExifTags, Image -from ._util import DeferredError, is_path - -TYPE_CHECKING = False -if TYPE_CHECKING: - from ._typing import StrOrBytesPath - -logger = logging.getLogger(__name__) +from . import Image +from ._deprecate import deprecate +from ._util import is_path MAXBLOCK = 65536 -""" -By default, Pillow processes image data in blocks. This helps to prevent excessive use -of resources. Codecs may disable this behaviour with ``_pulls_fd`` or ``_pushes_fd``. - -When reading an image, this is the number of bytes to read at once. - -When writing an image, this is the number of bytes to write at once. -If the image width times 4 is greater, then that will be used instead. -Plugins may also set a greater number. - -User code may set this to another number. -""" SAFEBLOCK = 1024 * 1024 @@ -94,16 +76,26 @@ def _get_oserror(error: int, *, encoder: bool) -> OSError: return OSError(msg) -def _tilesort(t: _Tile) -> int: +def raise_oserror(error: int) -> OSError: + deprecate( + "raise_oserror", + 12, + action="It is only useful for translating error codes returned by a codec's " + "decode() method, which ImageFile already does automatically.", + ) + raise _get_oserror(error, encoder=False) + + +def _tilesort(t): # sort on offset return t[2] class _Tile(NamedTuple): codec_name: str - extents: tuple[int, int, int, int] | None - offset: int = 0 - args: tuple[Any, ...] | str | None = None + extents: tuple[int, int, int, int] + offset: int + args: tuple[Any, ...] | str | None # @@ -114,36 +106,32 @@ class _Tile(NamedTuple): class ImageFile(Image.Image): """Base class for image file format handlers.""" - def __init__( - self, fp: StrOrBytesPath | IO[bytes], filename: str | bytes | None = None - ) -> None: + def __init__(self, fp=None, filename=None): super().__init__() self._min_frame = 0 - self.custom_mimetype: str | None = None + self.custom_mimetype = None - self.tile: list[_Tile] = [] - """ A list of tile descriptors """ + self.tile = None + """ A list of tile descriptors, or ``None`` """ self.readonly = 1 # until we know better - self.decoderconfig: tuple[Any, ...] = () + self.decoderconfig = () self.decodermaxblock = MAXBLOCK - self.fp: IO[bytes] | None - self._fp: IO[bytes] | DeferredError if is_path(fp): # filename self.fp = open(fp, "rb") - self.filename = os.fspath(fp) + self.filename = fp self._exclusive_fp = True else: # stream - self.fp = cast(IO[bytes], fp) - self.filename = filename if filename is not None else "" + self.fp = fp + self.filename = filename # can be overridden - self._exclusive_fp = False + self._exclusive_fp = None try: try: @@ -166,97 +154,6 @@ class ImageFile(Image.Image): self.fp.close() raise - def _open(self) -> None: - pass - - # Context manager support - def __enter__(self) -> ImageFile: - return self - - def _close_fp(self) -> None: - if getattr(self, "_fp", False) and not isinstance(self._fp, DeferredError): - if self._fp != self.fp: - self._fp.close() - self._fp = DeferredError(ValueError("Operation on closed image")) - if self.fp: - self.fp.close() - - def __exit__(self, *args: object) -> None: - if getattr(self, "_exclusive_fp", False): - self._close_fp() - self.fp = None - - def close(self) -> None: - """ - Closes the file pointer, if possible. - - This operation will destroy the image core and release its memory. - The image data will be unusable afterward. - - This function is required to close images that have multiple frames or - have not had their file read and closed by the - :py:meth:`~PIL.Image.Image.load` method. See :ref:`file-handling` for - more information. - """ - try: - self._close_fp() - self.fp = None - except Exception as msg: - logger.debug("Error closing: %s", msg) - - super().close() - - def get_child_images(self) -> list[ImageFile]: - child_images = [] - exif = self.getexif() - ifds = [] - if ExifTags.Base.SubIFDs in exif: - subifd_offsets = exif[ExifTags.Base.SubIFDs] - if subifd_offsets: - if not isinstance(subifd_offsets, tuple): - subifd_offsets = (subifd_offsets,) - for subifd_offset in subifd_offsets: - ifds.append((exif._get_ifd_dict(subifd_offset), subifd_offset)) - ifd1 = exif.get_ifd(ExifTags.IFD.IFD1) - if ifd1 and ifd1.get(ExifTags.Base.JpegIFOffset): - assert exif._info is not None - ifds.append((ifd1, exif._info.next)) - - offset = None - for ifd, ifd_offset in ifds: - assert self.fp is not None - current_offset = self.fp.tell() - if offset is None: - offset = current_offset - - fp = self.fp - if ifd is not None: - thumbnail_offset = ifd.get(ExifTags.Base.JpegIFOffset) - if thumbnail_offset is not None: - thumbnail_offset += getattr(self, "_exif_offset", 0) - self.fp.seek(thumbnail_offset) - - length = ifd.get(ExifTags.Base.JpegIFByteCount) - assert isinstance(length, int) - data = self.fp.read(length) - fp = io.BytesIO(data) - - with Image.open(fp) as im: - from . import TiffImagePlugin - - if thumbnail_offset is None and isinstance( - im, TiffImagePlugin.TiffImageFile - ): - im._frame_pos = [ifd_offset] - im._seek(0) - im.load() - child_images.append(im) - - if offset is not None: - assert self.fp is not None - self.fp.seek(offset) - return child_images - def get_format_mimetype(self) -> str | None: if self.custom_mimetype: return self.custom_mimetype @@ -264,13 +161,8 @@ class ImageFile(Image.Image): return Image.MIME.get(self.format.upper()) return None - def __getstate__(self) -> list[Any]: - return super().__getstate__() + [self.filename] - - def __setstate__(self, state: list[Any]) -> None: + def __setstate__(self, state): self.tile = [] - if len(state) > 5: - self.filename = state[5] super().__setstate__(state) def verify(self) -> None: @@ -278,14 +170,14 @@ class ImageFile(Image.Image): # raise exception if something's wrong. must be called # directly after open, and closes file when finished. - if self._exclusive_fp and self.fp: + if self._exclusive_fp: self.fp.close() self.fp = None - def load(self) -> Image.core.PixelAccess | None: + def load(self): """Load image data based on tile list""" - if not self.tile and self._im is None: + if self.tile is None: msg = "cannot load this image" raise OSError(msg) @@ -293,24 +185,25 @@ class ImageFile(Image.Image): if not self.tile: return pixel - self.map: mmap.mmap | None = None + self.map = None use_mmap = self.filename and len(self.tile) == 1 + # As of pypy 2.1.0, memory mapping was failing here. + use_mmap = use_mmap and not hasattr(sys, "pypy_version_info") - assert self.fp is not None readonly = 0 # look for read/seek overrides - if hasattr(self, "load_read"): + try: read = self.load_read # don't use mmap if there are custom read/seek functions use_mmap = False - else: + except AttributeError: read = self.fp.read - if hasattr(self, "load_seek"): + try: seek = self.load_seek use_mmap = False - else: + except AttributeError: seek = self.fp.seek if use_mmap: @@ -320,14 +213,10 @@ class ImageFile(Image.Image): args = (args, 0, 1) if ( decoder_name == "raw" - and isinstance(args, tuple) and len(args) >= 3 and args[0] == self.mode and args[0] in Image._MAPMODES ): - if offset < 0: - msg = "Tile offset cannot be negative" - raise ValueError(msg) try: # use mmap, if possible import mmap @@ -354,8 +243,11 @@ class ImageFile(Image.Image): # sort tiles in file order self.tile.sort(key=_tilesort) - # FIXME: This is a hack to handle TIFF's JpegTables tag. - prefix = getattr(self, "tile_prefix", b"") + try: + # FIXME: This is a hack to handle TIFF's JpegTables tag. + prefix = self.tile_prefix + except AttributeError: + prefix = b"" # Remove consecutive duplicates that only differ by their offset self.tile = [ @@ -364,7 +256,7 @@ class ImageFile(Image.Image): self.tile, lambda tile: (tile[0], tile[1], tile[3]) ) ] - for i, (decoder_name, extents, offset, args) in enumerate(self.tile): + for decoder_name, extents, offset, args in self.tile: seek(offset) decoder = Image._getdecoder( self.mode, decoder_name, args, self.decoderconfig @@ -377,13 +269,8 @@ class ImageFile(Image.Image): else: b = prefix while True: - read_bytes = self.decodermaxblock - if i + 1 < len(self.tile): - next_offset = self.tile[i + 1].offset - if next_offset > offset: - read_bytes = next_offset - offset try: - s = read(read_bytes) + s = read(self.decodermaxblock) except (IndexError, struct.error) as e: # truncated png/gif if LOAD_TRUNCATED_IMAGES: @@ -428,7 +315,7 @@ class ImageFile(Image.Image): def load_prepare(self) -> None: # create image memory if necessary - if self._im is None: + if not self.im or self.im.mode != self.mode or self.im.size != self.size: self.im = Image.core.new(self.mode, self.size) # create palette (optional) if self.mode == "P": @@ -446,14 +333,14 @@ class ImageFile(Image.Image): # def load_read(self, read_bytes: int) -> bytes: # pass - def _seek_check(self, frame: int) -> bool: + def _seek_check(self, frame): if ( frame < self._min_frame # Only check upper limit on frames if additional seek operations # are not required to do so or ( not (hasattr(self, "_n_frames") and self._n_frames is None) - and frame >= getattr(self, "n_frames") + self._min_frame + and frame >= self.n_frames + self._min_frame ) ): msg = "attempt to seek outside sequence" @@ -462,7 +349,7 @@ class ImageFile(Image.Image): return self.tell() != frame -class StubHandler(abc.ABC): +class StubHandler: def open(self, im: StubImageFile) -> None: pass @@ -471,7 +358,7 @@ class StubHandler(abc.ABC): pass -class StubImageFile(ImageFile, metaclass=abc.ABCMeta): +class StubImageFile(ImageFile): """ Base class for stub image loaders. @@ -479,11 +366,11 @@ class StubImageFile(ImageFile, metaclass=abc.ABCMeta): certain format, but relies on external code to load the file. """ - @abc.abstractmethod def _open(self) -> None: - pass + msg = "StubImageFile subclass must implement _open" + raise NotImplementedError(msg) - def load(self) -> Image.core.PixelAccess | None: + def load(self): loader = self._load() if loader is None: msg = f"cannot find loader for this {self.format} file" @@ -491,14 +378,14 @@ class StubImageFile(ImageFile, metaclass=abc.ABCMeta): image = loader.load(self) assert image is not None # become the other object (!) - self.__class__ = image.__class__ # type: ignore[assignment] + self.__class__ = image.__class__ self.__dict__ = image.__dict__ return image.load() - @abc.abstractmethod def _load(self) -> StubHandler | None: """(Hook) Find actual image loader.""" - pass + msg = "StubImageFile subclass must implement _load" + raise NotImplementedError(msg) class Parser: @@ -509,8 +396,8 @@ class Parser: incremental = None image: Image.Image | None = None - data: bytes | None = None - decoder: Image.core.ImagingDecoder | PyDecoder | None = None + data = None + decoder = None offset = 0 finished = 0 @@ -522,7 +409,7 @@ class Parser: """ assert self.data is None, "cannot reuse parsers" - def feed(self, data: bytes) -> None: + def feed(self, data): """ (Consumer) Feed data to the parser. @@ -598,13 +485,13 @@ class Parser: self.image = im - def __enter__(self) -> Parser: + def __enter__(self): return self def __exit__(self, *args: object) -> None: self.close() - def close(self) -> Image.Image: + def close(self): """ (Consumer) Close the stream. @@ -638,7 +525,7 @@ class Parser: # -------------------------------------------------------------------- -def _save(im: Image.Image, fp: IO[bytes], tile: list[_Tile], bufsize: int = 0) -> None: +def _save(im, fp, tile, bufsize=0) -> None: """Helper to save image based on tile list :param im: Image object. @@ -666,14 +553,7 @@ def _save(im: Image.Image, fp: IO[bytes], tile: list[_Tile], bufsize: int = 0) - fp.flush() -def _encode_tile( - im: Image.Image, - fp: IO[bytes], - tile: list[_Tile], - bufsize: int, - fh: int | None, - exc: BaseException | None = None, -) -> None: +def _encode_tile(im, fp, tile: list[_Tile], bufsize, fh, exc=None): for encoder_name, extents, offset, args in tile: if offset > 0: fp.seek(offset) @@ -693,7 +573,6 @@ def _encode_tile( break else: # slight speedup: compress to real file object - assert fh is not None errcode = encoder.encode_to_file(fh, bufsize) if errcode < 0: raise _get_oserror(errcode, encoder=True) from exc @@ -701,7 +580,7 @@ def _encode_tile( encoder.cleanup() -def _safe_read(fp: IO[bytes], size: int) -> bytes: +def _safe_read(fp, size): """ Reads large blocks in a safe way. Unlike fp.read(n), this function doesn't trust the user. If the requested size is larger than @@ -722,18 +601,18 @@ def _safe_read(fp: IO[bytes], size: int) -> bytes: msg = "Truncated File Read" raise OSError(msg) return data - blocks: list[bytes] = [] + data = [] remaining_size = size while remaining_size > 0: block = fp.read(min(remaining_size, SAFEBLOCK)) if not block: break - blocks.append(block) + data.append(block) remaining_size -= len(block) - if sum(len(block) for block in blocks) < size: + if sum(len(d) for d in data) < size: msg = "Truncated File Read" raise OSError(msg) - return b"".join(blocks) + return b"".join(data) class PyCodecState: @@ -750,18 +629,18 @@ class PyCodecState: class PyCodec: fd: IO[bytes] | None - def __init__(self, mode: str, *args: Any) -> None: - self.im: Image.core.ImagingCore | None = None + def __init__(self, mode, *args): + self.im = None self.state = PyCodecState() self.fd = None self.mode = mode self.init(args) - def init(self, args: tuple[Any, ...]) -> None: + def init(self, args): """ Override to perform codec specific initialization - :param args: Tuple of arg items from the tile entry + :param args: Array of args items from the tile entry :returns: None """ self.args = args @@ -774,7 +653,7 @@ class PyCodec: """ pass - def setfd(self, fd: IO[bytes]) -> None: + def setfd(self, fd): """ Called from ImageFile to set the Python file-like object @@ -783,11 +662,7 @@ class PyCodec: """ self.fd = fd - def setimage( - self, - im: Image.core.ImagingCore, - extents: tuple[int, int, int, int] | None = None, - ) -> None: + def setimage(self, im, extents: tuple[int, int, int, int] | None = None) -> None: """ Called from ImageFile to set the core output image for the codec @@ -839,7 +714,7 @@ class PyDecoder(PyCodec): def pulls_fd(self) -> bool: return self._pulls_fd - def decode(self, buffer: bytes | Image.SupportsArrayInterface) -> tuple[int, int]: + def decode(self, buffer: bytes) -> tuple[int, int]: """ Override to perform the decoding process. @@ -851,22 +726,19 @@ class PyDecoder(PyCodec): msg = "unavailable in base decoder" raise NotImplementedError(msg) - def set_as_raw( - self, data: bytes, rawmode: str | None = None, extra: tuple[Any, ...] = () - ) -> None: + def set_as_raw(self, data: bytes, rawmode=None) -> None: """ Convenience method to set the internal image from a stream of raw data :param data: Bytes to be set :param rawmode: The rawmode to be used for the decoder. If not specified, it will default to the mode of the image - :param extra: Extra arguments for the decoder. :returns: None """ if not rawmode: rawmode = self.mode - d = Image._getdecoder(self.mode, "raw", rawmode, extra) + d = Image._getdecoder(self.mode, "raw", rawmode) assert self.im is not None d.setimage(self.im, self.state.extents()) s = d.decode(data) @@ -921,7 +793,7 @@ class PyEncoder(PyCodec): self.fd.write(data) return bytes_consumed, errcode - def encode_to_file(self, fh: int, bufsize: int) -> int: + def encode_to_file(self, fh, bufsize): """ :param fh: File handle. :param bufsize: Buffer size. @@ -934,5 +806,5 @@ class PyEncoder(PyCodec): while errcode == 0: status, errcode, buf = self.encode(bufsize) if status > 0: - os.write(fh, buf[status:]) + fh.write(buf[status:]) return errcode diff --git a/venv/Lib/site-packages/PIL/ImageFilter.py b/venv/Lib/site-packages/PIL/ImageFilter.py index 9326eee..e18b4a4 100644 --- a/venv/Lib/site-packages/PIL/ImageFilter.py +++ b/venv/Lib/site-packages/PIL/ImageFilter.py @@ -18,20 +18,15 @@ from __future__ import annotations import abc import functools -from collections.abc import Sequence -from typing import cast +from types import ModuleType +from typing import TYPE_CHECKING, Any, Callable, Sequence, cast -TYPE_CHECKING = False if TYPE_CHECKING: - from collections.abc import Callable - from types import ModuleType - from typing import Any - from . import _imaging from ._typing import NumpyArray -class Filter(abc.ABC): +class Filter: @abc.abstractmethod def filter(self, image: _imaging.ImagingCore) -> _imaging.ImagingCore: pass @@ -557,7 +552,7 @@ class Color3DLUT(MultibandFilter): ch_out = channels or ch_in size_1d, size_2d, size_3d = self.size - table: list[float] = [0] * (size_1d * size_2d * size_3d * ch_out) + table = [0] * (size_1d * size_2d * size_3d * ch_out) idx_in = 0 idx_out = 0 for b in range(size_3d): @@ -602,6 +597,8 @@ class Color3DLUT(MultibandFilter): self.mode or image.mode, Image.Resampling.BILINEAR, self.channels, - self.size, + self.size[0], + self.size[1], + self.size[2], self.table, ) diff --git a/venv/Lib/site-packages/PIL/ImageFont.py b/venv/Lib/site-packages/PIL/ImageFont.py index d11f7bf..d260eef 100644 --- a/venv/Lib/site-packages/PIL/ImageFont.py +++ b/venv/Lib/site-packages/PIL/ImageFont.py @@ -34,26 +34,18 @@ import warnings from enum import IntEnum from io import BytesIO from types import ModuleType -from typing import IO, Any, BinaryIO, TypedDict, cast +from typing import IO, TYPE_CHECKING, Any, BinaryIO from . import Image from ._typing import StrOrBytesPath from ._util import DeferredError, is_path -TYPE_CHECKING = False if TYPE_CHECKING: from . import ImageFile from ._imaging import ImagingFont from ._imagingft import Font -class Axis(TypedDict): - minimum: int | None - default: int | None - maximum: int | None - name: bytes | None - - class Layout(IntEnum): BASIC = 0 RAQM = 1 @@ -99,13 +91,11 @@ class ImageFont: def _load_pilfont(self, filename: str) -> None: with open(filename, "rb") as fp: image: ImageFile.ImageFile | None = None - root = os.path.splitext(filename)[0] - for ext in (".png", ".gif", ".pbm"): if image: image.close() try: - fullname = root + ext + fullname = os.path.splitext(filename)[0] + ext image = Image.open(fullname) except Exception: pass @@ -115,8 +105,7 @@ class ImageFont: else: if image: image.close() - - msg = f"cannot find glyph data file {root}.{{gif|pbm|png}}" + msg = "cannot find glyph data file" raise OSError(msg) self.file = fullname @@ -125,20 +114,11 @@ class ImageFont: image.close() def _load_pilfont_data(self, file: IO[bytes], image: Image.Image) -> None: - # check image - if image.mode not in ("1", "L"): - image.close() - - msg = "invalid font image mode" - raise TypeError(msg) - # read PILfont header - if file.read(8) != b"PILfont\n": - image.close() - + if file.readline() != b"PILfont\n": msg = "Not a PILfont file" raise SyntaxError(msg) - file.readline() + file.readline().split(b";") self.info = [] # FIXME: should be a dictionary while True: s = file.readline() @@ -149,13 +129,16 @@ class ImageFont: # read PILfont metrics data = file.read(256 * 20) + # check image + if image.mode not in ("1", "L"): + msg = "invalid font image mode" + raise TypeError(msg) + image.load() self.font = Image.core.font(image.im, data) - def getmask( - self, text: str | bytes, mode: str = "", *args: Any, **kwargs: Any - ) -> Image.core.ImagingCore: + def getmask(self, text, mode="", *args, **kwargs): """ Create a bitmap for the text. @@ -220,7 +203,7 @@ class FreeTypeFont: def __init__( self, - font: StrOrBytesPath | BinaryIO, + font: StrOrBytesPath | BinaryIO | None = None, size: float = 10, index: int = 0, encoding: str = "", @@ -232,7 +215,7 @@ class FreeTypeFont: raise core.ex if size <= 0: - msg = f"font size must be greater than 0, not {size}" + msg = "font size must be greater than 0" raise ValueError(msg) self.path = font @@ -253,14 +236,14 @@ class FreeTypeFont: self.layout_engine = layout_engine - def load_from_bytes(f: IO[bytes]) -> None: + def load_from_bytes(f): self.font_bytes = f.read() self.font = core.getfont( "", size, index, encoding, self.font_bytes, layout_engine ) if is_path(font): - font = os.fspath(font) + font = os.path.realpath(os.fspath(font)) if sys.platform == "win32": font_bytes_path = font if isinstance(font, bytes) else font.encode() try: @@ -275,14 +258,14 @@ class FreeTypeFont: font, size, index, encoding, layout_engine=layout_engine ) else: - load_from_bytes(cast(IO[bytes], font)) + load_from_bytes(font) - def __getstate__(self) -> list[Any]: + def __getstate__(self): return [self.path, self.size, self.index, self.encoding, self.layout_engine] - def __setstate__(self, state: list[Any]) -> None: + def __setstate__(self, state): path, size, index, encoding, layout_engine = state - FreeTypeFont.__init__(self, path, size, index, encoding, layout_engine) + self.__init__(path, size, index, encoding, layout_engine) def getname(self) -> tuple[str | None, str | None]: """ @@ -300,12 +283,7 @@ class FreeTypeFont: return self.font.ascent, self.font.descent def getlength( - self, - text: str | bytes, - mode: str = "", - direction: str | None = None, - features: list[str] | None = None, - language: str | None = None, + self, text: str | bytes, mode="", direction=None, features=None, language=None ) -> float: """ Returns length (in pixels with 1/64 precision) of given text when rendered @@ -446,16 +424,16 @@ class FreeTypeFont: def getmask( self, - text: str | bytes, - mode: str = "", - direction: str | None = None, - features: list[str] | None = None, - language: str | None = None, - stroke_width: float = 0, - anchor: str | None = None, - ink: int = 0, - start: tuple[float, float] | None = None, - ) -> Image.core.ImagingCore: + text, + mode="", + direction=None, + features=None, + language=None, + stroke_width=0, + anchor=None, + ink=0, + start=None, + ): """ Create a bitmap for the text. @@ -538,17 +516,17 @@ class FreeTypeFont: def getmask2( self, text: str | bytes, - mode: str = "", - direction: str | None = None, - features: list[str] | None = None, - language: str | None = None, - stroke_width: float = 0, - anchor: str | None = None, - ink: int = 0, - start: tuple[float, float] | None = None, - *args: Any, - **kwargs: Any, - ) -> tuple[Image.core.ImagingCore, tuple[int, int]]: + mode="", + direction=None, + features=None, + language=None, + stroke_width=0, + anchor=None, + ink=0, + start=None, + *args, + **kwargs, + ): """ Create a bitmap for the text. @@ -621,7 +599,7 @@ class FreeTypeFont: if start is None: start = (0, 0) - def fill(width: int, height: int) -> Image.core.ImagingCore: + def fill(width, height): size = (width, height) Image._decompression_bomb_check(size) return Image.core.fill("RGBA" if mode == "RGBA" else "L", size) @@ -634,20 +612,15 @@ class FreeTypeFont: features, language, stroke_width, - kwargs.get("stroke_filled", False), anchor, ink, - start, + start[0], + start[1], ) def font_variant( - self, - font: StrOrBytesPath | BinaryIO | None = None, - size: float | None = None, - index: int | None = None, - encoding: str | None = None, - layout_engine: Layout | None = None, - ) -> FreeTypeFont: + self, font=None, size=None, index=None, encoding=None, layout_engine=None + ): """ Create a copy of this FreeTypeFont object, using any specified arguments to override the settings. @@ -675,14 +648,14 @@ class FreeTypeFont: :returns: A list of the named styles in a variation font. :exception OSError: If the font is not a variation font. """ - names = [] - for name in self.font.getvarnames(): - name = name.replace(b"\x00", b"") - if name not in names: - names.append(name) - return names + try: + names = self.font.getvarnames() + except AttributeError as e: + msg = "FreeType 2.9.1 or greater is required" + raise NotImplementedError(msg) from e + return [name.replace(b"\x00", b"") for name in names] - def set_variation_by_name(self, name: str | bytes) -> None: + def set_variation_by_name(self, name): """ :param name: The name of the style. :exception OSError: If the font is not a variation font. @@ -701,12 +674,16 @@ class FreeTypeFont: self.font.setvarname(index) - def get_variation_axes(self) -> list[Axis]: + def get_variation_axes(self): """ :returns: A list of the axes in a variation font. :exception OSError: If the font is not a variation font. """ - axes = self.font.getvaraxes() + try: + axes = self.font.getvaraxes() + except AttributeError as e: + msg = "FreeType 2.9.1 or greater is required" + raise NotImplementedError(msg) from e for axis in axes: if axis["name"]: axis["name"] = axis["name"].replace(b"\x00", b"") @@ -717,15 +694,17 @@ class FreeTypeFont: :param axes: A list of values for each axis. :exception OSError: If the font is not a variation font. """ - self.font.setvaraxes(axes) + try: + self.font.setvaraxes(axes) + except AttributeError as e: + msg = "FreeType 2.9.1 or greater is required" + raise NotImplementedError(msg) from e class TransposedFont: """Wrapper for writing rotated or mirrored text""" - def __init__( - self, font: ImageFont | FreeTypeFont, orientation: Image.Transpose | None = None - ): + def __init__(self, font, orientation=None): """ Wrapper that creates a transposed font from any existing font object. @@ -739,17 +718,13 @@ class TransposedFont: self.font = font self.orientation = orientation # any 'transpose' argument, or None - def getmask( - self, text: str | bytes, mode: str = "", *args: Any, **kwargs: Any - ) -> Image.core.ImagingCore: + def getmask(self, text, mode="", *args, **kwargs): im = self.font.getmask(text, mode, *args, **kwargs) if self.orientation is not None: return im.transpose(self.orientation) return im - def getbbox( - self, text: str | bytes, *args: Any, **kwargs: Any - ) -> tuple[int, int, float, float]: + def getbbox(self, text, *args, **kwargs): # TransposedFont doesn't support getmask2, move top-left point to (0, 0) # this has no effect on ImageFont and simulates anchor="lt" for FreeTypeFont left, top, right, bottom = self.font.getbbox(text, *args, **kwargs) @@ -759,7 +734,7 @@ class TransposedFont: return 0, 0, height, width return 0, 0, width, height - def getlength(self, text: str | bytes, *args: Any, **kwargs: Any) -> float: + def getlength(self, text: str | bytes, *args, **kwargs) -> float: if self.orientation in (Image.Transpose.ROTATE_90, Image.Transpose.ROTATE_270): msg = "text length is undefined for text rotated by 90 or 270 degrees" raise ValueError(msg) @@ -768,9 +743,8 @@ class TransposedFont: def load(filename: str) -> ImageFont: """ - Load a font file. This function loads a font object from the given - bitmap font file, and returns the corresponding font object. For loading TrueType - or OpenType fonts instead, see :py:func:`~PIL.ImageFont.truetype`. + Load a font file. This function loads a font object from the given + bitmap font file, and returns the corresponding font object. :param filename: Name of font file. :return: A font object. @@ -782,7 +756,7 @@ def load(filename: str) -> ImageFont: def truetype( - font: StrOrBytesPath | BinaryIO, + font: StrOrBytesPath | BinaryIO | None = None, size: float = 10, index: int = 0, encoding: str = "", @@ -790,10 +764,9 @@ def truetype( ) -> FreeTypeFont: """ Load a TrueType or OpenType font from a file or file-like object, - and create a font object. This function loads a font object from the given - file or file-like object, and creates a font object for a font of the given - size. For loading bitmap fonts instead, see :py:func:`~PIL.ImageFont.load` - and :py:func:`~PIL.ImageFont.load_path`. + and create a font object. + This function loads a font object from the given file or file-like + object, and creates a font object for a font of the given size. Pillow uses FreeType to open font files. On Windows, be aware that FreeType will keep the file open as long as the FreeTypeFont object exists. Windows @@ -854,7 +827,7 @@ def truetype( :exception ValueError: If the font size is not greater than zero. """ - def freetype(font: StrOrBytesPath | BinaryIO) -> FreeTypeFont: + def freetype(font: StrOrBytesPath | BinaryIO | None) -> FreeTypeFont: return FreeTypeFont(font, size, index, encoding, layout_engine) try: @@ -929,10 +902,7 @@ def load_path(filename: str | bytes) -> ImageFont: return load(os.path.join(directory, filename)) except OSError: pass - msg = f'cannot find font file "{filename}" in sys.path' - if os.path.exists(filename): - msg += f', did you mean ImageFont.load("{filename}") instead?' - + msg = "cannot find font file" raise OSError(msg) @@ -1074,7 +1044,7 @@ w7IkEbzhVQAAAABJRU5ErkJggg== def load_default(size: float | None = None) -> FreeTypeFont | ImageFont: """If FreeType support is available, load a version of Aileron Regular, - https://dotcolon.net/fonts/aileron, with a more limited character set. + https://dotcolon.net/font/aileron, with a more limited character set. Otherwise, load a "better than nothing" font. diff --git a/venv/Lib/site-packages/PIL/ImageGrab.py b/venv/Lib/site-packages/PIL/ImageGrab.py index 4228078..e27ca7e 100644 --- a/venv/Lib/site-packages/PIL/ImageGrab.py +++ b/venv/Lib/site-packages/PIL/ImageGrab.py @@ -25,17 +25,12 @@ import tempfile from . import Image -TYPE_CHECKING = False -if TYPE_CHECKING: - from . import ImageWin - def grab( bbox: tuple[int, int, int, int] | None = None, include_layered_windows: bool = False, all_screens: bool = False, xdisplay: str | None = None, - window: int | ImageWin.HWND | None = None, ) -> Image.Image: im: Image.Image if xdisplay is None: @@ -43,9 +38,7 @@ def grab( fh, filepath = tempfile.mkstemp(".png") os.close(fh) args = ["screencapture"] - if window: - args += ["-l", str(window)] - elif bbox: + if bbox: left, top, right, bottom = bbox args += ["-R", f"{left},{top},{right-left},{bottom-top}"] subprocess.call(args + ["-x", filepath]) @@ -53,43 +46,13 @@ def grab( im.load() os.unlink(filepath) if bbox: - if window: - # Determine if the window was in Retina mode or not - # by capturing it without the shadow, - # and checking how different the width is - fh, filepath = tempfile.mkstemp(".png") - os.close(fh) - subprocess.call( - ["screencapture", "-l", str(window), "-o", "-x", filepath] - ) - with Image.open(filepath) as im_no_shadow: - retina = im.width - im_no_shadow.width > 100 - os.unlink(filepath) - - # Since screencapture's -R does not work with -l, - # crop the image manually - if retina: - left, top, right, bottom = bbox - im_cropped = im.resize( - (right - left, bottom - top), - box=tuple(coord * 2 for coord in bbox), - ) - else: - im_cropped = im.crop(bbox) - im.close() - return im_cropped - else: - im_resized = im.resize((right - left, bottom - top)) - im.close() - return im_resized + im_resized = im.resize((right - left, bottom - top)) + im.close() + return im_resized return im elif sys.platform == "win32": - if window is not None: - all_screens = -1 offset, size, data = Image.core.grabscreen_win32( - include_layered_windows, - all_screens, - int(window) if window is not None else 0, + include_layered_windows, all_screens ) im = Image.frombytes( "RGB", @@ -114,18 +77,14 @@ def grab( raise OSError(msg) size, data = Image.core.grabscreen_x11(display_name) except OSError: - if display_name is None and sys.platform not in ("darwin", "win32"): - if shutil.which("gnome-screenshot"): - args = ["gnome-screenshot", "-f"] - elif shutil.which("grim"): - args = ["grim"] - elif shutil.which("spectacle"): - args = ["spectacle", "-n", "-b", "-f", "-o"] - else: - raise + if ( + display_name is None + and sys.platform not in ("darwin", "win32") + and shutil.which("gnome-screenshot") + ): fh, filepath = tempfile.mkstemp(".png") os.close(fh) - subprocess.call(args + [filepath]) + subprocess.call(["gnome-screenshot", "-f", filepath]) im = Image.open(filepath) im.load() os.unlink(filepath) @@ -145,27 +104,38 @@ def grab( def grabclipboard() -> Image.Image | list[str] | None: if sys.platform == "darwin": - p = subprocess.run( - ["osascript", "-e", "get the clipboard as «class PNGf»"], - capture_output=True, - ) - if p.returncode != 0: - return None + fh, filepath = tempfile.mkstemp(".png") + os.close(fh) + commands = [ + 'set theFile to (open for access POSIX file "' + + filepath + + '" with write permission)', + "try", + " write (the clipboard as «class PNGf») to theFile", + "end try", + "close access theFile", + ] + script = ["osascript"] + for command in commands: + script += ["-e", command] + subprocess.call(script) - import binascii - - data = io.BytesIO(binascii.unhexlify(p.stdout[11:-3])) - return Image.open(data) + im = None + if os.stat(filepath).st_size != 0: + im = Image.open(filepath) + im.load() + os.unlink(filepath) + return im elif sys.platform == "win32": fmt, data = Image.core.grabclipboard_win32() if fmt == "file": # CF_HDROP import struct o = struct.unpack_from("I", data)[0] - if data[16] == 0: - files = data[o:].decode("mbcs").split("\0") - else: + if data[16] != 0: files = data[o:].decode("utf-16le").split("\0") + else: + files = data[o:].decode("mbcs").split("\0") return files[: files.index("")] if isinstance(data, bytes): data = io.BytesIO(data) diff --git a/venv/Lib/site-packages/PIL/ImageMath.py b/venv/Lib/site-packages/PIL/ImageMath.py index dfdc50c..6664434 100644 --- a/venv/Lib/site-packages/PIL/ImageMath.py +++ b/venv/Lib/site-packages/PIL/ImageMath.py @@ -17,14 +17,11 @@ from __future__ import annotations import builtins +from types import CodeType +from typing import Any, Callable from . import Image, _imagingmath - -TYPE_CHECKING = False -if TYPE_CHECKING: - from collections.abc import Callable - from types import CodeType - from typing import Any +from ._deprecate import deprecate class _Operand: @@ -62,12 +59,13 @@ class _Operand: if im2 is None: # unary operation out = Image.new(mode or im_1.mode, im_1.size, None) + im_1.load() try: op = getattr(_imagingmath, f"{op}_{im_1.mode}") except AttributeError as e: msg = f"bad operand type for '{op}'" raise TypeError(msg) from e - _imagingmath.unop(op, out.getim(), im_1.getim()) + _imagingmath.unop(op, out.im.id, im_1.im.id) else: # binary operation im_2 = self.__fixup(im2) @@ -88,12 +86,14 @@ class _Operand: if im_2.size != size: im_2 = im_2.crop((0, 0) + size) out = Image.new(mode or im_1.mode, im_1.size, None) + im_1.load() + im_2.load() try: op = getattr(_imagingmath, f"{op}_{im_1.mode}") except AttributeError as e: msg = f"bad operand type for '{op}'" raise TypeError(msg) from e - _imagingmath.binop(op, out.getim(), im_1.getim(), im_2.getim()) + _imagingmath.binop(op, out.im.id, im_1.im.id, im_2.im.id) return _Operand(out) # unary operators @@ -176,10 +176,10 @@ class _Operand: return self.apply("rshift", self, other) # logical - def __eq__(self, other: _Operand | float) -> _Operand: # type: ignore[override] + def __eq__(self, other): return self.apply("eq", self, other) - def __ne__(self, other: _Operand | float) -> _Operand: # type: ignore[override] + def __ne__(self, other): return self.apply("ne", self, other) def __lt__(self, other: _Operand | float) -> _Operand: @@ -236,7 +236,11 @@ ops = { } -def lambda_eval(expression: Callable[[dict[str, Any]], Any], **kw: Any) -> Any: +def lambda_eval( + expression: Callable[[dict[str, Any]], Any], + options: dict[str, Any] = {}, + **kw: Any, +) -> Any: """ Returns the result of an image function. @@ -245,16 +249,19 @@ def lambda_eval(expression: Callable[[dict[str, Any]], Any], **kw: Any) -> Any: :py:func:`~PIL.Image.merge` function. :param expression: A function that receives a dictionary. - :param **kw: Values to add to the function's dictionary. + :param options: Values to add to the function's dictionary. You + can either use a dictionary, or one or more keyword + arguments. :return: The expression result. This is usually an image object, but can also be an integer, a floating point value, or a pixel tuple, depending on the expression. """ args: dict[str, Any] = ops.copy() + args.update(options) args.update(kw) for k, v in args.items(): - if isinstance(v, Image.Image): + if hasattr(v, "im"): args[k] = _Operand(v) out = expression(args) @@ -264,7 +271,11 @@ def lambda_eval(expression: Callable[[dict[str, Any]], Any], **kw: Any) -> Any: return out -def unsafe_eval(expression: str, **kw: Any) -> Any: +def unsafe_eval( + expression: str, + options: dict[str, Any] = {}, + **kw: Any, +) -> Any: """ Evaluates an image expression. This uses Python's ``eval()`` function to process the expression string, and carries the security risks of doing so. It is not @@ -276,7 +287,9 @@ def unsafe_eval(expression: str, **kw: Any) -> Any: :py:func:`~PIL.Image.merge` function. :param expression: A string containing a Python-style expression. - :param **kw: Values to add to the evaluation context. + :param options: Values to add to the evaluation context. You + can either use a dictionary, or one or more keyword + arguments. :return: The evaluated expression. This is usually an image object, but can also be an integer, a floating point value, or a pixel tuple, depending on the expression. @@ -284,14 +297,15 @@ def unsafe_eval(expression: str, **kw: Any) -> Any: # build execution namespace args: dict[str, Any] = ops.copy() - for k in kw: + for k in list(options.keys()) + list(kw.keys()): if "__" in k or hasattr(builtins, k): msg = f"'{k}' not allowed" raise ValueError(msg) + args.update(options) args.update(kw) for k, v in args.items(): - if isinstance(v, Image.Image): + if hasattr(v, "im"): args[k] = _Operand(v) compiled_code = compile(expression, "", "eval") @@ -312,3 +326,32 @@ def unsafe_eval(expression: str, **kw: Any) -> Any: return out.im except AttributeError: return out + + +def eval( + expression: str, + _dict: dict[str, Any] = {}, + **kw: Any, +) -> Any: + """ + Evaluates an image expression. + + Deprecated. Use lambda_eval() or unsafe_eval() instead. + + :param expression: A string containing a Python-style expression. + :param _dict: Values to add to the evaluation context. You + can either use a dictionary, or one or more keyword + arguments. + :return: The evaluated expression. This is usually an image object, but can + also be an integer, a floating point value, or a pixel tuple, + depending on the expression. + + .. deprecated:: 10.3.0 + """ + + deprecate( + "ImageMath.eval", + 12, + "ImageMath.lambda_eval or ImageMath.unsafe_eval", + ) + return unsafe_eval(expression, _dict, **kw) diff --git a/venv/Lib/site-packages/PIL/ImageMode.py b/venv/Lib/site-packages/PIL/ImageMode.py index b7c6c86..92a08d2 100644 --- a/venv/Lib/site-packages/PIL/ImageMode.py +++ b/venv/Lib/site-packages/PIL/ImageMode.py @@ -18,6 +18,8 @@ import sys from functools import lru_cache from typing import NamedTuple +from ._deprecate import deprecate + class ModeDescriptor(NamedTuple): """Wrapper for mode strings.""" @@ -55,11 +57,16 @@ def getmode(mode: str) -> ModeDescriptor: "HSV": ("RGB", "L", ("H", "S", "V"), "|u1"), # extra experimental modes "RGBa": ("RGB", "L", ("R", "G", "B", "a"), "|u1"), + "BGR;15": ("RGB", "L", ("B", "G", "R"), "|u1"), + "BGR;16": ("RGB", "L", ("B", "G", "R"), "|u1"), + "BGR;24": ("RGB", "L", ("B", "G", "R"), "|u1"), "LA": ("L", "L", ("L", "A"), "|u1"), "La": ("L", "L", ("L", "a"), "|u1"), "PA": ("RGB", "L", ("P", "A"), "|u1"), } if mode in modes: + if mode in ("BGR;15", "BGR;16", "BGR;24"): + deprecate(mode, 12) base_mode, base_type, bands, type_str = modes[mode] return ModeDescriptor(mode, bands, base_mode, base_type, type_str) diff --git a/venv/Lib/site-packages/PIL/ImageMorph.py b/venv/Lib/site-packages/PIL/ImageMorph.py index 9fcd8d7..6a43983 100644 --- a/venv/Lib/site-packages/PIL/ImageMorph.py +++ b/venv/Lib/site-packages/PIL/ImageMorph.py @@ -65,12 +65,10 @@ class LutBuilder: def __init__( self, patterns: list[str] | None = None, op_name: str | None = None ) -> None: - """ - :param patterns: A list of input patterns, or None. - :param op_name: The name of a known pattern. One of "corner", "dilation4", - "dilation8", "erosion4", "erosion8" or "edge". - :exception Exception: If the op_name is not recognized. - """ + if patterns is not None: + self.patterns = patterns + else: + self.patterns = [] self.lut: bytearray | None = None if op_name is not None: known_patterns = { @@ -90,38 +88,20 @@ class LutBuilder: raise Exception(msg) self.patterns = known_patterns[op_name] - elif patterns is not None: - self.patterns = patterns - else: - self.patterns = [] def add_patterns(self, patterns: list[str]) -> None: - """ - Append to list of patterns. - - :param patterns: Additional patterns. - """ self.patterns += patterns - def build_default_lut(self) -> bytearray: - """ - Set the current LUT, and return it. - - This is the default LUT that patterns will be applied against when building. - """ + def build_default_lut(self) -> None: symbols = [0, 1] m = 1 << 4 # pos of current pixel self.lut = bytearray(symbols[(i & m) > 0] for i in range(LUT_SIZE)) - return self.lut def get_lut(self) -> bytearray | None: - """ - Returns the current LUT - """ return self.lut def _string_permute(self, pattern: str, permutation: list[int]) -> str: - """Takes a pattern and a permutation and returns the + """string_permute takes a pattern and a permutation and returns the string permuted according to the permutation list. """ assert len(permutation) == 9 @@ -130,7 +110,7 @@ class LutBuilder: def _pattern_permute( self, basic_pattern: str, options: str, basic_result: int ) -> list[tuple[str, int]]: - """Takes a basic pattern and its result and clones + """pattern_permute takes a basic pattern and its result and clones the pattern according to the modifications described in the $options parameter. It returns a list of all cloned patterns.""" patterns = [(basic_pattern, basic_result)] @@ -160,16 +140,17 @@ class LutBuilder: return patterns def build_lut(self) -> bytearray: - """Compile all patterns into a morphology LUT, and return it. + """Compile all patterns into a morphology lut. - This is the data to be passed into MorphOp.""" + TBD :Build based on (file) morphlut:modify_lut + """ self.build_default_lut() assert self.lut is not None patterns = [] # Parse and create symmetries of the patterns strings for p in self.patterns: - m = re.search(r"(\w):?\s*\((.+?)\)\s*->\s*(\d)", p.replace("\n", "")) + m = re.search(r"(\w*):?\s*\((.+?)\)\s*->\s*(\d)", p.replace("\n", "")) if not m: msg = 'Syntax error in pattern "' + p + '"' raise Exception(msg) @@ -182,14 +163,15 @@ class LutBuilder: patterns += self._pattern_permute(pattern, options, result) - # Compile the patterns into regular expressions for speed + # compile the patterns into regular expressions for speed compiled_patterns = [] for pattern in patterns: p = pattern[0].replace(".", "X").replace("X", "[01]") compiled_patterns.append((re.compile(p), pattern[1])) # Step through table and find patterns that match. - # Note that all the patterns are searched. The last one found takes priority + # Note that all the patterns are searched. The last one + # caught overrides for i in range(LUT_SIZE): # Build the bit pattern bitpattern = bin(i)[2:] @@ -211,82 +193,57 @@ class MorphOp: op_name: str | None = None, patterns: list[str] | None = None, ) -> None: - """Create a binary morphological operator. - - If the LUT is not provided, then it is built using LutBuilder from the op_name - or the patterns. - - :param lut: The LUT data. - :param patterns: A list of input patterns, or None. - :param op_name: The name of a known pattern. One of "corner", "dilation4", - "dilation8", "erosion4", "erosion8", "edge". - :exception Exception: If the op_name is not recognized. - """ - if patterns is None and op_name is None: - self.lut = lut - else: - self.lut = LutBuilder(patterns, op_name).build_lut() + """Create a binary morphological operator""" + self.lut = lut + if op_name is not None: + self.lut = LutBuilder(op_name=op_name).build_lut() + elif patterns is not None: + self.lut = LutBuilder(patterns=patterns).build_lut() def apply(self, image: Image.Image) -> tuple[int, Image.Image]: - """Run a single morphological operation on an image. + """Run a single morphological operation on an image Returns a tuple of the number of changed pixels and the - morphed image. - - :param image: A 1-mode or L-mode image. - :exception Exception: If the current operator is None. - :exception ValueError: If the image is not 1 or L mode.""" + morphed image""" if self.lut is None: msg = "No operator loaded" raise Exception(msg) - if image.mode not in ("1", "L"): - msg = "Image mode must be 1 or L" + if image.mode != "L": + msg = "Image mode must be L" raise ValueError(msg) - outimage = Image.new(image.mode, image.size) - count = _imagingmorph.apply(bytes(self.lut), image.getim(), outimage.getim()) + outimage = Image.new(image.mode, image.size, None) + count = _imagingmorph.apply(bytes(self.lut), image.im.id, outimage.im.id) return count, outimage def match(self, image: Image.Image) -> list[tuple[int, int]]: """Get a list of coordinates matching the morphological operation on an image. - Returns a list of tuples of (x,y) coordinates of all matching pixels. See - :ref:`coordinate-system`. - - :param image: A 1-mode or L-mode image. - :exception Exception: If the current operator is None. - :exception ValueError: If the image is not 1 or L mode.""" + Returns a list of tuples of (x,y) coordinates + of all matching pixels. See :ref:`coordinate-system`.""" if self.lut is None: msg = "No operator loaded" raise Exception(msg) - if image.mode not in ("1", "L"): - msg = "Image mode must be 1 or L" + if image.mode != "L": + msg = "Image mode must be L" raise ValueError(msg) - return _imagingmorph.match(bytes(self.lut), image.getim()) + return _imagingmorph.match(bytes(self.lut), image.im.id) def get_on_pixels(self, image: Image.Image) -> list[tuple[int, int]]: - """Get a list of all turned on pixels in a 1 or L mode image. + """Get a list of all turned on pixels in a binary image - Returns a list of tuples of (x,y) coordinates of all non-empty pixels. See - :ref:`coordinate-system`. + Returns a list of tuples of (x,y) coordinates + of all matching pixels. See :ref:`coordinate-system`.""" - :param image: A 1-mode or L-mode image. - :exception ValueError: If the image is not 1 or L mode.""" - - if image.mode not in ("1", "L"): - msg = "Image mode must be 1 or L" + if image.mode != "L": + msg = "Image mode must be L" raise ValueError(msg) - return _imagingmorph.get_on_pixels(image.getim()) + return _imagingmorph.get_on_pixels(image.im.id) def load_lut(self, filename: str) -> None: - """ - Load an operator from an mrl file - - :param filename: The file to read from. - :exception Exception: If the length of the file data is not 512. - """ + """Load an operator from an mrl file""" with open(filename, "rb") as f: self.lut = bytearray(f.read()) @@ -296,12 +253,7 @@ class MorphOp: raise Exception(msg) def save_lut(self, filename: str) -> None: - """ - Save an operator to an mrl file. - - :param filename: The destination file. - :exception Exception: If the current operator is None. - """ + """Save an operator to an mrl file""" if self.lut is None: msg = "No operator loaded" raise Exception(msg) @@ -309,9 +261,5 @@ class MorphOp: f.write(self.lut) def set_lut(self, lut: bytearray | None) -> None: - """ - Set the LUT from an external source - - :param lut: A new LUT. - """ + """Set the lut from an external source""" self.lut = lut diff --git a/venv/Lib/site-packages/PIL/ImageOps.py b/venv/Lib/site-packages/PIL/ImageOps.py index 42b10bd..a84c083 100644 --- a/venv/Lib/site-packages/PIL/ImageOps.py +++ b/venv/Lib/site-packages/PIL/ImageOps.py @@ -21,8 +21,7 @@ from __future__ import annotations import functools import operator import re -from collections.abc import Sequence -from typing import Literal, Protocol, cast, overload +from typing import Protocol, Sequence, cast from . import ExifTags, Image, ImagePalette @@ -213,14 +212,14 @@ def colorize( blue = [] # Create the low-end values - for i in range(blackpoint): + for i in range(0, blackpoint): red.append(rgb_black[0]) green.append(rgb_black[1]) blue.append(rgb_black[2]) # Create the mapping (2-color) if rgb_mid is None: - range_map = range(whitepoint - blackpoint) + range_map = range(0, whitepoint - blackpoint) for i in range_map: red.append( @@ -235,8 +234,8 @@ def colorize( # Create the mapping (3-color) else: - range_map1 = range(midpoint - blackpoint) - range_map2 = range(whitepoint - midpoint) + range_map1 = range(0, midpoint - blackpoint) + range_map2 = range(0, whitepoint - midpoint) for i in range_map1: red.append( @@ -256,7 +255,7 @@ def colorize( blue.append(rgb_mid[2] + i * (rgb_white[2] - rgb_mid[2]) // len(range_map2)) # Create the high-end values - for i in range(256 - whitepoint): + for i in range(0, 256 - whitepoint): red.append(rgb_white[0]) green.append(rgb_white[1]) blue.append(rgb_white[2]) @@ -362,9 +361,7 @@ def pad( else: out = Image.new(image.mode, size, color) if resized.palette: - palette = resized.getpalette() - if palette is not None: - out.putpalette(palette) + out.putpalette(resized.getpalette()) if resized.width != size[0]: x = round((size[0] - resized.width) * max(0, min(centering[0], 1))) out.paste(resized, (x, 0)) @@ -499,15 +496,14 @@ def expand( height = top + image.size[1] + bottom color = _color(fill, image.mode) if image.palette: - mode = image.palette.mode - palette = ImagePalette.ImagePalette(mode, image.getpalette(mode)) + palette = ImagePalette.ImagePalette(palette=image.getpalette()) if isinstance(color, tuple) and (len(color) == 3 or len(color) == 4): color = palette.getcolor(color) else: palette = None out = Image.new(image.mode, (width, height), color) if palette: - out.putpalette(palette.palette, mode) + out.putpalette(palette.palette) out.paste(image, (left, top)) return out @@ -674,16 +670,6 @@ def solarize(image: Image.Image, threshold: int = 128) -> Image.Image: return _lut(image, lut) -@overload -def exif_transpose(image: Image.Image, *, in_place: Literal[True]) -> None: ... - - -@overload -def exif_transpose( - image: Image.Image, *, in_place: Literal[False] = False -) -> Image.Image: ... - - def exif_transpose(image: Image.Image, *, in_place: bool = False) -> Image.Image | None: """ If an image has an EXIF Orientation tag, other than 1, transpose the image @@ -709,11 +695,11 @@ def exif_transpose(image: Image.Image, *, in_place: bool = False) -> Image.Image 8: Image.Transpose.ROTATE_90, }.get(orientation) if method is not None: + transposed_image = image.transpose(method) if in_place: - image.im = image.im.transpose(method) - image._size = image.im.size - else: - transposed_image = image.transpose(method) + image.im = transposed_image.im + image.pyaccess = None + image._size = transposed_image._size exif_image = image if in_place else transposed_image exif = exif_image.getexif() @@ -730,15 +716,11 @@ def exif_transpose(image: Image.Image, *, in_place: bool = False) -> Image.Image r"([0-9])", ): value = exif_image.info[key] - if isinstance(value, str): - value = re.sub(pattern, "", value) - elif isinstance(value, tuple): - value = tuple( - re.sub(pattern.encode(), b"", v) for v in value - ) - else: - value = re.sub(pattern.encode(), b"", value) - exif_image.info[key] = value + exif_image.info[key] = ( + re.sub(pattern, "", value) + if isinstance(value, str) + else re.sub(pattern.encode(), b"", value) + ) if not in_place: return transposed_image elif not in_place: diff --git a/venv/Lib/site-packages/PIL/ImagePalette.py b/venv/Lib/site-packages/PIL/ImagePalette.py index eae7aea..ed38285 100644 --- a/venv/Lib/site-packages/PIL/ImagePalette.py +++ b/venv/Lib/site-packages/PIL/ImagePalette.py @@ -18,12 +18,10 @@ from __future__ import annotations import array -from collections.abc import Sequence -from typing import IO +from typing import IO, TYPE_CHECKING, Sequence from . import GimpGradientFile, GimpPaletteFile, ImageColor, PaletteFile -TYPE_CHECKING = False if TYPE_CHECKING: from . import Image @@ -118,7 +116,7 @@ class ImagePalette: ) -> int: if not isinstance(self.palette, bytearray): self._palette = bytearray(self.palette) - index = len(self.palette) // len(self.mode) + index = len(self.palette) // 3 special_colors: tuple[int | tuple[int, ...] | None, ...] = () if image: special_colors = ( @@ -168,12 +166,11 @@ class ImagePalette: index = self._new_color_index(image, e) assert isinstance(self._palette, bytearray) self.colors[color] = index - mode_len = len(self.mode) - if index * mode_len < len(self.palette): + if index * 3 < len(self.palette): self._palette = ( - self._palette[: index * mode_len] + self._palette[: index * 3] + bytes(color) - + self._palette[index * mode_len + mode_len :] + + self._palette[index * 3 + 3 :] ) else: self._palette += bytes(color) @@ -210,7 +207,7 @@ class ImagePalette: # Internal -def raw(rawmode: str, data: Sequence[int] | bytes | bytearray) -> ImagePalette: +def raw(rawmode, data: Sequence[int] | bytes | bytearray) -> ImagePalette: palette = ImagePalette() palette.rawmode = rawmode palette.palette = data diff --git a/venv/Lib/site-packages/PIL/ImageQt.py b/venv/Lib/site-packages/PIL/ImageQt.py index af4d074..35a3776 100644 --- a/venv/Lib/site-packages/PIL/ImageQt.py +++ b/venv/Lib/site-packages/PIL/ImageQt.py @@ -19,19 +19,11 @@ from __future__ import annotations import sys from io import BytesIO +from typing import Callable from . import Image from ._util import is_path -TYPE_CHECKING = False -if TYPE_CHECKING: - from collections.abc import Callable - from typing import Any - - from . import ImageFile - - QBuffer: type - qt_version: str | None qt_versions = [ ["6", "PyQt6"], @@ -42,17 +34,17 @@ qt_versions = [ qt_versions.sort(key=lambda version: version[1] in sys.modules, reverse=True) for version, qt_module in qt_versions: try: + QBuffer: type + QIODevice: type + QImage: type + QPixmap: type qRgba: Callable[[int, int, int, int], int] if qt_module == "PyQt6": - from PyQt6.QtCore import QBuffer, QByteArray, QIODevice + from PyQt6.QtCore import QBuffer, QIODevice from PyQt6.QtGui import QImage, QPixmap, qRgba elif qt_module == "PySide6": - from PySide6.QtCore import ( # type: ignore[assignment] - QBuffer, - QByteArray, - QIODevice, - ) - from PySide6.QtGui import QImage, QPixmap, qRgba # type: ignore[assignment] + from PySide6.QtCore import QBuffer, QIODevice + from PySide6.QtGui import QImage, QPixmap, qRgba except (ImportError, RuntimeError): continue qt_is_installed = True @@ -63,27 +55,26 @@ else: qt_version = None -def rgb(r: int, g: int, b: int, a: int = 255) -> int: +def rgb(r, g, b, a=255): """(Internal) Turns an RGB color into a Qt compatible color integer.""" # use qRgb to pack the colors, and then turn the resulting long # into a negative integer with the same bitpattern. return qRgba(r, g, b, a) & 0xFFFFFFFF -def fromqimage(im: QImage | QPixmap) -> ImageFile.ImageFile: +def fromqimage(im): """ :param im: QImage or PIL ImageQt object """ buffer = QBuffer() - qt_openmode: object if qt_version == "6": try: - qt_openmode = getattr(QIODevice, "OpenModeFlag") + qt_openmode = QIODevice.OpenModeFlag except AttributeError: - qt_openmode = getattr(QIODevice, "OpenMode") + qt_openmode = QIODevice.OpenMode else: qt_openmode = QIODevice - buffer.open(getattr(qt_openmode, "ReadWrite")) + buffer.open(qt_openmode.ReadWrite) # preserve alpha channel with png # otherwise ppm is more friendly with Image.open if im.hasAlphaChannel(): @@ -99,11 +90,11 @@ def fromqimage(im: QImage | QPixmap) -> ImageFile.ImageFile: return Image.open(b) -def fromqpixmap(im: QPixmap) -> ImageFile.ImageFile: +def fromqpixmap(im): return fromqimage(im) -def align8to32(bytes: bytes, width: int, mode: str) -> bytes: +def align8to32(bytes, width, mode): """ converts each scanline of data from 8 bit to 32 bit aligned """ @@ -129,7 +120,7 @@ def align8to32(bytes: bytes, width: int, mode: str) -> bytes: return b"".join(new_data) -def _toqclass_helper(im: Image.Image | str | QByteArray) -> dict[str, Any]: +def _toqclass_helper(im): data = None colortable = None exclusive_fp = False @@ -141,32 +132,30 @@ def _toqclass_helper(im: Image.Image | str | QByteArray) -> dict[str, Any]: if is_path(im): im = Image.open(im) exclusive_fp = True - assert isinstance(im, Image.Image) - qt_format = getattr(QImage, "Format") if qt_version == "6" else QImage + qt_format = QImage.Format if qt_version == "6" else QImage if im.mode == "1": - format = getattr(qt_format, "Format_Mono") + format = qt_format.Format_Mono elif im.mode == "L": - format = getattr(qt_format, "Format_Indexed8") + format = qt_format.Format_Indexed8 colortable = [rgb(i, i, i) for i in range(256)] elif im.mode == "P": - format = getattr(qt_format, "Format_Indexed8") + format = qt_format.Format_Indexed8 palette = im.getpalette() - assert palette is not None colortable = [rgb(*palette[i : i + 3]) for i in range(0, len(palette), 3)] elif im.mode == "RGB": # Populate the 4th channel with 255 im = im.convert("RGBA") data = im.tobytes("raw", "BGRA") - format = getattr(qt_format, "Format_RGB32") + format = qt_format.Format_RGB32 elif im.mode == "RGBA": data = im.tobytes("raw", "BGRA") - format = getattr(qt_format, "Format_ARGB32") + format = qt_format.Format_ARGB32 elif im.mode == "I;16": im = im.point(lambda i: i * 256) - format = getattr(qt_format, "Format_Grayscale16") + format = qt_format.Format_Grayscale16 else: if exclusive_fp: im.close() @@ -183,7 +172,7 @@ def _toqclass_helper(im: Image.Image | str | QByteArray) -> dict[str, Any]: if qt_is_installed: class ImageQt(QImage): - def __init__(self, im: Image.Image | str | QByteArray) -> None: + def __init__(self, im): """ An PIL image wrapper for Qt. This is a subclass of PyQt's QImage class. @@ -207,13 +196,10 @@ if qt_is_installed: self.setColorTable(im_data["colortable"]) -def toqimage(im: Image.Image | str | QByteArray) -> ImageQt: +def toqimage(im) -> ImageQt: return ImageQt(im) -def toqpixmap(im: Image.Image | str | QByteArray) -> QPixmap: +def toqpixmap(im): qimage = toqimage(im) - pixmap = getattr(QPixmap, "fromImage")(qimage) - if qt_version == "6": - pixmap.detach() - return pixmap + return QPixmap.fromImage(qimage) diff --git a/venv/Lib/site-packages/PIL/ImageSequence.py b/venv/Lib/site-packages/PIL/ImageSequence.py index 361be48..2c18502 100644 --- a/venv/Lib/site-packages/PIL/ImageSequence.py +++ b/venv/Lib/site-packages/PIL/ImageSequence.py @@ -16,11 +16,9 @@ ## from __future__ import annotations -from . import Image +from typing import Callable -TYPE_CHECKING = False -if TYPE_CHECKING: - from collections.abc import Callable +from . import Image class Iterator: @@ -35,7 +33,7 @@ class Iterator: :param im: An image object. """ - def __init__(self, im: Image.Image) -> None: + def __init__(self, im: Image.Image): if not hasattr(im, "seek"): msg = "im must have seek method" raise AttributeError(msg) diff --git a/venv/Lib/site-packages/PIL/ImageShow.py b/venv/Lib/site-packages/PIL/ImageShow.py index 7705608..037d6f4 100644 --- a/venv/Lib/site-packages/PIL/ImageShow.py +++ b/venv/Lib/site-packages/PIL/ImageShow.py @@ -26,7 +26,7 @@ from . import Image _viewers = [] -def register(viewer: type[Viewer] | Viewer, order: int = 1) -> None: +def register(viewer, order: int = 1) -> None: """ The :py:func:`register` function is used to register additional viewers:: @@ -40,8 +40,11 @@ def register(viewer: type[Viewer] | Viewer, order: int = 1) -> None: Zero or a negative integer to prepend this viewer to the list, a positive integer to append it. """ - if isinstance(viewer, type) and issubclass(viewer, Viewer): - viewer = viewer() + try: + if issubclass(viewer, Viewer): + viewer = viewer() + except TypeError: + pass # raised if viewer wasn't a class if order > 0: _viewers.append(viewer) else: @@ -175,9 +178,7 @@ class MacViewer(Viewer): if not os.path.exists(path): raise FileNotFoundError subprocess.call(["open", "-a", "Preview.app", path]) - - pyinstaller = getattr(sys, "frozen", False) and hasattr(sys, "_MEIPASS") - executable = (not pyinstaller and sys.executable) or shutil.which("python3") + executable = sys.executable or shutil.which("python3") if executable: subprocess.Popen( [ @@ -194,7 +195,7 @@ if sys.platform == "darwin": register(MacViewer) -class UnixViewer(abc.ABC, Viewer): +class UnixViewer(Viewer): format = "PNG" options = {"compress_level": 1, "save_all": True} diff --git a/venv/Lib/site-packages/PIL/ImageStat.py b/venv/Lib/site-packages/PIL/ImageStat.py index 3a1044b..8bc5045 100644 --- a/venv/Lib/site-packages/PIL/ImageStat.py +++ b/venv/Lib/site-packages/PIL/ImageStat.py @@ -120,7 +120,7 @@ class Stat: @cached_property def mean(self) -> list[float]: """Average (arithmetic mean) pixel level for each band in the image.""" - return [self.sum[i] / self.count[i] if self.count[i] else 0 for i in self.bands] + return [self.sum[i] / self.count[i] for i in self.bands] @cached_property def median(self) -> list[int]: @@ -141,20 +141,13 @@ class Stat: @cached_property def rms(self) -> list[float]: """RMS (root-mean-square) for each band in the image.""" - return [ - math.sqrt(self.sum2[i] / self.count[i]) if self.count[i] else 0 - for i in self.bands - ] + return [math.sqrt(self.sum2[i] / self.count[i]) for i in self.bands] @cached_property def var(self) -> list[float]: """Variance for each band in the image.""" return [ - ( - (self.sum2[i] - (self.sum[i] ** 2.0) / self.count[i]) / self.count[i] - if self.count[i] - else 0 - ) + (self.sum2[i] - (self.sum[i] ** 2.0) / self.count[i]) / self.count[i] for i in self.bands ] diff --git a/venv/Lib/site-packages/PIL/ImageText.py b/venv/Lib/site-packages/PIL/ImageText.py deleted file mode 100644 index e6ccd82..0000000 --- a/venv/Lib/site-packages/PIL/ImageText.py +++ /dev/null @@ -1,320 +0,0 @@ -from __future__ import annotations - -from . import ImageFont -from ._typing import _Ink - - -class Text: - def __init__( - self, - text: str | bytes, - font: ( - ImageFont.ImageFont - | ImageFont.FreeTypeFont - | ImageFont.TransposedFont - | None - ) = None, - mode: str = "RGB", - spacing: float = 4, - direction: str | None = None, - features: list[str] | None = None, - language: str | None = None, - ) -> None: - """ - :param text: String to be drawn. - :param font: Either an :py:class:`~PIL.ImageFont.ImageFont` instance, - :py:class:`~PIL.ImageFont.FreeTypeFont` instance, - :py:class:`~PIL.ImageFont.TransposedFont` instance or ``None``. If - ``None``, the default font from :py:meth:`.ImageFont.load_default` - will be used. - :param mode: The image mode this will be used with. - :param spacing: The number of pixels between lines. - :param direction: Direction of the text. It can be ``"rtl"`` (right to left), - ``"ltr"`` (left to right) or ``"ttb"`` (top to bottom). - Requires libraqm. - :param features: A list of OpenType font features to be used during text - layout. This is usually used to turn on optional font features - that are not enabled by default, for example ``"dlig"`` or - ``"ss01"``, but can be also used to turn off default font - features, for example ``"-liga"`` to disable ligatures or - ``"-kern"`` to disable kerning. To get all supported - features, see `OpenType docs`_. - Requires libraqm. - :param language: Language of the text. Different languages may use - different glyph shapes or ligatures. This parameter tells - the font which language the text is in, and to apply the - correct substitutions as appropriate, if available. - It should be a `BCP 47 language code`_. - Requires libraqm. - """ - self.text = text - self.font = font or ImageFont.load_default() - - self.mode = mode - self.spacing = spacing - self.direction = direction - self.features = features - self.language = language - - self.embedded_color = False - - self.stroke_width: float = 0 - self.stroke_fill: _Ink | None = None - - def embed_color(self) -> None: - """ - Use embedded color glyphs (COLR, CBDT, SBIX). - """ - if self.mode not in ("RGB", "RGBA"): - msg = "Embedded color supported only in RGB and RGBA modes" - raise ValueError(msg) - self.embedded_color = True - - def stroke(self, width: float = 0, fill: _Ink | None = None) -> None: - """ - :param width: The width of the text stroke. - :param fill: Color to use for the text stroke when drawing. If not given, will - default to the ``fill`` parameter from - :py:meth:`.ImageDraw.ImageDraw.text`. - """ - self.stroke_width = width - self.stroke_fill = fill - - def _get_fontmode(self) -> str: - if self.mode in ("1", "P", "I", "F"): - return "1" - elif self.embedded_color: - return "RGBA" - else: - return "L" - - def get_length(self) -> float: - """ - Returns length (in pixels with 1/64 precision) of text. - - This is the amount by which following text should be offset. - Text bounding box may extend past the length in some fonts, - e.g. when using italics or accents. - - The result is returned as a float; it is a whole number if using basic layout. - - Note that the sum of two lengths may not equal the length of a concatenated - string due to kerning. If you need to adjust for kerning, include the following - character and subtract its length. - - For example, instead of:: - - hello = ImageText.Text("Hello", font).get_length() - world = ImageText.Text("World", font).get_length() - helloworld = ImageText.Text("HelloWorld", font).get_length() - assert hello + world == helloworld - - use:: - - hello = ( - ImageText.Text("HelloW", font).get_length() - - ImageText.Text("W", font).get_length() - ) # adjusted for kerning - world = ImageText.Text("World", font).get_length() - helloworld = ImageText.Text("HelloWorld", font).get_length() - assert hello + world == helloworld - - or disable kerning with (requires libraqm):: - - hello = ImageText.Text("Hello", font, features=["-kern"]).get_length() - world = ImageText.Text("World", font, features=["-kern"]).get_length() - helloworld = ImageText.Text( - "HelloWorld", font, features=["-kern"] - ).get_length() - assert hello + world == helloworld - - :return: Either width for horizontal text, or height for vertical text. - """ - if isinstance(self.text, str): - multiline = "\n" in self.text - else: - multiline = b"\n" in self.text - if multiline: - msg = "can't measure length of multiline text" - raise ValueError(msg) - return self.font.getlength( - self.text, - self._get_fontmode(), - self.direction, - self.features, - self.language, - ) - - def _split( - self, xy: tuple[float, float], anchor: str | None, align: str - ) -> list[tuple[tuple[float, float], str, str | bytes]]: - if anchor is None: - anchor = "lt" if self.direction == "ttb" else "la" - elif len(anchor) != 2: - msg = "anchor must be a 2 character string" - raise ValueError(msg) - - lines = ( - self.text.split("\n") - if isinstance(self.text, str) - else self.text.split(b"\n") - ) - if len(lines) == 1: - return [(xy, anchor, self.text)] - - if anchor[1] in "tb" and self.direction != "ttb": - msg = "anchor not supported for multiline text" - raise ValueError(msg) - - fontmode = self._get_fontmode() - line_spacing = ( - self.font.getbbox( - "A", - fontmode, - None, - self.features, - self.language, - self.stroke_width, - )[3] - + self.stroke_width - + self.spacing - ) - - top = xy[1] - parts = [] - if self.direction == "ttb": - left = xy[0] - for line in lines: - parts.append(((left, top), anchor, line)) - left += line_spacing - else: - widths = [] - max_width: float = 0 - for line in lines: - line_width = self.font.getlength( - line, fontmode, self.direction, self.features, self.language - ) - widths.append(line_width) - max_width = max(max_width, line_width) - - if anchor[1] == "m": - top -= (len(lines) - 1) * line_spacing / 2.0 - elif anchor[1] == "d": - top -= (len(lines) - 1) * line_spacing - - idx = -1 - for line in lines: - left = xy[0] - idx += 1 - width_difference = max_width - widths[idx] - - # align by align parameter - if align in ("left", "justify"): - pass - elif align == "center": - left += width_difference / 2.0 - elif align == "right": - left += width_difference - else: - msg = 'align must be "left", "center", "right" or "justify"' - raise ValueError(msg) - - if ( - align == "justify" - and width_difference != 0 - and idx != len(lines) - 1 - ): - words = ( - line.split(" ") if isinstance(line, str) else line.split(b" ") - ) - if len(words) > 1: - # align left by anchor - if anchor[0] == "m": - left -= max_width / 2.0 - elif anchor[0] == "r": - left -= max_width - - word_widths = [ - self.font.getlength( - word, - fontmode, - self.direction, - self.features, - self.language, - ) - for word in words - ] - word_anchor = "l" + anchor[1] - width_difference = max_width - sum(word_widths) - i = 0 - for word in words: - parts.append(((left, top), word_anchor, word)) - left += word_widths[i] + width_difference / (len(words) - 1) - i += 1 - top += line_spacing - continue - - # align left by anchor - if anchor[0] == "m": - left -= width_difference / 2.0 - elif anchor[0] == "r": - left -= width_difference - parts.append(((left, top), anchor, line)) - top += line_spacing - - return parts - - def get_bbox( - self, - xy: tuple[float, float] = (0, 0), - anchor: str | None = None, - align: str = "left", - ) -> tuple[float, float, float, float]: - """ - Returns bounding box (in pixels) of text. - - Use :py:meth:`get_length` to get the offset of following text with 1/64 pixel - precision. The bounding box includes extra margins for some fonts, e.g. italics - or accents. - - :param xy: The anchor coordinates of the text. - :param anchor: The text anchor alignment. Determines the relative location of - the anchor to the text. The default alignment is top left, - specifically ``la`` for horizontal text and ``lt`` for - vertical text. See :ref:`text-anchors` for details. - :param align: For multiline text, ``"left"``, ``"center"``, ``"right"`` or - ``"justify"`` determines the relative alignment of lines. Use the - ``anchor`` parameter to specify the alignment to ``xy``. - - :return: ``(left, top, right, bottom)`` bounding box - """ - bbox: tuple[float, float, float, float] | None = None - fontmode = self._get_fontmode() - for xy, anchor, line in self._split(xy, anchor, align): - bbox_line = self.font.getbbox( - line, - fontmode, - self.direction, - self.features, - self.language, - self.stroke_width, - anchor, - ) - bbox_line = ( - bbox_line[0] + xy[0], - bbox_line[1] + xy[1], - bbox_line[2] + xy[0], - bbox_line[3] + xy[1], - ) - if bbox is None: - bbox = bbox_line - else: - bbox = ( - min(bbox[0], bbox_line[0]), - min(bbox[1], bbox_line[1]), - max(bbox[2], bbox_line[2]), - max(bbox[3], bbox_line[3]), - ) - - assert bbox is not None - return bbox diff --git a/venv/Lib/site-packages/PIL/ImageTk.py b/venv/Lib/site-packages/PIL/ImageTk.py index 3a4cb81..90defdb 100644 --- a/venv/Lib/site-packages/PIL/ImageTk.py +++ b/venv/Lib/site-packages/PIL/ImageTk.py @@ -28,42 +28,48 @@ from __future__ import annotations import tkinter from io import BytesIO -from typing import Any -from . import Image, ImageFile - -TYPE_CHECKING = False -if TYPE_CHECKING: - from ._typing import CapsuleType +from . import Image # -------------------------------------------------------------------- # Check for Tkinter interface hooks +_pilbitmap_ok = None -def _get_image_from_kw(kw: dict[str, Any]) -> ImageFile.ImageFile | None: + +def _pilbitmap_check() -> int: + global _pilbitmap_ok + if _pilbitmap_ok is None: + try: + im = Image.new("1", (1, 1)) + tkinter.BitmapImage(data=f"PIL:{im.im.id}") + _pilbitmap_ok = 1 + except tkinter.TclError: + _pilbitmap_ok = 0 + return _pilbitmap_ok + + +def _get_image_from_kw(kw): source = None if "file" in kw: source = kw.pop("file") elif "data" in kw: source = BytesIO(kw.pop("data")) - if not source: - return None - return Image.open(source) + if source: + return Image.open(source) -def _pyimagingtkcall( - command: str, photo: PhotoImage | tkinter.PhotoImage, ptr: CapsuleType -) -> None: +def _pyimagingtkcall(command, photo, id): tk = photo.tk try: - tk.call(command, photo, repr(ptr)) + tk.call(command, photo, id) except tkinter.TclError: # activate Tkinter hook # may raise an error if it cannot attach to Tkinter from . import _imagingtk _imagingtk.tkinit(tk.interpaddr()) - tk.call(command, photo, repr(ptr)) + tk.call(command, photo, id) # -------------------------------------------------------------------- @@ -90,36 +96,27 @@ class PhotoImage: image file). """ - def __init__( - self, - image: Image.Image | str | None = None, - size: tuple[int, int] | None = None, - **kw: Any, - ) -> None: + def __init__(self, image=None, size=None, **kw): # Tk compatibility: file or data if image is None: image = _get_image_from_kw(kw) - if image is None: - msg = "Image is required" - raise ValueError(msg) - elif isinstance(image, str): - mode = image - image = None - - if size is None: - msg = "If first argument is mode, size is required" - raise ValueError(msg) - else: + if hasattr(image, "mode") and hasattr(image, "size"): # got an image instead of a mode mode = image.mode if mode == "P": # palette mapped data image.apply_transparency() image.load() - mode = image.palette.mode if image.palette else "RGB" + try: + mode = image.palette.mode + except AttributeError: + mode = "RGB" # default size = image.size kw["width"], kw["height"] = size + else: + mode = image + image = None if mode not in ["1", "L", "RGB", "RGBA"]: mode = Image.getmodebase(mode) @@ -132,10 +129,7 @@ class PhotoImage: self.paste(image) def __del__(self) -> None: - try: - name = self.__photo.name - except AttributeError: - return + name = self.__photo.name self.__photo.name = None try: self.__photo.tk.call("image", "delete", name) @@ -178,14 +172,15 @@ class PhotoImage: the bitmap image. """ # convert to blittable - ptr = im.getim() + im.load() image = im.im - if not image.isblock() or im.mode != self.__mode: - block = Image.core.new_block(self.__mode, im.size) + if image.isblock() and im.mode == self.__mode: + block = image + else: + block = image.new_block(self.__mode, im.size) image.convert2(block, image) # convert directly between buffers - ptr = block.ptr - _pyimagingtkcall("PyImagingPhoto", self.__photo, ptr) + _pyimagingtkcall("PyImagingPhoto", self.__photo, block.id) # -------------------------------------------------------------------- @@ -206,24 +201,26 @@ class BitmapImage: :param image: A PIL image. """ - def __init__(self, image: Image.Image | None = None, **kw: Any) -> None: + def __init__(self, image=None, **kw): # Tk compatibility: file or data if image is None: image = _get_image_from_kw(kw) - if image is None: - msg = "Image is required" - raise ValueError(msg) self.__mode = image.mode self.__size = image.size - self.__photo = tkinter.BitmapImage(data=image.tobitmap(), **kw) + if _pilbitmap_check(): + # fast way (requires the pilbitmap booster patch) + image.load() + kw["data"] = f"PIL:{image.im.id}" + self.__im = image # must keep a reference + else: + # slow but safe way + kw["data"] = image.tobitmap() + self.__photo = tkinter.BitmapImage(**kw) def __del__(self) -> None: - try: - name = self.__photo.name - except AttributeError: - return + name = self.__photo.name self.__photo.name = None try: self.__photo.tk.call("image", "delete", name) @@ -260,7 +257,28 @@ class BitmapImage: def getimage(photo: PhotoImage) -> Image.Image: """Copies the contents of a PhotoImage to a PIL image memory.""" im = Image.new("RGBA", (photo.width(), photo.height())) + block = im.im - _pyimagingtkcall("PyImagingPhotoGet", photo, im.getim()) + _pyimagingtkcall("PyImagingPhotoGet", photo, block.id) return im + + +def _show(image, title): + """Helper for the Image.show method.""" + + class UI(tkinter.Label): + def __init__(self, master, im): + if im.mode == "1": + self.image = BitmapImage(im, foreground="white", master=master) + else: + self.image = PhotoImage(im, master=master) + super().__init__(master, image=self.image, bg="black", bd=0) + + if not tkinter._default_root: + msg = "tkinter not initialized" + raise OSError(msg) + top = tkinter.Toplevel() + if title: + top.title(title) + UI(top, image).pack() diff --git a/venv/Lib/site-packages/PIL/ImageTransform.py b/venv/Lib/site-packages/PIL/ImageTransform.py index fb144ff..ffd7916 100644 --- a/venv/Lib/site-packages/PIL/ImageTransform.py +++ b/venv/Lib/site-packages/PIL/ImageTransform.py @@ -14,8 +14,7 @@ # from __future__ import annotations -from collections.abc import Sequence -from typing import Any +from typing import Any, Sequence from . import Image @@ -48,9 +47,9 @@ class AffineTransform(Transform): Define an affine image transform. This function takes a 6-tuple (a, b, c, d, e, f) which contain the first - two rows from the inverse of an affine transform matrix. For each pixel - (x, y) in the output image, the new value is taken from a position (a x + - b y + c, d x + e y + f) in the input image, rounded to nearest pixel. + two rows from an affine transform matrix. For each pixel (x, y) in the + output image, the new value is taken from a position (a x + b y + c, + d x + e y + f) in the input image, rounded to nearest pixel. This function can be used to scale, translate, rotate, and shear the original image. @@ -58,7 +57,7 @@ class AffineTransform(Transform): See :py:meth:`.Image.transform` :param matrix: A 6-tuple (a, b, c, d, e, f) containing the first two rows - from the inverse of an affine transform matrix. + from an affine transform matrix. """ method = Image.Transform.AFFINE diff --git a/venv/Lib/site-packages/PIL/ImageWin.py b/venv/Lib/site-packages/PIL/ImageWin.py index 98c28f2..978c5a9 100644 --- a/venv/Lib/site-packages/PIL/ImageWin.py +++ b/venv/Lib/site-packages/PIL/ImageWin.py @@ -70,14 +70,11 @@ class Dib: """ def __init__( - self, image: Image.Image | str, size: tuple[int, int] | None = None + self, image: Image.Image | str, size: tuple[int, int] | list[int] | None = None ) -> None: if isinstance(image, str): mode = image image = "" - if size is None: - msg = "If first argument is mode, size is required" - raise ValueError(msg) else: mode = image.mode size = image.size @@ -90,7 +87,7 @@ class Dib: assert not isinstance(image, str) self.paste(image) - def expose(self, handle: int | HDC | HWND) -> None: + def expose(self, handle): """ Copy the bitmap contents to a device context. @@ -98,22 +95,17 @@ class Dib: HDC or HWND instance. In PythonWin, you can use ``CDC.GetHandleAttrib()`` to get a suitable handle. """ - handle_int = int(handle) if isinstance(handle, HWND): - dc = self.image.getdc(handle_int) + dc = self.image.getdc(handle) try: - self.image.expose(dc) + result = self.image.expose(dc) finally: - self.image.releasedc(handle_int, dc) + self.image.releasedc(handle, dc) else: - self.image.expose(handle_int) + result = self.image.expose(handle) + return result - def draw( - self, - handle: int | HDC | HWND, - dst: tuple[int, int, int, int], - src: tuple[int, int, int, int] | None = None, - ) -> None: + def draw(self, handle, dst, src=None): """ Same as expose, but allows you to specify where to draw the image, and what part of it to draw. @@ -123,19 +115,19 @@ class Dib: the destination have different sizes, the image is resized as necessary. """ - if src is None: + if not src: src = (0, 0) + self.size - handle_int = int(handle) if isinstance(handle, HWND): - dc = self.image.getdc(handle_int) + dc = self.image.getdc(handle) try: - self.image.draw(dc, dst, src) + result = self.image.draw(dc, dst, src) finally: - self.image.releasedc(handle_int, dc) + self.image.releasedc(handle, dc) else: - self.image.draw(handle_int, dst, src) + result = self.image.draw(handle, dst, src) + return result - def query_palette(self, handle: int | HDC | HWND) -> int: + def query_palette(self, handle): """ Installs the palette associated with the image in the given device context. @@ -147,18 +139,17 @@ class Dib: :param handle: Device context (HDC), cast to a Python integer, or an HDC or HWND instance. - :return: The number of entries that were changed (if one or more entries, - this indicates that the image should be redrawn). + :return: A true value if one or more entries were changed (this + indicates that the image should be redrawn). """ - handle_int = int(handle) if isinstance(handle, HWND): - handle = self.image.getdc(handle_int) + handle = self.image.getdc(handle) try: result = self.image.query_palette(handle) finally: self.image.releasedc(handle, handle) else: - result = self.image.query_palette(handle_int) + result = self.image.query_palette(handle) return result def paste( @@ -211,22 +202,22 @@ class Window: title, self.__dispatcher, width or 0, height or 0 ) - def __dispatcher(self, action: str, *args: int) -> None: - getattr(self, f"ui_handle_{action}")(*args) + def __dispatcher(self, action, *args): + return getattr(self, f"ui_handle_{action}")(*args) - def ui_handle_clear(self, dc: int, x0: int, y0: int, x1: int, y1: int) -> None: + def ui_handle_clear(self, dc, x0, y0, x1, y1): pass - def ui_handle_damage(self, x0: int, y0: int, x1: int, y1: int) -> None: + def ui_handle_damage(self, x0, y0, x1, y1): pass def ui_handle_destroy(self) -> None: pass - def ui_handle_repair(self, dc: int, x0: int, y0: int, x1: int, y1: int) -> None: + def ui_handle_repair(self, dc, x0, y0, x1, y1): pass - def ui_handle_resize(self, width: int, height: int) -> None: + def ui_handle_resize(self, width, height): pass def mainloop(self) -> None: @@ -236,12 +227,12 @@ class Window: class ImageWindow(Window): """Create an image window which displays the given image.""" - def __init__(self, image: Image.Image | Dib, title: str = "PIL") -> None: + def __init__(self, image, title="PIL"): if not isinstance(image, Dib): image = Dib(image) self.image = image width, height = image.size super().__init__(title, width=width, height=height) - def ui_handle_repair(self, dc: int, x0: int, y0: int, x1: int, y1: int) -> None: + def ui_handle_repair(self, dc, x0, y0, x1, y1): self.image.draw(dc, (x0, y0, x1, y1)) diff --git a/venv/Lib/site-packages/PIL/ImtImagePlugin.py b/venv/Lib/site-packages/PIL/ImtImagePlugin.py index c4eccee..abb3fb7 100644 --- a/venv/Lib/site-packages/PIL/ImtImagePlugin.py +++ b/venv/Lib/site-packages/PIL/ImtImagePlugin.py @@ -55,14 +55,14 @@ class ImtImageFile(ImageFile.ImageFile): if not s: break - if s == b"\x0c": + if s == b"\x0C": # image data begins self.tile = [ - ImageFile._Tile( + ( "raw", (0, 0) + self.size, self.fp.tell() - len(buffer), - self.mode, + (self.mode, 0, 1), ) ] diff --git a/venv/Lib/site-packages/PIL/IptcImagePlugin.py b/venv/Lib/site-packages/PIL/IptcImagePlugin.py index 6fc824e..73df83b 100644 --- a/venv/Lib/site-packages/PIL/IptcImagePlugin.py +++ b/venv/Lib/site-packages/PIL/IptcImagePlugin.py @@ -17,15 +17,24 @@ from __future__ import annotations from io import BytesIO -from typing import cast +from typing import Sequence from . import Image, ImageFile from ._binary import i16be as i16 from ._binary import i32be as i32 +from ._deprecate import deprecate COMPRESSION = {1: "raw", 5: "jpeg"} +def __getattr__(name: str) -> bytes: + if name == "PAD": + deprecate("IptcImagePlugin.PAD", 12) + return b"\0\0\0\0" + msg = f"module '{__name__}' has no attribute '{name}'" + raise AttributeError(msg) + + # # Helpers @@ -34,6 +43,24 @@ def _i(c: bytes) -> int: return i32((b"\0\0\0\0" + c)[-4:]) +def _i8(c: int | bytes) -> int: + return c if isinstance(c, int) else c[0] + + +def i(c: bytes) -> int: + """.. deprecated:: 10.2.0""" + deprecate("IptcImagePlugin.i", 12) + return _i(c) + + +def dump(c: Sequence[int | bytes]) -> None: + """.. deprecated:: 10.2.0""" + deprecate("IptcImagePlugin.dump", 12) + for i in c: + print(f"{_i8(i):02x}", end=" ") + print() + + ## # Image plugin for IPTC/NAA datastreams. To read IPTC/NAA fields # from TIFF and JPEG files, use the getiptcinfo function. @@ -49,7 +76,6 @@ class IptcImageFile(ImageFile.ImageFile): def field(self) -> tuple[tuple[int, int] | None, int]: # # get a IPTC field header - assert self.fp is not None s = self.fp.read(5) if not s.strip(b"\x00"): return None, 0 @@ -77,7 +103,6 @@ class IptcImageFile(ImageFile.ImageFile): def _open(self) -> None: # load descriptive fields - assert self.fp is not None while True: offset = self.fp.tell() tag, size = self.field() @@ -98,18 +123,16 @@ class IptcImageFile(ImageFile.ImageFile): # mode layers = self.info[(3, 60)][0] component = self.info[(3, 60)][1] + if (3, 65) in self.info: + id = self.info[(3, 65)][0] - 1 + else: + id = 0 if layers == 1 and not component: self._mode = "L" - band = None - else: - if layers == 3 and component: - self._mode = "RGB" - elif layers == 4 and component: - self._mode = "CMYK" - if (3, 65) in self.info: - band = self.info[(3, 65)][0] - 1 - else: - band = 0 + elif layers == 3 and component: + self._mode = "RGB"[id] + elif layers == 4 and component: + self._mode = "CMYK"[id] # size self._size = self.getint((3, 20)), self.getint((3, 30)) @@ -123,47 +146,36 @@ class IptcImageFile(ImageFile.ImageFile): # tile if tag == (8, 10): - self.tile = [ - ImageFile._Tile("iptc", (0, 0) + self.size, offset, (compression, band)) - ] + self.tile = [("iptc", (0, 0) + self.size, offset, compression)] - def load(self) -> Image.core.PixelAccess | None: - if self.tile: - args = self.tile[0].args - assert isinstance(args, tuple) - compression, band = args + def load(self): + if len(self.tile) != 1 or self.tile[0][0] != "iptc": + return ImageFile.ImageFile.load(self) - assert self.fp is not None - self.fp.seek(self.tile[0].offset) + offset, compression = self.tile[0][2:] - # Copy image data to temporary file - o = BytesIO() - if compression == "raw": - # To simplify access to the extracted file, - # prepend a PPM header - o.write(b"P5\n%d %d\n255\n" % self.size) - while True: - type, size = self.field() - if type != (8, 10): + self.fp.seek(offset) + + # Copy image data to temporary file + o = BytesIO() + if compression == "raw": + # To simplify access to the extracted file, + # prepend a PPM header + o.write(b"P5\n%d %d\n255\n" % self.size) + while True: + type, size = self.field() + if type != (8, 10): + break + while size > 0: + s = self.fp.read(min(size, 8192)) + if not s: break - while size > 0: - s = self.fp.read(min(size, 8192)) - if not s: - break - o.write(s) - size -= len(s) + o.write(s) + size -= len(s) - with Image.open(o) as _im: - if band is not None: - bands = [Image.new("L", _im.size)] * Image.getmodebands(self.mode) - bands[band] = _im - im = Image.merge(self.mode, bands) - else: - im = _im - im.load() - self.im = im.im - self.tile = [] - return ImageFile.ImageFile.load(self) + with Image.open(o) as _im: + _im.load() + self.im = _im.im Image.register_open(IptcImageFile.format, IptcImageFile) @@ -171,9 +183,7 @@ Image.register_open(IptcImageFile.format, IptcImageFile) Image.register_extension(IptcImageFile.format, ".iim") -def getiptcinfo( - im: ImageFile.ImageFile, -) -> dict[tuple[int, int], bytes | list[bytes]] | None: +def getiptcinfo(im): """ Get IPTC information from TIFF, JPEG, or IPTC file. @@ -185,13 +195,9 @@ def getiptcinfo( data = None - info: dict[tuple[int, int], bytes | list[bytes]] = {} if isinstance(im, IptcImageFile): # return info dictionary right away - for k, v in im.info.items(): - if isinstance(k, tuple): - info[k] = v - return info + return im.info elif isinstance(im, JpegImagePlugin.JpegImageFile): # extract the IPTC/NAA resource @@ -203,8 +209,8 @@ def getiptcinfo( # get raw data from the IPTC/NAA tag (PhotoShop tags the data # as 4-byte integers, so we cannot use the get method...) try: - data = im.tag_v2._tagdata[TiffImagePlugin.IPTC_NAA_CHUNK] - except KeyError: + data = im.tag.tagdata[TiffImagePlugin.IPTC_NAA_CHUNK] + except (AttributeError, KeyError): pass if data is None: @@ -214,20 +220,16 @@ def getiptcinfo( class FakeImage: pass - fake_im = FakeImage() - fake_im.__class__ = IptcImageFile # type: ignore[assignment] - iptc_im = cast(IptcImageFile, fake_im) + im = FakeImage() + im.__class__ = IptcImageFile # parse the IPTC information chunk - iptc_im.info = {} - iptc_im.fp = BytesIO(data) + im.info = {} + im.fp = BytesIO(data) try: - iptc_im._open() + im._open() except (IndexError, KeyError): pass # expected failure - for k, v in iptc_im.info.items(): - if isinstance(k, tuple): - info[k] = v - return info + return im.info diff --git a/venv/Lib/site-packages/PIL/Jpeg2KImagePlugin.py b/venv/Lib/site-packages/PIL/Jpeg2KImagePlugin.py index d6ec38d..e50cd77 100644 --- a/venv/Lib/site-packages/PIL/Jpeg2KImagePlugin.py +++ b/venv/Lib/site-packages/PIL/Jpeg2KImagePlugin.py @@ -18,15 +18,10 @@ from __future__ import annotations import io import os import struct -from typing import cast +from typing import IO, Tuple, cast from . import Image, ImageFile, ImagePalette, _binary -TYPE_CHECKING = False -if TYPE_CHECKING: - from collections.abc import Callable - from typing import IO - class BoxReader: """ @@ -34,7 +29,7 @@ class BoxReader: and to easily step into and read sub-boxes. """ - def __init__(self, fp: IO[bytes], length: int = -1) -> None: + def __init__(self, fp, length=-1): self.fp = fp self.has_length = length >= 0 self.length = length @@ -87,7 +82,7 @@ class BoxReader: self.remaining_in_box = -1 # Read the length and type of the next box - lbox, tbox = cast(tuple[int, bytes], self.read_fields(">I4s")) + lbox, tbox = cast(Tuple[int, bytes], self.read_fields(">I4s")) if lbox == 1: lbox = cast(int, self.read_fields(">Q")[0]) hlen = 16 @@ -102,7 +97,7 @@ class BoxReader: return tbox -def _parse_codestream(fp: IO[bytes]) -> tuple[tuple[int, int], str]: +def _parse_codestream(fp) -> tuple[tuple[int, int], str]: """Parse the JPEG 2000 codestream to extract the size and component count from the SIZ marker segment, returning a PIL (size, mode) tuple.""" @@ -142,15 +137,7 @@ def _res_to_dpi(num: int, denom: int, exp: int) -> float | None: return (254 * num * (10**exp)) / (10000 * denom) -def _parse_jp2_header( - fp: IO[bytes], -) -> tuple[ - tuple[int, int], - str, - str | None, - tuple[float, float] | None, - ImagePalette.ImagePalette | None, -]: +def _parse_jp2_header(fp): """Parse the JP2 header box to extract size, component count, color space information, and optionally DPI information, returning a (size, mode, mimetype, dpi) tuple.""" @@ -168,7 +155,6 @@ def _parse_jp2_header( elif tbox == b"ftyp": if reader.read_fields(">4s")[0] == b"jpx ": mimetype = "image/jpx" - assert header is not None size = None mode = None @@ -182,9 +168,6 @@ def _parse_jp2_header( if tbox == b"ihdr": height, width, nc, bpc = header.read_fields(">IIHB") - assert isinstance(height, int) - assert isinstance(width, int) - assert isinstance(bpc, int) size = (width, height) if nc == 1 and (bpc & 0x7F) > 8: mode = "I;16" @@ -202,21 +185,11 @@ def _parse_jp2_header( mode = "CMYK" elif tbox == b"pclr" and mode in ("L", "LA"): ne, npc = header.read_fields(">HB") - assert isinstance(ne, int) - assert isinstance(npc, int) - max_bitdepth = 0 - for bitdepth in header.read_fields(">" + ("B" * npc)): - assert isinstance(bitdepth, int) - if bitdepth > max_bitdepth: - max_bitdepth = bitdepth - if max_bitdepth <= 8: - palette = ImagePalette.ImagePalette("RGBA" if npc == 4 else "RGB") + bitdepths = header.read_fields(">" + ("B" * npc)) + if max(bitdepths) <= 8: + palette = ImagePalette.ImagePalette() for i in range(ne): - color: list[int] = [] - for value in header.read_fields(">" + ("B" * npc)): - assert isinstance(value, int) - color.append(value) - palette.getcolor(tuple(color)) + palette.getcolor(header.read_fields(">" + ("B" * npc))) mode = "P" if mode == "L" else "PA" elif tbox == b"res ": res = header.read_boxes() @@ -224,12 +197,6 @@ def _parse_jp2_header( tres = res.next_box_type() if tres == b"resc": vrcn, vrcd, hrcn, hrcd, vrce, hrce = res.read_fields(">HHHHBB") - assert isinstance(vrcn, int) - assert isinstance(vrcd, int) - assert isinstance(hrcn, int) - assert isinstance(hrcd, int) - assert isinstance(vrce, int) - assert isinstance(hrce, int) hres = _res_to_dpi(hrcn, hrcd, hrce) vres = _res_to_dpi(vrcn, vrcd, vrce) if hres is not None and vres is not None: @@ -252,12 +219,10 @@ class Jpeg2KImageFile(ImageFile.ImageFile): format_description = "JPEG 2000 (ISO 15444)" def _open(self) -> None: - assert self.fp is not None sig = self.fp.read(4) if sig == b"\xff\x4f\xff\x51": self.codec = "j2k" self._size, self._mode = _parse_codestream(self.fp) - self._parse_comment() else: sig = sig + self.fp.read(8) @@ -268,9 +233,6 @@ class Jpeg2KImageFile(ImageFile.ImageFile): if dpi is not None: self.info["dpi"] = dpi if self.fp.read(12).endswith(b"jp2c\xff\x4f\xff\x51"): - hdr = self.fp.read(2) - length = _binary.i16be(hdr) - self.fp.seek(length - 2, os.SEEK_CUR) self._parse_comment() else: msg = "not a JPEG 2000 file" @@ -296,7 +258,7 @@ class Jpeg2KImageFile(ImageFile.ImageFile): length = -1 self.tile = [ - ImageFile._Tile( + ( "jpeg2k", (0, 0) + self.size, 0, @@ -305,7 +267,10 @@ class Jpeg2KImageFile(ImageFile.ImageFile): ] def _parse_comment(self) -> None: - assert self.fp is not None + hdr = self.fp.read(2) + length = _binary.i16be(hdr) + self.fp.seek(length - 2, os.SEEK_CUR) + while True: marker = self.fp.read(2) if not marker: @@ -323,23 +288,18 @@ class Jpeg2KImageFile(ImageFile.ImageFile): else: self.fp.seek(length - 2, os.SEEK_CUR) - @property # type: ignore[override] - def reduce( - self, - ) -> ( - Callable[[int | tuple[int, int], tuple[int, int, int, int] | None], Image.Image] - | int - ): + @property + def reduce(self): # https://github.com/python-pillow/Pillow/issues/4343 found that the # new Image 'reduce' method was shadowed by this plugin's 'reduce' # property. This attempts to allow for both scenarios return self._reduce or super().reduce @reduce.setter - def reduce(self, value: int) -> None: + def reduce(self, value): self._reduce = value - def load(self) -> Image.core.PixelAccess | None: + def load(self): if self.tile and self._reduce: power = 1 << self._reduce adjust = power >> 1 @@ -350,16 +310,16 @@ class Jpeg2KImageFile(ImageFile.ImageFile): # Update the reduce and layers settings t = self.tile[0] - assert isinstance(t[3], tuple) t3 = (t[3][0], self._reduce, self.layers, t[3][3], t[3][4]) - self.tile = [ImageFile._Tile(t[0], (0, 0) + self.size, t[2], t3)] + self.tile = [(t[0], (0, 0) + self.size, t[2], t3)] return ImageFile.ImageFile.load(self) def _accept(prefix: bytes) -> bool: - return prefix.startswith( - (b"\xff\x4f\xff\x51", b"\x00\x00\x00\x0cjP \x0d\x0a\x87\x0a") + return ( + prefix[:4] == b"\xff\x4f\xff\x51" + or prefix[:12] == b"\x00\x00\x00\x0cjP \x0d\x0a\x87\x0a" ) @@ -431,7 +391,7 @@ def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: plt, ) - ImageFile._save(im, fp, [ImageFile._Tile("jpeg2k", (0, 0) + im.size, 0, kind)]) + ImageFile._save(im, fp, [("jpeg2k", (0, 0) + im.size, 0, kind)]) # ------------------------------------------------------------ diff --git a/venv/Lib/site-packages/PIL/JpegImagePlugin.py b/venv/Lib/site-packages/PIL/JpegImagePlugin.py index 894c154..b15bf06 100644 --- a/venv/Lib/site-packages/PIL/JpegImagePlugin.py +++ b/venv/Lib/site-packages/PIL/JpegImagePlugin.py @@ -42,6 +42,7 @@ import subprocess import sys import tempfile import warnings +from typing import IO, Any from . import Image, ImageFile from ._binary import i16be as i16 @@ -50,37 +51,29 @@ from ._binary import o8 from ._binary import o16be as o16 from .JpegPresets import presets -TYPE_CHECKING = False -if TYPE_CHECKING: - from typing import IO, Any - - from .MpoImagePlugin import MpoImageFile - # # Parser def Skip(self: JpegImageFile, marker: int) -> None: - assert self.fp is not None n = i16(self.fp.read(2)) - 2 ImageFile._safe_read(self.fp, n) -def APP(self: JpegImageFile, marker: int) -> None: +def APP(self, marker): # # Application marker. Store these in the APP dictionary. # Also look for well-known application markers. - assert self.fp is not None n = i16(self.fp.read(2)) - 2 s = ImageFile._safe_read(self.fp, n) - app = f"APP{marker & 15}" + app = "APP%d" % (marker & 15) self.app[app] = s # compatibility self.applist.append((app, s)) - if marker == 0xFFE0 and s.startswith(b"JFIF"): + if marker == 0xFFE0 and s[:4] == b"JFIF": # extract JFIF information self.info["jfif"] = version = i16(s, 5) # version self.info["jfif_version"] = divmod(version, 256) @@ -93,24 +86,21 @@ def APP(self: JpegImageFile, marker: int) -> None: else: if jfif_unit == 1: self.info["dpi"] = jfif_density - elif jfif_unit == 2: # cm - # 1 dpcm = 2.54 dpi - self.info["dpi"] = tuple(d * 2.54 for d in jfif_density) self.info["jfif_unit"] = jfif_unit self.info["jfif_density"] = jfif_density - elif marker == 0xFFE1 and s.startswith(b"Exif\0\0"): + elif marker == 0xFFE1 and s[:6] == b"Exif\0\0": # extract EXIF information if "exif" in self.info: self.info["exif"] += s[6:] else: self.info["exif"] = s self._exif_offset = self.fp.tell() - n + 6 - elif marker == 0xFFE1 and s.startswith(b"http://ns.adobe.com/xap/1.0/\x00"): + elif marker == 0xFFE1 and s[:29] == b"http://ns.adobe.com/xap/1.0/\x00": self.info["xmp"] = s.split(b"\x00", 1)[1] - elif marker == 0xFFE2 and s.startswith(b"FPXR\0"): + elif marker == 0xFFE2 and s[:5] == b"FPXR\0": # extract FlashPix information (incomplete) self.info["flashpix"] = s # FIXME: value will change - elif marker == 0xFFE2 and s.startswith(b"ICC_PROFILE\0"): + elif marker == 0xFFE2 and s[:12] == b"ICC_PROFILE\0": # Since an ICC profile can be larger than the maximum size of # a JPEG marker (64K), we need provisions to split it into # multiple markers. The format defined by the ICC specifies @@ -123,7 +113,7 @@ def APP(self: JpegImageFile, marker: int) -> None: # reassemble the profile, rather than assuming that the APP2 # markers appear in the correct sequence. self.icclist.append(s) - elif marker == 0xFFED and s.startswith(b"Photoshop 3.0\x00"): + elif marker == 0xFFED and s[:14] == b"Photoshop 3.0\x00": # parse the image resource block offset = 14 photoshop = self.info.setdefault("photoshop", {}) @@ -143,20 +133,19 @@ def APP(self: JpegImageFile, marker: int) -> None: offset += 4 data = s[offset : offset + size] if code == 0x03ED: # ResolutionInfo - photoshop[code] = { + data = { "XResolution": i32(data, 0) / 65536, "DisplayedUnitsX": i16(data, 4), "YResolution": i32(data, 8) / 65536, "DisplayedUnitsY": i16(data, 12), } - else: - photoshop[code] = data + photoshop[code] = data offset += size offset += offset & 1 # align except struct.error: break # insufficient data - elif marker == 0xFFEE and s.startswith(b"Adobe"): + elif marker == 0xFFEE and s[:5] == b"Adobe": self.info["adobe"] = i16(s, 5) # extract Adobe custom properties try: @@ -165,7 +154,7 @@ def APP(self: JpegImageFile, marker: int) -> None: pass else: self.info["adobe_transform"] = adobe_transform - elif marker == 0xFFE2 and s.startswith(b"MPF\0"): + elif marker == 0xFFE2 and s[:4] == b"MPF\0": # extract MPO information self.info["mp"] = s[4:] # offset is current location minus buffer size @@ -176,7 +165,6 @@ def APP(self: JpegImageFile, marker: int) -> None: def COM(self: JpegImageFile, marker: int) -> None: # # Comment marker. Store these in the APP dictionary. - assert self.fp is not None n = i16(self.fp.read(2)) - 2 s = ImageFile._safe_read(self.fp, n) @@ -193,12 +181,9 @@ def SOF(self: JpegImageFile, marker: int) -> None: # mode. Note that this could be made a bit brighter, by # looking for JFIF and Adobe APP markers. - assert self.fp is not None n = i16(self.fp.read(2)) - 2 s = ImageFile._safe_read(self.fp, n) self._size = i16(s, 3), i16(s, 1) - if self._im is not None and self.size != self.im.size: - self._im = None self.bits = s[0] if self.bits != 8: @@ -244,7 +229,6 @@ def DQT(self: JpegImageFile, marker: int) -> None: # FIXME: The quantization tables can be used to estimate the # compression quality. - assert self.fp is not None n = i16(self.fp.read(2)) - 2 s = ImageFile._safe_read(self.fp, n) while len(s): @@ -333,7 +317,7 @@ MARKER = { def _accept(prefix: bytes) -> bool: # Magic number was taken from https://en.wikipedia.org/wiki/JPEG - return prefix.startswith(b"\xff\xd8\xff") + return prefix[:3] == b"\xFF\xD8\xFF" ## @@ -344,27 +328,25 @@ class JpegImageFile(ImageFile.ImageFile): format = "JPEG" format_description = "JPEG (ISO 10918)" - def _open(self) -> None: - assert self.fp is not None + def _open(self): s = self.fp.read(3) if not _accept(s): msg = "not a JPEG file" raise SyntaxError(msg) - s = b"\xff" + s = b"\xFF" # Create attributes self.bits = self.layers = 0 - self._exif_offset = 0 # JPEG specifics (internal) - self.layer: list[tuple[int, int, int, int]] = [] - self._huffman_dc: dict[Any, Any] = {} - self._huffman_ac: dict[Any, Any] = {} - self.quantization: dict[int, list[int]] = {} - self.app: dict[str, bytes] = {} # compatibility - self.applist: list[tuple[str, bytes]] = [] - self.icclist: list[bytes] = [] + self.layer = [] + self.huffman_dc = {} + self.huffman_ac = {} + self.quantization = {} + self.app = {} # compatibility + self.applist = [] + self.icclist = [] while True: i = s[0] @@ -384,9 +366,7 @@ class JpegImageFile(ImageFile.ImageFile): rawmode = self.mode if self.mode == "CMYK": rawmode = "CMYK;I" # assume adobe conventions - self.tile = [ - ImageFile._Tile("jpeg", (0, 0) + self.size, 0, (rawmode, "")) - ] + self.tile = [("jpeg", (0, 0) + self.size, 0, (rawmode, ""))] # self.__offset = self.fp.tell() break s = self.fp.read(1) @@ -401,27 +381,19 @@ class JpegImageFile(ImageFile.ImageFile): self._read_dpi_from_exif() - def __getstate__(self) -> list[Any]: - return super().__getstate__() + [self.layers, self.layer] - - def __setstate__(self, state: list[Any]) -> None: - self.layers, self.layer = state[6:] - super().__setstate__(state) - def load_read(self, read_bytes: int) -> bytes: """ internal: read more image data For premature EOF and LOAD_TRUNCATED_IMAGES adds EOI marker so libjpeg can finish decoding """ - assert self.fp is not None s = self.fp.read(read_bytes) if not s and ImageFile.LOAD_TRUNCATED_IMAGES and not hasattr(self, "_ended"): # Premature EOF. # Pretend file is finished adding EOI marker self._ended = True - return b"\xff\xd9" + return b"\xFF\xD9" return s @@ -439,7 +411,6 @@ class JpegImageFile(ImageFile.ImageFile): scale = 1 original_size = self.size - assert isinstance(a, tuple) if a[0] == "RGB" and mode in ["L", "YCbCr"]: self._mode = mode a = mode, "" @@ -449,7 +420,6 @@ class JpegImageFile(ImageFile.ImageFile): for s in [8, 4, 2, 1]: if scale >= s: break - assert e is not None e = ( e[0], e[1], @@ -459,7 +429,7 @@ class JpegImageFile(ImageFile.ImageFile): self._size = ((self.size[0] + s - 1) // s, (self.size[1] + s - 1) // s) scale = s - self.tile = [ImageFile._Tile(d, e, o, a)] + self.tile = [(d, e, o, a)] self.decoderconfig = (scale, 0) box = (0, 0, original_size[0] / scale, original_size[1] / scale) @@ -496,7 +466,7 @@ class JpegImageFile(ImageFile.ImageFile): self.tile = [] - def _getexif(self) -> dict[int, Any] | None: + def _getexif(self) -> dict[str, Any] | None: return _getexif(self) def _read_dpi_from_exif(self) -> None: @@ -528,17 +498,17 @@ class JpegImageFile(ImageFile.ImageFile): ): self.info["dpi"] = 72, 72 - def _getmp(self) -> dict[int, Any] | None: + def _getmp(self): return _getmp(self) -def _getexif(self: JpegImageFile) -> dict[int, Any] | None: +def _getexif(self) -> dict[str, Any] | None: if "exif" not in self.info: return None return self.getexif()._get_merged_dict() -def _getmp(self: JpegImageFile) -> dict[int, Any] | None: +def _getmp(self): # Extract MP information. This method was inspired by the "highly # experimental" _getexif version that's been in use for years now, # itself based on the ImageFileDirectory class in the TIFF plugin. @@ -551,7 +521,7 @@ def _getmp(self: JpegImageFile) -> dict[int, Any] | None: return None file_contents = io.BytesIO(data) head = file_contents.read(8) - endianness = ">" if head.startswith(b"\x4d\x4d\x00\x2a") else "<" + endianness = ">" if head[:4] == b"\x4d\x4d\x00\x2a" else "<" # process dictionary from . import TiffImagePlugin @@ -573,7 +543,7 @@ def _getmp(self: JpegImageFile) -> dict[int, Any] | None: mpentries = [] try: rawmpentries = mp[0xB002] - for entrynum in range(quant): + for entrynum in range(0, quant): unpackedentry = struct.unpack_from( f"{endianness}LLLHH", rawmpentries, entrynum * 16 ) @@ -646,7 +616,7 @@ samplings = { # fmt: on -def get_sampling(im: Image.Image) -> int: +def get_sampling(im): # There's no subsampling when images have only 1 layer # (grayscale images) or when they are CMYK (4 layers), # so set subsampling to the default value. @@ -654,7 +624,7 @@ def get_sampling(im: Image.Image) -> int: # NOTE: currently Pillow can't encode JPEG to YCCK format. # If YCCK support is added in the future, subsampling code will have # to be updated (here and in JpegEncode.c) to deal with 4 layers. - if not isinstance(im, JpegImageFile) or im.layers in (1, 4): + if not hasattr(im, "layers") or im.layers in (1, 4): return -1 sampling = im.layer[0][1:3] + im.layer[1][1:3] + im.layer[2][1:3] return samplings.get(sampling, -1) @@ -713,11 +683,7 @@ def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: raise ValueError(msg) subsampling = get_sampling(im) - def validate_qtables( - qtables: ( - str | tuple[list[int], ...] | list[list[int]] | dict[int, list[int]] | None - ), - ) -> list[list[int]] | None: + def validate_qtables(qtables): if qtables is None: return qtables if isinstance(qtables, str): @@ -747,12 +713,12 @@ def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: if len(table) != 64: msg = "Invalid quantization table" raise TypeError(msg) - table_array = array.array("H", table) + table = array.array("H", table) except TypeError as e: msg = "Invalid quantization table" raise ValueError(msg) from e else: - qtables[idx] = list(table_array) + qtables[idx] = list(table) return qtables if qtables == "keep": @@ -765,27 +731,19 @@ def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: extra = info.get("extra", b"") MAX_BYTES_IN_MARKER = 65533 - if xmp := info.get("xmp"): - overhead_len = 29 # b"http://ns.adobe.com/xap/1.0/\x00" - max_data_bytes_in_marker = MAX_BYTES_IN_MARKER - overhead_len - if len(xmp) > max_data_bytes_in_marker: - msg = "XMP data is too long" - raise ValueError(msg) - size = o16(2 + overhead_len + len(xmp)) - extra += b"\xff\xe1" + size + b"http://ns.adobe.com/xap/1.0/\x00" + xmp - - if icc_profile := info.get("icc_profile"): - overhead_len = 14 # b"ICC_PROFILE\0" + o8(i) + o8(len(markers)) - max_data_bytes_in_marker = MAX_BYTES_IN_MARKER - overhead_len + icc_profile = info.get("icc_profile") + if icc_profile: + ICC_OVERHEAD_LEN = 14 + MAX_DATA_BYTES_IN_MARKER = MAX_BYTES_IN_MARKER - ICC_OVERHEAD_LEN markers = [] while icc_profile: - markers.append(icc_profile[:max_data_bytes_in_marker]) - icc_profile = icc_profile[max_data_bytes_in_marker:] + markers.append(icc_profile[:MAX_DATA_BYTES_IN_MARKER]) + icc_profile = icc_profile[MAX_DATA_BYTES_IN_MARKER:] i = 1 for marker in markers: - size = o16(2 + overhead_len + len(marker)) + size = o16(2 + ICC_OVERHEAD_LEN + len(marker)) extra += ( - b"\xff\xe2" + b"\xFF\xE2" + size + b"ICC_PROFILE\0" + o8(i) @@ -818,7 +776,8 @@ def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: optimize, info.get("keep_rgb", False), info.get("streamtype", 0), - dpi, + dpi[0], + dpi[1], subsampling, info.get("restart_marker_blocks", 0), info.get("restart_marker_rows", 0), @@ -832,6 +791,7 @@ def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: # in a shot. Guessing on the size, at im.size bytes. (raw pixel size is # channels*size, this is a value that's been used in a django patch. # https://github.com/matthewwithanm/django-imagekit/issues/50 + bufsize = 0 if optimize or progressive: # CMYK can be bigger if im.mode == "CMYK": @@ -848,22 +808,28 @@ def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: else: # The EXIF info needs to be written as one block, + APP1, + one spare byte. # Ensure that our buffer is big enough. Same with the icc_profile block. - bufsize = max(len(exif) + 5, len(extra) + 1) + bufsize = max(bufsize, len(exif) + 5, len(extra) + 1) - ImageFile._save( - im, fp, [ImageFile._Tile("jpeg", (0, 0) + im.size, 0, rawmode)], bufsize - ) + ImageFile._save(im, fp, [("jpeg", (0, 0) + im.size, 0, rawmode)], bufsize) + + +def _save_cjpeg(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: + # ALTERNATIVE: handle JPEGs via the IJG command line utilities. + tempfile = im._dump() + subprocess.check_call(["cjpeg", "-outfile", filename, tempfile]) + try: + os.unlink(tempfile) + except OSError: + pass ## # Factory for making JPEG and MPO instances -def jpeg_factory( - fp: IO[bytes], filename: str | bytes | None = None -) -> JpegImageFile | MpoImageFile: +def jpeg_factory(fp=None, filename=None): im = JpegImageFile(fp, filename) try: mpheader = im._getmp() - if mpheader is not None and mpheader[45057] > 1: + if mpheader[45057] > 1: for segment, content in im.applist: if segment == "APP1" and b' hdrgm:Version="' in content: # Ultra HDR images are not yet supported diff --git a/venv/Lib/site-packages/PIL/JpegPresets.py b/venv/Lib/site-packages/PIL/JpegPresets.py index d0e64a3..3aefa07 100644 --- a/venv/Lib/site-packages/PIL/JpegPresets.py +++ b/venv/Lib/site-packages/PIL/JpegPresets.py @@ -37,7 +37,7 @@ You can get the subsampling of a JPEG with the :func:`.JpegImagePlugin.get_sampling` function. In JPEG compressed data a JPEG marker is used instead of an EXIF tag. -(ref.: https://exiv2.org/tags.html) +(ref.: https://web.archive.org/web/20240227115053/https://exiv2.org/tags.html) Quantization tables diff --git a/venv/Lib/site-packages/PIL/McIdasImagePlugin.py b/venv/Lib/site-packages/PIL/McIdasImagePlugin.py index 9a47933..2797223 100644 --- a/venv/Lib/site-packages/PIL/McIdasImagePlugin.py +++ b/venv/Lib/site-packages/PIL/McIdasImagePlugin.py @@ -23,7 +23,7 @@ from . import Image, ImageFile def _accept(prefix: bytes) -> bool: - return prefix.startswith(b"\x00\x00\x00\x00\x00\x00\x00\x04") + return prefix[:8] == b"\x00\x00\x00\x00\x00\x00\x00\x04" ## @@ -44,13 +44,15 @@ class McIdasImageFile(ImageFile.ImageFile): raise SyntaxError(msg) self.area_descriptor_raw = s - self.area_descriptor = w = [0, *struct.unpack("!64i", s)] + self.area_descriptor = w = [0] + list(struct.unpack("!64i", s)) # get mode if w[11] == 1: mode = rawmode = "L" elif w[11] == 2: - mode = rawmode = "I;16B" + # FIXME: add memory map support + mode = "I" + rawmode = "I;16B" elif w[11] == 4: # FIXME: add memory map support mode = "I" @@ -65,9 +67,7 @@ class McIdasImageFile(ImageFile.ImageFile): offset = w[34] + w[15] stride = w[15] + w[10] * w[11] * w[14] - self.tile = [ - ImageFile._Tile("raw", (0, 0) + self.size, offset, (rawmode, stride, 1)) - ] + self.tile = [("raw", (0, 0) + self.size, offset, (rawmode, stride, 1))] # -------------------------------------------------------------------- diff --git a/venv/Lib/site-packages/PIL/MicImagePlugin.py b/venv/Lib/site-packages/PIL/MicImagePlugin.py index 99a07ba..0723988 100644 --- a/venv/Lib/site-packages/PIL/MicImagePlugin.py +++ b/venv/Lib/site-packages/PIL/MicImagePlugin.py @@ -26,7 +26,7 @@ from . import Image, TiffImagePlugin def _accept(prefix: bytes) -> bool: - return prefix.startswith(olefile.MAGIC) + return prefix[:8] == olefile.MAGIC ## @@ -54,7 +54,7 @@ class MicImageFile(TiffImagePlugin.TiffImageFile): self.images = [ path for path in self.ole.listdir() - if path[1:] and path[0].endswith(".ACI") and path[1] == "Image" + if path[1:] and path[0][-4:] == ".ACI" and path[1] == "Image" ] # if we didn't find any images, this is probably not @@ -67,14 +67,18 @@ class MicImageFile(TiffImagePlugin.TiffImageFile): self._n_frames = len(self.images) self.is_animated = self._n_frames > 1 - assert self.fp is not None self.__fp = self.fp self.seek(0) - def seek(self, frame: int) -> None: + def seek(self, frame): if not self._seek_check(frame): return - filename = self.images[frame] + try: + filename = self.images[frame] + except IndexError as e: + msg = "no such frame" + raise EOFError(msg) from e + self.fp = self.ole.openstream(filename) TiffImagePlugin.TiffImageFile._open(self) diff --git a/venv/Lib/site-packages/PIL/MpegImagePlugin.py b/venv/Lib/site-packages/PIL/MpegImagePlugin.py index 47ebe9d..ad4d3e9 100644 --- a/venv/Lib/site-packages/PIL/MpegImagePlugin.py +++ b/venv/Lib/site-packages/PIL/MpegImagePlugin.py @@ -33,7 +33,11 @@ class BitStream: def peek(self, bits: int) -> int: while self.bits < bits: - self.bitbuffer = (self.bitbuffer << 8) + self.next() + c = self.next() + if c < 0: + self.bits = 0 + continue + self.bitbuffer = (self.bitbuffer << 8) + c self.bits += 8 return self.bitbuffer >> (self.bits - bits) & (1 << bits) - 1 @@ -50,7 +54,7 @@ class BitStream: def _accept(prefix: bytes) -> bool: - return prefix.startswith(b"\x00\x00\x01\xb3") + return prefix[:4] == b"\x00\x00\x01\xb3" ## diff --git a/venv/Lib/site-packages/PIL/MpoImagePlugin.py b/venv/Lib/site-packages/PIL/MpoImagePlugin.py index 9360061..f215706 100644 --- a/venv/Lib/site-packages/PIL/MpoImagePlugin.py +++ b/venv/Lib/site-packages/PIL/MpoImagePlugin.py @@ -19,19 +19,18 @@ # from __future__ import annotations +import itertools import os import struct -from typing import IO, Any, cast +from typing import IO from . import ( Image, - ImageFile, ImageSequence, JpegImagePlugin, TiffImagePlugin, ) from ._binary import o32le -from ._util import DeferredError def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: @@ -46,18 +45,12 @@ def _save_all(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: mpf_offset = 28 offsets: list[int] = [] - im_sequences = [im, *append_images] - total = sum(getattr(seq, "n_frames", 1) for seq in im_sequences) - for im_sequence in im_sequences: - for im_frame in ImageSequence.Iterator(im_sequence): + for imSequence in itertools.chain([im], append_images): + for im_frame in ImageSequence.Iterator(imSequence): if not offsets: # APP2 marker - ifd_length = 66 + 16 * total im_frame.encoderinfo["extra"] = ( - b"\xff\xe2" - + struct.pack(">H", 6 + ifd_length) - + b"MPF\0" - + b" " * ifd_length + b"\xFF\xE2" + struct.pack(">H", 6 + 82) + b"MPF\0" + b" " * 82 ) exif = im_frame.encoderinfo.get("exif") if isinstance(exif, Image.Exif): @@ -69,9 +62,7 @@ def _save_all(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: JpegImagePlugin._save(im_frame, fp, filename) offsets.append(fp.tell()) else: - encoderinfo = im_frame._attach_default_encoderinfo(im) im_frame.save(fp, "JPEG") - im_frame.encoderinfo = encoderinfo offsets.append(fp.tell() - offsets[-1]) ifd = TiffImagePlugin.ImageFileDirectory_v2() @@ -92,7 +83,7 @@ def _save_all(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: ifd[0xB002] = mpentries fp.seek(mpf_offset) - fp.write(b"II\x2a\x00" + o32le(8) + ifd.tobytes(8)) + fp.write(b"II\x2A\x00" + o32le(8) + ifd.tobytes(8)) fp.seek(0, os.SEEK_END) @@ -106,16 +97,12 @@ class MpoImageFile(JpegImagePlugin.JpegImageFile): _close_exclusive_fp_after_loading = False def _open(self) -> None: - assert self.fp is not None self.fp.seek(0) # prep the fp in order to pass the JPEG test JpegImagePlugin.JpegImageFile._open(self) self._after_jpeg_open() - def _after_jpeg_open(self, mpheader: dict[int, Any] | None = None) -> None: + def _after_jpeg_open(self, mpheader=None): self.mpinfo = mpheader if mpheader is not None else self._getmp() - if self.mpinfo is None: - msg = "Image appears to be a malformed MPO file" - raise ValueError(msg) self.n_frames = self.mpinfo[0xB001] self.__mpoffsets = [ mpent["DataOffset"] + self.info["mpoffset"] for mpent in self.mpinfo[0xB002] @@ -126,7 +113,6 @@ class MpoImageFile(JpegImagePlugin.JpegImageFile): assert self.n_frames == len(self.__mpoffsets) del self.info["mpoffset"] # no longer needed self.is_animated = self.n_frames > 1 - assert self.fp is not None self._fp = self.fp # FIXME: hack self._fp.seek(self.__mpoffsets[0]) # get ready to read first frame self.__frame = 0 @@ -135,15 +121,11 @@ class MpoImageFile(JpegImagePlugin.JpegImageFile): self.readonly = 1 def load_seek(self, pos: int) -> None: - if isinstance(self._fp, DeferredError): - raise self._fp.ex self._fp.seek(pos) def seek(self, frame: int) -> None: if not self._seek_check(frame): return - if isinstance(self._fp, DeferredError): - raise self._fp.ex self.fp = self._fp self.offset = self.__mpoffsets[frame] @@ -160,19 +142,14 @@ class MpoImageFile(JpegImagePlugin.JpegImageFile): if self.info.get("exif") != original_exif: self._reload_exif() - self.tile = [ - ImageFile._Tile("jpeg", (0, 0) + self.size, self.offset, self.tile[0][-1]) - ] + self.tile = [("jpeg", (0, 0) + self.size, self.offset, self.tile[0][-1])] self.__frame = frame def tell(self) -> int: return self.__frame @staticmethod - def adopt( - jpeg_instance: JpegImagePlugin.JpegImageFile, - mpheader: dict[int, Any] | None = None, - ) -> MpoImageFile: + def adopt(jpeg_instance, mpheader=None): """ Transform the instance of JpegImageFile into an instance of MpoImageFile. @@ -184,9 +161,8 @@ class MpoImageFile(JpegImagePlugin.JpegImageFile): double call to _open. """ jpeg_instance.__class__ = MpoImageFile - mpo_instance = cast(MpoImageFile, jpeg_instance) - mpo_instance._after_jpeg_open(mpheader) - return mpo_instance + jpeg_instance._after_jpeg_open(mpheader) + return jpeg_instance # --------------------------------------------------------------------- diff --git a/venv/Lib/site-packages/PIL/MspImagePlugin.py b/venv/Lib/site-packages/PIL/MspImagePlugin.py index 277087a..0a75c86 100644 --- a/venv/Lib/site-packages/PIL/MspImagePlugin.py +++ b/venv/Lib/site-packages/PIL/MspImagePlugin.py @@ -37,7 +37,7 @@ from ._binary import o16le as o16 def _accept(prefix: bytes) -> bool: - return prefix.startswith((b"DanM", b"LinS")) + return prefix[:4] in [b"DanM", b"LinS"] ## @@ -69,10 +69,10 @@ class MspImageFile(ImageFile.ImageFile): self._mode = "1" self._size = i16(s, 4), i16(s, 6) - if s.startswith(b"DanM"): - self.tile = [ImageFile._Tile("raw", (0, 0) + self.size, 32, "1")] + if s[:4] == b"DanM": + self.tile = [("raw", (0, 0) + self.size, 32, ("1", 0, 1))] else: - self.tile = [ImageFile._Tile("MSP", (0, 0) + self.size, 32)] + self.tile = [("MSP", (0, 0) + self.size, 32, None)] class MspDecoder(ImageFile.PyDecoder): @@ -112,7 +112,7 @@ class MspDecoder(ImageFile.PyDecoder): _pulls_fd = True - def decode(self, buffer: bytes | Image.SupportsArrayInterface) -> tuple[int, int]: + def decode(self, buffer: bytes) -> tuple[int, int]: assert self.fd is not None img = io.BytesIO() @@ -152,7 +152,7 @@ class MspDecoder(ImageFile.PyDecoder): msg = f"Corrupted MSP file in row {x}" raise OSError(msg) from e - self.set_as_raw(img.getvalue(), "1") + self.set_as_raw(img.getvalue(), ("1", 0, 1)) return -1, 0 @@ -188,7 +188,7 @@ def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: fp.write(o16(h)) # image body - ImageFile._save(im, fp, [ImageFile._Tile("raw", (0, 0) + im.size, 32, "1")]) + ImageFile._save(im, fp, [("raw", (0, 0) + im.size, 32, ("1", 0, 1))]) # diff --git a/venv/Lib/site-packages/PIL/PSDraw.py b/venv/Lib/site-packages/PIL/PSDraw.py index 7fd4c5c..673eae1 100644 --- a/venv/Lib/site-packages/PIL/PSDraw.py +++ b/venv/Lib/site-packages/PIL/PSDraw.py @@ -17,13 +17,10 @@ from __future__ import annotations import sys -from typing import IO +from typing import TYPE_CHECKING from . import EpsImagePlugin -TYPE_CHECKING = False - - ## # Simple PostScript graphics interface. @@ -31,12 +28,15 @@ TYPE_CHECKING = False class PSDraw: """ Sets up printing to the given file. If ``fp`` is omitted, - ``sys.stdout.buffer`` is assumed. + ``sys.stdout.buffer`` or ``sys.stdout`` is assumed. """ - def __init__(self, fp: IO[bytes] | None = None) -> None: + def __init__(self, fp=None): if not fp: - fp = sys.stdout.buffer + try: + fp = sys.stdout.buffer + except AttributeError: + fp = sys.stdout self.fp = fp def begin_document(self, id: str | None = None) -> None: diff --git a/venv/Lib/site-packages/PIL/PaletteFile.py b/venv/Lib/site-packages/PIL/PaletteFile.py index 2a26e5d..81652e5 100644 --- a/venv/Lib/site-packages/PIL/PaletteFile.py +++ b/venv/Lib/site-packages/PIL/PaletteFile.py @@ -32,7 +32,7 @@ class PaletteFile: if not s: break - if s.startswith(b"#"): + if s[:1] == b"#": continue if len(s) > 100: msg = "bad palette file" diff --git a/venv/Lib/site-packages/PIL/PalmImagePlugin.py b/venv/Lib/site-packages/PIL/PalmImagePlugin.py index 15f7129..1735070 100644 --- a/venv/Lib/site-packages/PIL/PalmImagePlugin.py +++ b/venv/Lib/site-packages/PIL/PalmImagePlugin.py @@ -116,6 +116,9 @@ _COMPRESSION_TYPES = {"none": 0xFF, "rle": 0x01, "scanline": 0x00} def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: if im.mode == "P": + # we assume this is a color Palm image with the standard colormap, + # unless the "info" dict has a "custom-colormap" field + rawmode = "P" bpp = 8 version = 1 @@ -169,11 +172,11 @@ def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: compression_type = _COMPRESSION_TYPES["none"] flags = 0 - if im.mode == "P": - flags |= _FLAGS["custom-colormap"] - colormap = im.im.getpalette() - colors = len(colormap) // 3 - colormapsize = 4 * colors + 2 + if im.mode == "P" and "custom-colormap" in im.info: + flags = flags & _FLAGS["custom-colormap"] + colormapsize = 4 * 256 + 2 + colormapmode = im.palette.mode + colormap = im.getdata().getpalette() else: colormapsize = 0 @@ -192,16 +195,25 @@ def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: # now write colormap if necessary - if colormapsize: - fp.write(o16b(colors)) - for i in range(colors): + if colormapsize > 0: + fp.write(o16b(256)) + for i in range(256): fp.write(o8(i)) - fp.write(colormap[3 * i : 3 * i + 3]) + if colormapmode == "RGB": + fp.write( + o8(colormap[3 * i]) + + o8(colormap[3 * i + 1]) + + o8(colormap[3 * i + 2]) + ) + elif colormapmode == "RGBA": + fp.write( + o8(colormap[4 * i]) + + o8(colormap[4 * i + 1]) + + o8(colormap[4 * i + 2]) + ) # now convert data to raw form - ImageFile._save( - im, fp, [ImageFile._Tile("raw", (0, 0) + im.size, 0, (rawmode, rowbytes, 1))] - ) + ImageFile._save(im, fp, [("raw", (0, 0) + im.size, 0, (rawmode, rowbytes, 1))]) if hasattr(fp, "flush"): fp.flush() diff --git a/venv/Lib/site-packages/PIL/PcdImagePlugin.py b/venv/Lib/site-packages/PIL/PcdImagePlugin.py index 296f377..1cd5c4a 100644 --- a/venv/Lib/site-packages/PIL/PcdImagePlugin.py +++ b/venv/Lib/site-packages/PIL/PcdImagePlugin.py @@ -32,9 +32,9 @@ class PcdImageFile(ImageFile.ImageFile): assert self.fp is not None self.fp.seek(2048) - s = self.fp.read(1539) + s = self.fp.read(2048) - if not s.startswith(b"PCD_"): + if s[:4] != b"PCD_": msg = "not a PCD file" raise SyntaxError(msg) @@ -43,21 +43,19 @@ class PcdImageFile(ImageFile.ImageFile): if orientation == 1: self.tile_post_rotate = 90 elif orientation == 3: - self.tile_post_rotate = 270 + self.tile_post_rotate = -90 self._mode = "RGB" - self._size = (512, 768) if orientation in (1, 3) else (768, 512) - self.tile = [ImageFile._Tile("pcd", (0, 0, 768, 512), 96 * 2048)] - - def load_prepare(self) -> None: - if self._im is None and self.tile_post_rotate: - self.im = Image.core.new(self.mode, (768, 512)) - ImageFile.ImageFile.load_prepare(self) + self._size = 768, 512 # FIXME: not correct for rotated images! + self.tile = [("pcd", (0, 0) + self.size, 96 * 2048, None)] def load_end(self) -> None: if self.tile_post_rotate: # Handle rotated PCDs - self.im = self.rotate(self.tile_post_rotate, expand=True).im + assert self.im is not None + + self.im = self.im.rotate(self.tile_post_rotate) + self._size = self.im.size # diff --git a/venv/Lib/site-packages/PIL/PcfFontFile.py b/venv/Lib/site-packages/PIL/PcfFontFile.py index a00e9b9..0d1968b 100644 --- a/venv/Lib/site-packages/PIL/PcfFontFile.py +++ b/venv/Lib/site-packages/PIL/PcfFontFile.py @@ -18,6 +18,7 @@ from __future__ import annotations import io +from typing import BinaryIO, Callable from . import FontFile, Image from ._binary import i8 @@ -26,11 +27,6 @@ from ._binary import i16le as l16 from ._binary import i32be as b32 from ._binary import i32le as l32 -TYPE_CHECKING = False -if TYPE_CHECKING: - from collections.abc import Callable - from typing import BinaryIO - # -------------------------------------------------------------------- # declarations diff --git a/venv/Lib/site-packages/PIL/PcxImagePlugin.py b/venv/Lib/site-packages/PIL/PcxImagePlugin.py index 6b16d53..dd42003 100644 --- a/venv/Lib/site-packages/PIL/PcxImagePlugin.py +++ b/venv/Lib/site-packages/PIL/PcxImagePlugin.py @@ -39,7 +39,7 @@ logger = logging.getLogger(__name__) def _accept(prefix: bytes) -> bool: - return len(prefix) >= 2 and prefix[0] == 10 and prefix[1] in [0, 2, 3, 5] + return prefix[0] == 10 and prefix[1] in [0, 2, 3, 5] ## @@ -54,7 +54,7 @@ class PcxImageFile(ImageFile.ImageFile): # header assert self.fp is not None - s = self.fp.read(68) + s = self.fp.read(128) if not _accept(s): msg = "not a PCX file" raise SyntaxError(msg) @@ -66,8 +66,6 @@ class PcxImageFile(ImageFile.ImageFile): raise SyntaxError(msg) logger.debug("BBox: %s %s %s %s", *bbox) - offset = self.fp.tell() + 60 - # format version = s[1] bits = s[3] @@ -88,7 +86,7 @@ class PcxImageFile(ImageFile.ImageFile): elif bits == 1 and planes in (2, 4): mode = "P" - rawmode = f"P;{planes}L" + rawmode = "P;%dL" % planes self.palette = ImagePalette.raw("RGB", s[16:64]) elif version == 5 and bits == 8 and planes == 1: @@ -104,6 +102,7 @@ class PcxImageFile(ImageFile.ImageFile): break if mode == "P": self.palette = ImagePalette.raw("RGB", s[1:]) + self.fp.seek(128) elif version == 5 and bits == 8 and planes == 3: mode = "RGB" @@ -129,7 +128,7 @@ class PcxImageFile(ImageFile.ImageFile): bbox = (0, 0) + self.size logger.debug("size: %sx%s", *self.size) - self.tile = [ImageFile._Tile("pcx", bbox, offset, (rawmode, planes * stride))] + self.tile = [("pcx", bbox, self.fp.tell(), (rawmode, planes * stride))] # -------------------------------------------------------------------- @@ -187,7 +186,7 @@ def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: + o16(dpi[0]) + o16(dpi[1]) + b"\0" * 24 - + b"\xff" * 24 + + b"\xFF" * 24 + b"\0" + o8(planes) + o16(stride) @@ -199,12 +198,12 @@ def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: assert fp.tell() == 128 - ImageFile._save( - im, fp, [ImageFile._Tile("pcx", (0, 0) + im.size, 0, (rawmode, bits * planes))] - ) + ImageFile._save(im, fp, [("pcx", (0, 0) + im.size, 0, (rawmode, bits * planes))]) if im.mode == "P": # colour palette + assert im.im is not None + fp.write(o8(12)) palette = im.im.getpalette("RGB", "RGB") palette += b"\x00" * (768 - len(palette)) diff --git a/venv/Lib/site-packages/PIL/PdfImagePlugin.py b/venv/Lib/site-packages/PIL/PdfImagePlugin.py index 5594c7e..f0da1e0 100644 --- a/venv/Lib/site-packages/PIL/PdfImagePlugin.py +++ b/venv/Lib/site-packages/PIL/PdfImagePlugin.py @@ -25,9 +25,9 @@ import io import math import os import time -from typing import IO, Any +from typing import IO -from . import Image, ImageFile, ImageSequence, PdfParser, features +from . import Image, ImageFile, ImageSequence, PdfParser, __version__, features # # -------------------------------------------------------------------- @@ -48,12 +48,7 @@ def _save_all(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: # (Internal) Image save plugin for the PDF format. -def _write_image( - im: Image.Image, - filename: str | bytes, - existing_pdf: PdfParser.PdfParser, - image_refs: list[PdfParser.IndirectReference], -) -> tuple[PdfParser.IndirectReference, str]: +def _write_image(im, filename, existing_pdf, image_refs): # FIXME: Should replace ASCIIHexDecode with RunLengthDecode # (packbits) or LZWDecode (tiff/lzw compression). Note that # PDF 1.2 also supports Flatedecode (zip compression). @@ -66,10 +61,10 @@ def _write_image( width, height = im.size - dict_obj: dict[str, Any] = {"BitsPerComponent": 8} + dict_obj = {"BitsPerComponent": 8} if im.mode == "1": if features.check("libtiff"): - decode_filter = "CCITTFaxDecode" + filter = "CCITTFaxDecode" dict_obj["BitsPerComponent"] = 1 params = PdfParser.PdfArray( [ @@ -84,23 +79,22 @@ def _write_image( ] ) else: - decode_filter = "DCTDecode" + filter = "DCTDecode" dict_obj["ColorSpace"] = PdfParser.PdfName("DeviceGray") procset = "ImageB" # grayscale elif im.mode == "L": - decode_filter = "DCTDecode" + filter = "DCTDecode" # params = f"<< /Predictor 15 /Columns {width-2} >>" dict_obj["ColorSpace"] = PdfParser.PdfName("DeviceGray") procset = "ImageB" # grayscale elif im.mode == "LA": - decode_filter = "JPXDecode" + filter = "JPXDecode" # params = f"<< /Predictor 15 /Columns {width-2} >>" procset = "ImageB" # grayscale dict_obj["SMaskInData"] = 1 elif im.mode == "P": - decode_filter = "ASCIIHexDecode" + filter = "ASCIIHexDecode" palette = im.getpalette() - assert palette is not None dict_obj["ColorSpace"] = [ PdfParser.PdfName("Indexed"), PdfParser.PdfName("DeviceRGB"), @@ -116,15 +110,15 @@ def _write_image( image_ref = _write_image(smask, filename, existing_pdf, image_refs)[0] dict_obj["SMask"] = image_ref elif im.mode == "RGB": - decode_filter = "DCTDecode" + filter = "DCTDecode" dict_obj["ColorSpace"] = PdfParser.PdfName("DeviceRGB") procset = "ImageC" # color images elif im.mode == "RGBA": - decode_filter = "JPXDecode" + filter = "JPXDecode" procset = "ImageC" # color images dict_obj["SMaskInData"] = 1 elif im.mode == "CMYK": - decode_filter = "DCTDecode" + filter = "DCTDecode" dict_obj["ColorSpace"] = PdfParser.PdfName("DeviceCMYK") procset = "ImageC" # color images decode = [1, 0, 1, 0, 1, 0, 1, 0] @@ -137,9 +131,9 @@ def _write_image( op = io.BytesIO() - if decode_filter == "ASCIIHexDecode": - ImageFile._save(im, op, [ImageFile._Tile("hex", (0, 0) + im.size, 0, im.mode)]) - elif decode_filter == "CCITTFaxDecode": + if filter == "ASCIIHexDecode": + ImageFile._save(im, op, [("hex", (0, 0) + im.size, 0, im.mode)]) + elif filter == "CCITTFaxDecode": im.save( op, "TIFF", @@ -147,22 +141,21 @@ def _write_image( # use a single strip strip_size=math.ceil(width / 8) * height, ) - elif decode_filter == "DCTDecode": + elif filter == "DCTDecode": Image.SAVE["JPEG"](im, op, filename) - elif decode_filter == "JPXDecode": + elif filter == "JPXDecode": del dict_obj["BitsPerComponent"] Image.SAVE["JPEG2000"](im, op, filename) else: - msg = f"unsupported PDF filter ({decode_filter})" + msg = f"unsupported PDF filter ({filter})" raise ValueError(msg) stream = op.getvalue() - filter: PdfParser.PdfArray | PdfParser.PdfName - if decode_filter == "CCITTFaxDecode": + if filter == "CCITTFaxDecode": stream = stream[8:] - filter = PdfParser.PdfArray([PdfParser.PdfName(decode_filter)]) + filter = PdfParser.PdfArray([PdfParser.PdfName(filter)]) else: - filter = PdfParser.PdfName(decode_filter) + filter = PdfParser.PdfName(filter) image_ref = image_refs.pop(0) existing_pdf.write_obj( @@ -181,15 +174,12 @@ def _write_image( return image_ref, procset -def _save( - im: Image.Image, fp: IO[bytes], filename: str | bytes, save_all: bool = False -) -> None: +def _save(im, fp, filename, save_all=False): is_appending = im.encoderinfo.get("append", False) - filename_str = filename.decode() if isinstance(filename, bytes) else filename if is_appending: - existing_pdf = PdfParser.PdfParser(f=fp, filename=filename_str, mode="r+b") + existing_pdf = PdfParser.PdfParser(f=fp, filename=filename, mode="r+b") else: - existing_pdf = PdfParser.PdfParser(f=fp, filename=filename_str, mode="w+b") + existing_pdf = PdfParser.PdfParser(f=fp, filename=filename, mode="w+b") dpi = im.encoderinfo.get("dpi") if dpi: @@ -221,7 +211,7 @@ def _save( existing_pdf.start_writing() existing_pdf.write_header() - existing_pdf.write_comment("created by Pillow PDF driver") + existing_pdf.write_comment(f"created by Pillow {__version__} PDF driver") # # pages @@ -238,7 +228,12 @@ def _save( for im in ims: im_number_of_pages = 1 if save_all: - im_number_of_pages = getattr(im, "n_frames", 1) + try: + im_number_of_pages = im.n_frames + except AttributeError: + # Image format does not have n_frames. + # It is a single frame image + pass number_of_pages += im_number_of_pages for i in range(im_number_of_pages): image_refs.append(existing_pdf.next_object_id(0)) @@ -255,9 +250,7 @@ def _save( page_number = 0 for im_sequence in ims: - im_pages: ImageSequence.Iterator | list[Image.Image] = ( - ImageSequence.Iterator(im_sequence) if save_all else [im_sequence] - ) + im_pages = ImageSequence.Iterator(im_sequence) if save_all else [im_sequence] for im in im_pages: image_ref, procset = _write_image(im, filename, existing_pdf, image_refs) diff --git a/venv/Lib/site-packages/PIL/PdfParser.py b/venv/Lib/site-packages/PIL/PdfParser.py index 2c90314..9e22313 100644 --- a/venv/Lib/site-packages/PIL/PdfParser.py +++ b/venv/Lib/site-packages/PIL/PdfParser.py @@ -8,15 +8,7 @@ import os import re import time import zlib -from typing import Any, NamedTuple - -TYPE_CHECKING = False -if TYPE_CHECKING: - from typing import IO - - _DictBase = collections.UserDict[str | bytes, Any] -else: - _DictBase = collections.UserDict +from typing import TYPE_CHECKING, Any, List, NamedTuple, Union # see 7.9.2.2 Text String Type on page 86 and D.3 PDFDocEncoding Character Set @@ -27,14 +19,14 @@ def encode_text(s: str) -> bytes: PDFDocEncoding = { 0x16: "\u0017", - 0x18: "\u02d8", - 0x19: "\u02c7", - 0x1A: "\u02c6", - 0x1B: "\u02d9", - 0x1C: "\u02dd", - 0x1D: "\u02db", - 0x1E: "\u02da", - 0x1F: "\u02dc", + 0x18: "\u02D8", + 0x19: "\u02C7", + 0x1A: "\u02C6", + 0x1B: "\u02D9", + 0x1C: "\u02DD", + 0x1D: "\u02DB", + 0x1E: "\u02DA", + 0x1F: "\u02DC", 0x80: "\u2022", 0x81: "\u2020", 0x82: "\u2021", @@ -44,33 +36,33 @@ PDFDocEncoding = { 0x86: "\u0192", 0x87: "\u2044", 0x88: "\u2039", - 0x89: "\u203a", + 0x89: "\u203A", 0x8A: "\u2212", 0x8B: "\u2030", - 0x8C: "\u201e", - 0x8D: "\u201c", - 0x8E: "\u201d", + 0x8C: "\u201E", + 0x8D: "\u201C", + 0x8E: "\u201D", 0x8F: "\u2018", 0x90: "\u2019", - 0x91: "\u201a", + 0x91: "\u201A", 0x92: "\u2122", - 0x93: "\ufb01", - 0x94: "\ufb02", + 0x93: "\uFB01", + 0x94: "\uFB02", 0x95: "\u0141", 0x96: "\u0152", 0x97: "\u0160", 0x98: "\u0178", - 0x99: "\u017d", + 0x99: "\u017D", 0x9A: "\u0131", 0x9B: "\u0142", 0x9C: "\u0153", 0x9D: "\u0161", - 0x9E: "\u017e", - 0xA0: "\u20ac", + 0x9E: "\u017E", + 0xA0: "\u20AC", } -def decode_text(b: bytes) -> str: +def decode_text(b): if b[: len(codecs.BOM_UTF16_BE)] == codecs.BOM_UTF16_BE: return b[len(codecs.BOM_UTF16_BE) :].decode("utf_16_be") else: @@ -107,7 +99,7 @@ class IndirectReference(IndirectReferenceTuple): assert isinstance(other, IndirectReference) return other.object_id == self.object_id and other.generation == self.generation - def __ne__(self, other: object) -> bool: + def __ne__(self, other): return not (self == other) def __hash__(self) -> int: @@ -120,17 +112,13 @@ class IndirectObjectDef(IndirectReference): class XrefTable: - def __init__(self) -> None: - self.existing_entries: dict[int, tuple[int, int]] = ( - {} - ) # object ID => (offset, generation) - self.new_entries: dict[int, tuple[int, int]] = ( - {} - ) # object ID => (offset, generation) + def __init__(self): + self.existing_entries = {} # object ID => (offset, generation) + self.new_entries = {} # object ID => (offset, generation) self.deleted_entries = {0: 65536} # object ID => generation self.reading_finished = False - def __setitem__(self, key: int, value: tuple[int, int]) -> None: + def __setitem__(self, key, value): if self.reading_finished: self.new_entries[key] = value else: @@ -138,13 +126,13 @@ class XrefTable: if key in self.deleted_entries: del self.deleted_entries[key] - def __getitem__(self, key: int) -> tuple[int, int]: + def __getitem__(self, key): try: return self.new_entries[key] except KeyError: return self.existing_entries[key] - def __delitem__(self, key: int) -> None: + def __delitem__(self, key): if key in self.new_entries: generation = self.new_entries[key][1] + 1 del self.new_entries[key] @@ -158,7 +146,7 @@ class XrefTable: msg = f"object ID {key} cannot be deleted because it doesn't exist" raise IndexError(msg) - def __contains__(self, key: int) -> bool: + def __contains__(self, key): return key in self.existing_entries or key in self.new_entries def __len__(self) -> int: @@ -168,19 +156,19 @@ class XrefTable: | set(self.deleted_entries.keys()) ) - def keys(self) -> set[int]: + def keys(self): return ( set(self.existing_entries.keys()) - set(self.deleted_entries.keys()) ) | set(self.new_entries.keys()) - def write(self, f: IO[bytes]) -> int: + def write(self, f): keys = sorted(set(self.new_entries.keys()) | set(self.deleted_entries.keys())) deleted_keys = sorted(set(self.deleted_entries.keys())) startxref = f.tell() f.write(b"xref\n") while keys: # find a contiguous sequence of object IDs - prev: int | None = None + prev = None for index, key in enumerate(keys): if prev is None or prev + 1 == key: prev = key @@ -190,7 +178,7 @@ class XrefTable: break else: contiguous_keys = keys - keys = [] + keys = None f.write(b"%d %d\n" % (contiguous_keys[0], len(contiguous_keys))) for object_id in contiguous_keys: if object_id in self.new_entries: @@ -214,9 +202,7 @@ class XrefTable: class PdfName: - name: bytes - - def __init__(self, name: PdfName | bytes | str) -> None: + def __init__(self, name): if isinstance(name, PdfName): self.name = name.name elif isinstance(name, bytes): @@ -227,7 +213,7 @@ class PdfName: def name_as_str(self) -> str: return self.name.decode("us-ascii") - def __eq__(self, other: object) -> bool: + def __eq__(self, other): return ( isinstance(other, PdfName) and other.name == self.name ) or other == self.name @@ -239,7 +225,7 @@ class PdfName: return f"{self.__class__.__name__}({repr(self.name)})" @classmethod - def from_pdf_stream(cls, data: bytes) -> PdfName: + def from_pdf_stream(cls, data): return cls(PdfParser.interpret_name(data)) allowed_chars = set(range(33, 127)) - {ord(c) for c in "#%/()<>[]{}"} @@ -254,19 +240,25 @@ class PdfName: return bytes(result) -class PdfArray(list[Any]): +class PdfArray(List[Any]): def __bytes__(self) -> bytes: return b"[ " + b" ".join(pdf_repr(x) for x in self) + b" ]" +if TYPE_CHECKING: + _DictBase = collections.UserDict[Union[str, bytes], Any] +else: + _DictBase = collections.UserDict + + class PdfDict(_DictBase): - def __setattr__(self, key: str, value: Any) -> None: + def __setattr__(self, key, value): if key == "data": collections.UserDict.__setattr__(self, key, value) else: self[key.encode("us-ascii")] = value - def __getattr__(self, key: str) -> str | time.struct_time: + def __getattr__(self, key): try: value = self[key.encode("us-ascii")] except KeyError as e: @@ -308,7 +300,7 @@ class PdfDict(_DictBase): class PdfBinary: - def __init__(self, data: list[int] | bytes) -> None: + def __init__(self, data): self.data = data def __bytes__(self) -> bytes: @@ -316,27 +308,27 @@ class PdfBinary: class PdfStream: - def __init__(self, dictionary: PdfDict, buf: bytes) -> None: + def __init__(self, dictionary, buf): self.dictionary = dictionary self.buf = buf - def decode(self) -> bytes: + def decode(self): try: - filter = self.dictionary[b"Filter"] - except KeyError: + filter = self.dictionary.Filter + except AttributeError: return self.buf if filter == b"FlateDecode": try: - expected_length = self.dictionary[b"DL"] - except KeyError: - expected_length = self.dictionary[b"Length"] + expected_length = self.dictionary.DL + except AttributeError: + expected_length = self.dictionary.Length return zlib.decompress(self.buf, bufsize=int(expected_length)) else: - msg = f"stream filter {repr(filter)} unknown/unsupported" + msg = f"stream filter {repr(self.dictionary.Filter)} unknown/unsupported" raise NotImplementedError(msg) -def pdf_repr(x: Any) -> bytes: +def pdf_repr(x): if x is True: return b"true" elif x is False: @@ -371,19 +363,12 @@ class PdfParser: Supports PDF up to 1.4 """ - def __init__( - self, - filename: str | None = None, - f: IO[bytes] | None = None, - buf: bytes | bytearray | None = None, - start_offset: int = 0, - mode: str = "rb", - ) -> None: + def __init__(self, filename=None, f=None, buf=None, start_offset=0, mode="rb"): if buf and f: msg = "specify buf or f or filename, but not both buf and f" raise RuntimeError(msg) self.filename = filename - self.buf: bytes | bytearray | mmap.mmap | None = buf + self.buf = buf self.f = f self.start_offset = start_offset self.should_close_buf = False @@ -392,16 +377,12 @@ class PdfParser: self.f = f = open(filename, mode) self.should_close_file = True if f is not None: - self.buf = self.get_buf_from_file(f) + self.buf = buf = self.get_buf_from_file(f) self.should_close_buf = True if not filename and hasattr(f, "name"): self.filename = f.name - self.cached_objects: dict[IndirectReference, Any] = {} - self.root_ref: IndirectReference | None - self.info_ref: IndirectReference | None - self.pages_ref: IndirectReference | None - self.last_xref_section_offset: int | None - if self.buf: + self.cached_objects = {} + if buf: self.read_pdf_info() else: self.file_size_total = self.file_size_this = 0 @@ -409,12 +390,12 @@ class PdfParser: self.root_ref = None self.info = PdfDict() self.info_ref = None - self.page_tree_root = PdfDict() - self.pages: list[IndirectReference] = [] - self.orig_pages: list[IndirectReference] = [] + self.page_tree_root = {} + self.pages = [] + self.orig_pages = [] self.pages_ref = None self.last_xref_section_offset = None - self.trailer_dict: dict[bytes, Any] = {} + self.trailer_dict = {} self.xref_table = XrefTable() self.xref_table.reading_finished = True if f: @@ -431,8 +412,10 @@ class PdfParser: self.seek_end() def close_buf(self) -> None: - if isinstance(self.buf, mmap.mmap): + try: self.buf.close() + except AttributeError: + pass self.buf = None def close(self) -> None: @@ -443,19 +426,15 @@ class PdfParser: self.f = None def seek_end(self) -> None: - assert self.f is not None self.f.seek(0, os.SEEK_END) def write_header(self) -> None: - assert self.f is not None self.f.write(b"%PDF-1.4\n") - def write_comment(self, s: str) -> None: - assert self.f is not None + def write_comment(self, s): self.f.write(f"% {s}\n".encode()) def write_catalog(self) -> IndirectReference: - assert self.f is not None self.del_root() self.root_ref = self.next_object_id(self.f.tell()) self.pages_ref = self.next_object_id(0) @@ -498,10 +477,7 @@ class PdfParser: pages_tree_node_ref = pages_tree_node.get(b"Parent", None) self.orig_pages = [] - def write_xref_and_trailer( - self, new_root_ref: IndirectReference | None = None - ) -> None: - assert self.f is not None + def write_xref_and_trailer(self, new_root_ref=None): if new_root_ref: self.del_root() self.root_ref = new_root_ref @@ -509,10 +485,7 @@ class PdfParser: self.info_ref = self.write_obj(None, self.info) start_xref = self.xref_table.write(self.f) num_entries = len(self.xref_table) - trailer_dict: dict[str | bytes, Any] = { - b"Root": self.root_ref, - b"Size": num_entries, - } + trailer_dict = {b"Root": self.root_ref, b"Size": num_entries} if self.last_xref_section_offset is not None: trailer_dict[b"Prev"] = self.last_xref_section_offset if self.info: @@ -524,20 +497,16 @@ class PdfParser: + b"\nstartxref\n%d\n%%%%EOF" % start_xref ) - def write_page( - self, ref: int | IndirectReference | None, *objs: Any, **dict_obj: Any - ) -> IndirectReference: - obj_ref = self.pages[ref] if isinstance(ref, int) else ref + def write_page(self, ref, *objs, **dict_obj): + if isinstance(ref, int): + ref = self.pages[ref] if "Type" not in dict_obj: dict_obj["Type"] = PdfName(b"Page") if "Parent" not in dict_obj: dict_obj["Parent"] = self.pages_ref - return self.write_obj(obj_ref, *objs, **dict_obj) + return self.write_obj(ref, *objs, **dict_obj) - def write_obj( - self, ref: IndirectReference | None, *objs: Any, **dict_obj: Any - ) -> IndirectReference: - assert self.f is not None + def write_obj(self, ref, *objs, **dict_obj): f = self.f if ref is None: ref = self.next_object_id(f.tell()) @@ -565,7 +534,7 @@ class PdfParser: del self.xref_table[self.root[b"Pages"].object_id] @staticmethod - def get_buf_from_file(f: IO[bytes]) -> bytes | mmap.mmap: + def get_buf_from_file(f): if hasattr(f, "getbuffer"): return f.getbuffer() elif hasattr(f, "getvalue"): @@ -577,15 +546,10 @@ class PdfParser: return b"" def read_pdf_info(self) -> None: - assert self.buf is not None self.file_size_total = len(self.buf) self.file_size_this = self.file_size_total - self.start_offset self.read_trailer() - check_format_condition( - self.trailer_dict.get(b"Root") is not None, "Root is missing" - ) self.root_ref = self.trailer_dict[b"Root"] - assert self.root_ref is not None self.info_ref = self.trailer_dict.get(b"Info", None) self.root = PdfDict(self.read_indirect(self.root_ref)) if self.info_ref is None: @@ -596,15 +560,12 @@ class PdfParser: check_format_condition( self.root[b"Type"] == b"Catalog", "/Type in Root is not /Catalog" ) - check_format_condition( - self.root.get(b"Pages") is not None, "/Pages missing in Root" - ) + check_format_condition(b"Pages" in self.root, "/Pages missing in Root") check_format_condition( isinstance(self.root[b"Pages"], IndirectReference), "/Pages in Root is not an indirect reference", ) self.pages_ref = self.root[b"Pages"] - assert self.pages_ref is not None self.page_tree_root = self.read_indirect(self.pages_ref) self.pages = self.linearize_page_tree(self.page_tree_root) # save the original list of page references @@ -612,7 +573,7 @@ class PdfParser: # and we need to rewrite the pages and their list self.orig_pages = self.pages[:] - def next_object_id(self, offset: int | None = None) -> IndirectReference: + def next_object_id(self, offset=None): try: # TODO: support reuse of deleted objects reference = IndirectReference(max(self.xref_table.keys()) + 1, 0) @@ -662,13 +623,12 @@ class PdfParser: re.DOTALL, ) - def read_trailer(self) -> None: - assert self.buf is not None + def read_trailer(self): search_start_offset = len(self.buf) - 16384 if search_start_offset < self.start_offset: search_start_offset = self.start_offset m = self.re_trailer_end.search(self.buf, search_start_offset) - check_format_condition(m is not None, "trailer end not found") + check_format_condition(m, "trailer end not found") # make sure we found the LAST trailer last_match = m while m: @@ -676,7 +636,6 @@ class PdfParser: m = self.re_trailer_end.search(self.buf, m.start() + 16) if not m: m = last_match - assert m is not None trailer_data = m.group(1) self.last_xref_section_offset = int(m.group(2)) self.trailer_dict = self.interpret_trailer(trailer_data) @@ -685,14 +644,12 @@ class PdfParser: if b"Prev" in self.trailer_dict: self.read_prev_trailer(self.trailer_dict[b"Prev"]) - def read_prev_trailer(self, xref_section_offset: int) -> None: - assert self.buf is not None + def read_prev_trailer(self, xref_section_offset): trailer_offset = self.read_xref_table(xref_section_offset=xref_section_offset) m = self.re_trailer_prev.search( self.buf[trailer_offset : trailer_offset + 16384] ) - check_format_condition(m is not None, "previous trailer not found") - assert m is not None + check_format_condition(m, "previous trailer not found") trailer_data = m.group(1) check_format_condition( int(m.group(2)) == xref_section_offset, @@ -713,7 +670,7 @@ class PdfParser: re_dict_end = re.compile(whitespace_optional + rb">>" + whitespace_optional) @classmethod - def interpret_trailer(cls, trailer_data: bytes) -> dict[bytes, Any]: + def interpret_trailer(cls, trailer_data): trailer = {} offset = 0 while True: @@ -721,18 +678,14 @@ class PdfParser: if not m: m = cls.re_dict_end.match(trailer_data, offset) check_format_condition( - m is not None and m.end() == len(trailer_data), + m and m.end() == len(trailer_data), "name not found in trailer, remaining data: " + repr(trailer_data[offset:]), ) break key = cls.interpret_name(m.group(1)) - assert isinstance(key, bytes) - value, value_offset = cls.get_value(trailer_data, m.end()) + value, offset = cls.get_value(trailer_data, m.end()) trailer[key] = value - if value_offset is None: - break - offset = value_offset check_format_condition( b"Size" in trailer and isinstance(trailer[b"Size"], int), "/Size not in trailer or not an integer", @@ -746,7 +699,7 @@ class PdfParser: re_hashes_in_name = re.compile(rb"([^#]*)(#([0-9a-fA-F]{2}))?") @classmethod - def interpret_name(cls, raw: bytes, as_text: bool = False) -> str | bytes: + def interpret_name(cls, raw, as_text=False): name = b"" for m in cls.re_hashes_in_name.finditer(raw): if m.group(3): @@ -808,13 +761,7 @@ class PdfParser: ) @classmethod - def get_value( - cls, - data: bytes | bytearray | mmap.mmap, - offset: int, - expect_indirect: IndirectReference | None = None, - max_nesting: int = -1, - ) -> tuple[Any, int | None]: + def get_value(cls, data, offset, expect_indirect=None, max_nesting=-1): if max_nesting == 0: return None, None m = cls.re_comment.match(data, offset) @@ -836,16 +783,11 @@ class PdfParser: == IndirectReference(int(m.group(1)), int(m.group(2))), "indirect object definition different than expected", ) - object, object_offset = cls.get_value( - data, m.end(), max_nesting=max_nesting - 1 - ) - if object_offset is None: + object, offset = cls.get_value(data, m.end(), max_nesting=max_nesting - 1) + if offset is None: return object, None - m = cls.re_indirect_def_end.match(data, object_offset) - check_format_condition( - m is not None, "indirect object definition end not found" - ) - assert m is not None + m = cls.re_indirect_def_end.match(data, offset) + check_format_condition(m, "indirect object definition end not found") return object, m.end() check_format_condition( not expect_indirect, "indirect object definition not found" @@ -864,53 +806,46 @@ class PdfParser: m = cls.re_dict_start.match(data, offset) if m: offset = m.end() - result: dict[Any, Any] = {} + result = {} m = cls.re_dict_end.match(data, offset) - current_offset: int | None = offset while not m: - assert current_offset is not None - key, current_offset = cls.get_value( - data, current_offset, max_nesting=max_nesting - 1 - ) - if current_offset is None: + key, offset = cls.get_value(data, offset, max_nesting=max_nesting - 1) + if offset is None: return result, None - value, current_offset = cls.get_value( - data, current_offset, max_nesting=max_nesting - 1 - ) + value, offset = cls.get_value(data, offset, max_nesting=max_nesting - 1) result[key] = value - if current_offset is None: + if offset is None: return result, None - m = cls.re_dict_end.match(data, current_offset) - current_offset = m.end() - m = cls.re_stream_start.match(data, current_offset) + m = cls.re_dict_end.match(data, offset) + offset = m.end() + m = cls.re_stream_start.match(data, offset) if m: - stream_len = result.get(b"Length") - if stream_len is None or not isinstance(stream_len, int): - msg = f"bad or missing Length in stream dict ({stream_len})" - raise PdfFormatError(msg) + try: + stream_len_str = result.get(b"Length") + stream_len = int(stream_len_str) + except (TypeError, ValueError) as e: + msg = f"bad or missing Length in stream dict ({stream_len_str})" + raise PdfFormatError(msg) from e stream_data = data[m.end() : m.end() + stream_len] m = cls.re_stream_end.match(data, m.end() + stream_len) - check_format_condition(m is not None, "stream end not found") - assert m is not None - current_offset = m.end() - return PdfStream(PdfDict(result), stream_data), current_offset - return PdfDict(result), current_offset + check_format_condition(m, "stream end not found") + offset = m.end() + result = PdfStream(PdfDict(result), stream_data) + else: + result = PdfDict(result) + return result, offset m = cls.re_array_start.match(data, offset) if m: offset = m.end() - results = [] + result = [] m = cls.re_array_end.match(data, offset) - current_offset = offset while not m: - assert current_offset is not None - value, current_offset = cls.get_value( - data, current_offset, max_nesting=max_nesting - 1 - ) - results.append(value) - if current_offset is None: - return results, None - m = cls.re_array_end.match(data, current_offset) - return results, m.end() + value, offset = cls.get_value(data, offset, max_nesting=max_nesting - 1) + result.append(value) + if offset is None: + return result, None + m = cls.re_array_end.match(data, offset) + return result, m.end() m = cls.re_null.match(data, offset) if m: return None, m.end() @@ -970,9 +905,7 @@ class PdfParser: } @classmethod - def get_literal_string( - cls, data: bytes | bytearray | mmap.mmap, offset: int - ) -> tuple[bytes, int]: + def get_literal_string(cls, data, offset): nesting_depth = 0 result = bytearray() for m in cls.re_lit_str_token.finditer(data, offset): @@ -1008,14 +941,12 @@ class PdfParser: ) re_xref_entry = re.compile(rb"([0-9]{10}) ([0-9]{5}) ([fn])( \r| \n|\r\n)") - def read_xref_table(self, xref_section_offset: int) -> int: - assert self.buf is not None + def read_xref_table(self, xref_section_offset): subsection_found = False m = self.re_xref_section_start.match( self.buf, xref_section_offset + self.start_offset ) - check_format_condition(m is not None, "xref section start not found") - assert m is not None + check_format_condition(m, "xref section start not found") offset = m.end() while True: m = self.re_xref_subsection_start.match(self.buf, offset) @@ -1030,8 +961,7 @@ class PdfParser: num_objects = int(m.group(2)) for i in range(first_object, first_object + num_objects): m = self.re_xref_entry.match(self.buf, offset) - check_format_condition(m is not None, "xref entry not found") - assert m is not None + check_format_condition(m, "xref entry not found") offset = m.end() is_free = m.group(3) == b"f" if not is_free: @@ -1041,14 +971,13 @@ class PdfParser: self.xref_table[i] = new_entry return offset - def read_indirect(self, ref: IndirectReference, max_nesting: int = -1) -> Any: + def read_indirect(self, ref, max_nesting=-1): offset, generation = self.xref_table[ref[0]] check_format_condition( generation == ref[1], f"expected to find generation {ref[1]} for object ID {ref[0]} in xref " f"table, instead found generation {generation} at offset {offset}", ) - assert self.buf is not None value = self.get_value( self.buf, offset + self.start_offset, @@ -1058,15 +987,14 @@ class PdfParser: self.cached_objects[ref] = value return value - def linearize_page_tree( - self, node: PdfDict | None = None - ) -> list[IndirectReference]: - page_node = node if node is not None else self.page_tree_root + def linearize_page_tree(self, node=None): + if node is None: + node = self.page_tree_root check_format_condition( - page_node[b"Type"] == b"Pages", "/Type of page tree node is not /Pages" + node[b"Type"] == b"Pages", "/Type of page tree node is not /Pages" ) pages = [] - for kid in page_node[b"Kids"]: + for kid in node[b"Kids"]: kid_object = self.read_indirect(kid) if kid_object[b"Type"] == b"Page": pages.append(kid) diff --git a/venv/Lib/site-packages/PIL/PixarImagePlugin.py b/venv/Lib/site-packages/PIL/PixarImagePlugin.py index d2b6d0a..887b656 100644 --- a/venv/Lib/site-packages/PIL/PixarImagePlugin.py +++ b/venv/Lib/site-packages/PIL/PixarImagePlugin.py @@ -28,7 +28,7 @@ from ._binary import i16le as i16 def _accept(prefix: bytes) -> bool: - return prefix.startswith(b"\200\350\000\000") + return prefix[:4] == b"\200\350\000\000" ## @@ -61,7 +61,7 @@ class PixarImageFile(ImageFile.ImageFile): # FIXME: to be continued... # create tile descriptor (assuming "dumped") - self.tile = [ImageFile._Tile("raw", (0, 0) + self.size, 1024, self.mode)] + self.tile = [("raw", (0, 0) + self.size, 1024, (self.mode, 0, 1))] # diff --git a/venv/Lib/site-packages/PIL/PngImagePlugin.py b/venv/Lib/site-packages/PIL/PngImagePlugin.py index 9826a4c..d283492 100644 --- a/venv/Lib/site-packages/PIL/PngImagePlugin.py +++ b/venv/Lib/site-packages/PIL/PngImagePlugin.py @@ -39,8 +39,7 @@ import struct import warnings import zlib from enum import IntEnum -from fractions import Fraction -from typing import IO, NamedTuple, cast +from typing import IO, TYPE_CHECKING, Any, NoReturn from . import Image, ImageChops, ImageFile, ImagePalette, ImageSequence from ._binary import i16be as i16 @@ -48,14 +47,8 @@ from ._binary import i32be as i32 from ._binary import o8 from ._binary import o16be as o16 from ._binary import o32be as o32 -from ._deprecate import deprecate -from ._util import DeferredError -TYPE_CHECKING = False if TYPE_CHECKING: - from collections.abc import Callable - from typing import Any, NoReturn - from . import _imaging logger = logging.getLogger(__name__) @@ -142,16 +135,16 @@ class Blend(IntEnum): """ -def _safe_zlib_decompress(s: bytes) -> bytes: +def _safe_zlib_decompress(s): dobj = zlib.decompressobj() plaintext = dobj.decompress(s, MAX_TEXT_CHUNK) if dobj.unconsumed_tail: - msg = "Decompressed data too large for PngImagePlugin.MAX_TEXT_CHUNK" + msg = "Decompressed Data Too Large" raise ValueError(msg) return plaintext -def _crc32(data: bytes, seed: int = 0) -> int: +def _crc32(data, seed=0): return zlib.crc32(data, seed) & 0xFFFFFFFF @@ -198,7 +191,7 @@ class ChunkStream: assert self.queue is not None self.queue.append((cid, pos, length)) - def call(self, cid: bytes, pos: int, length: int) -> bytes: + def call(self, cid, pos, length): """Call the appropriate chunk handler""" logger.debug("STREAM %r %s %s", cid, pos, length) @@ -237,7 +230,6 @@ class ChunkStream: cids = [] - assert self.fp is not None while True: try: cid, pos, length = self.read() @@ -264,9 +256,7 @@ class iTXt(str): tkey: str | bytes | None @staticmethod - def __new__( - cls, text: str, lang: str | None = None, tkey: str | None = None - ) -> iTXt: + def __new__(cls, text, lang=None, tkey=None): """ :param cls: the class to use when creating the instance :param text: value for this key @@ -376,27 +366,21 @@ class PngInfo: # PNG image stream (IHDR/IEND) -class _RewindState(NamedTuple): - info: dict[str | tuple[int, int], Any] - tile: list[ImageFile._Tile] - seq_num: int | None - - class PngStream(ChunkStream): - def __init__(self, fp: IO[bytes]) -> None: + def __init__(self, fp): super().__init__(fp) # local copies of Image attributes - self.im_info: dict[str | tuple[int, int], Any] = {} - self.im_text: dict[str, str | iTXt] = {} + self.im_info = {} + self.im_text = {} self.im_size = (0, 0) - self.im_mode = "" - self.im_tile: list[ImageFile._Tile] = [] - self.im_palette: tuple[str, bytes] | None = None - self.im_custom_mimetype: str | None = None - self.im_n_frames: int | None = None - self._seq_num: int | None = None - self.rewind_state = _RewindState({}, [], None) + self.im_mode = None + self.im_tile = None + self.im_palette = None + self.im_custom_mimetype = None + self.im_n_frames = None + self._seq_num = None + self.rewind_state = None self.text_memory = 0 @@ -410,20 +394,19 @@ class PngStream(ChunkStream): raise ValueError(msg) def save_rewind(self) -> None: - self.rewind_state = _RewindState( - self.im_info.copy(), - self.im_tile, - self._seq_num, - ) + self.rewind_state = { + "info": self.im_info.copy(), + "tile": self.im_tile, + "seq_num": self._seq_num, + } def rewind(self) -> None: - self.im_info = self.rewind_state.info.copy() - self.im_tile = self.rewind_state.tile - self._seq_num = self.rewind_state.seq_num + self.im_info = self.rewind_state["info"].copy() + self.im_tile = self.rewind_state["tile"] + self._seq_num = self.rewind_state["seq_num"] def chunk_iCCP(self, pos: int, length: int) -> bytes: # ICC profile - assert self.fp is not None s = ImageFile._safe_read(self.fp, length) # according to PNG spec, the iCCP chunk contains: # Profile name 1-79 bytes (character string) @@ -451,7 +434,6 @@ class PngStream(ChunkStream): def chunk_IHDR(self, pos: int, length: int) -> bytes: # image header - assert self.fp is not None s = ImageFile._safe_read(self.fp, length) if length < 13: if ImageFile.LOAD_TRUNCATED_IMAGES: @@ -473,11 +455,11 @@ class PngStream(ChunkStream): def chunk_IDAT(self, pos: int, length: int) -> NoReturn: # image data if "bbox" in self.im_info: - tile = [ImageFile._Tile("zip", self.im_info["bbox"], pos, self.im_rawmode)] + tile = [("zip", self.im_info["bbox"], pos, self.im_rawmode)] else: if self.im_n_frames is not None: self.im_info["default_image"] = True - tile = [ImageFile._Tile("zip", (0, 0) + self.im_size, pos, self.im_rawmode)] + tile = [("zip", (0, 0) + self.im_size, pos, self.im_rawmode)] self.im_tile = tile self.im_idat = length msg = "image data found" @@ -489,7 +471,6 @@ class PngStream(ChunkStream): def chunk_PLTE(self, pos: int, length: int) -> bytes: # palette - assert self.fp is not None s = ImageFile._safe_read(self.fp, length) if self.im_mode == "P": self.im_palette = "RGB", s @@ -497,7 +478,6 @@ class PngStream(ChunkStream): def chunk_tRNS(self, pos: int, length: int) -> bytes: # transparency - assert self.fp is not None s = ImageFile._safe_read(self.fp, length) if self.im_mode == "P": if _simple_palette.match(s): @@ -510,9 +490,7 @@ class PngStream(ChunkStream): # otherwise, we have a byte string with one alpha value # for each palette entry self.im_info["transparency"] = s - elif self.im_mode == "1": - self.im_info["transparency"] = 255 if i16(s) else 0 - elif self.im_mode in ("L", "I;16"): + elif self.im_mode in ("1", "L", "I;16"): self.im_info["transparency"] = i16(s) elif self.im_mode == "RGB": self.im_info["transparency"] = i16(s), i16(s, 2), i16(s, 4) @@ -520,7 +498,6 @@ class PngStream(ChunkStream): def chunk_gAMA(self, pos: int, length: int) -> bytes: # gamma setting - assert self.fp is not None s = ImageFile._safe_read(self.fp, length) self.im_info["gamma"] = i32(s) / 100000.0 return s @@ -529,9 +506,8 @@ class PngStream(ChunkStream): # chromaticity, 8 unsigned ints, actual value is scaled by 100,000 # WP x,y, Red x,y, Green x,y Blue x,y - assert self.fp is not None s = ImageFile._safe_read(self.fp, length) - raw_vals = struct.unpack(f">{len(s) // 4}I", s) + raw_vals = struct.unpack(">%dI" % (len(s) // 4), s) self.im_info["chromaticity"] = tuple(elt / 100000.0 for elt in raw_vals) return s @@ -542,7 +518,6 @@ class PngStream(ChunkStream): # 2 saturation # 3 absolute colorimetric - assert self.fp is not None s = ImageFile._safe_read(self.fp, length) if length < 1: if ImageFile.LOAD_TRUNCATED_IMAGES: @@ -554,7 +529,6 @@ class PngStream(ChunkStream): def chunk_pHYs(self, pos: int, length: int) -> bytes: # pixels per unit - assert self.fp is not None s = ImageFile._safe_read(self.fp, length) if length < 9: if ImageFile.LOAD_TRUNCATED_IMAGES: @@ -572,7 +546,6 @@ class PngStream(ChunkStream): def chunk_tEXt(self, pos: int, length: int) -> bytes: # text - assert self.fp is not None s = ImageFile._safe_read(self.fp, length) try: k, v = s.split(b"\0", 1) @@ -581,18 +554,17 @@ class PngStream(ChunkStream): k = s v = b"" if k: - k_str = k.decode("latin-1", "strict") + k = k.decode("latin-1", "strict") v_str = v.decode("latin-1", "replace") - self.im_info[k_str] = v if k == b"exif" else v_str - self.im_text[k_str] = v_str + self.im_info[k] = v if k == "exif" else v_str + self.im_text[k] = v_str self.check_text_memory(len(v_str)) return s def chunk_zTXt(self, pos: int, length: int) -> bytes: # compressed text - assert self.fp is not None s = ImageFile._safe_read(self.fp, length) try: k, v = s.split(b"\0", 1) @@ -617,17 +589,16 @@ class PngStream(ChunkStream): v = b"" if k: - k_str = k.decode("latin-1", "strict") - v_str = v.decode("latin-1", "replace") + k = k.decode("latin-1", "strict") + v = v.decode("latin-1", "replace") - self.im_info[k_str] = self.im_text[k_str] = v_str - self.check_text_memory(len(v_str)) + self.im_info[k] = self.im_text[k] = v + self.check_text_memory(len(v)) return s def chunk_iTXt(self, pos: int, length: int) -> bytes: # international text - assert self.fp is not None r = s = ImageFile._safe_read(self.fp, length) try: k, r = r.split(b"\0", 1) @@ -656,27 +627,25 @@ class PngStream(ChunkStream): if k == b"XML:com.adobe.xmp": self.im_info["xmp"] = v try: - k_str = k.decode("latin-1", "strict") - lang_str = lang.decode("utf-8", "strict") - tk_str = tk.decode("utf-8", "strict") - v_str = v.decode("utf-8", "strict") + k = k.decode("latin-1", "strict") + lang = lang.decode("utf-8", "strict") + tk = tk.decode("utf-8", "strict") + v = v.decode("utf-8", "strict") except UnicodeError: return s - self.im_info[k_str] = self.im_text[k_str] = iTXt(v_str, lang_str, tk_str) - self.check_text_memory(len(v_str)) + self.im_info[k] = self.im_text[k] = iTXt(v, lang, tk) + self.check_text_memory(len(v)) return s def chunk_eXIf(self, pos: int, length: int) -> bytes: - assert self.fp is not None s = ImageFile._safe_read(self.fp, length) self.im_info["exif"] = b"Exif\x00\x00" + s return s # APNG chunks def chunk_acTL(self, pos: int, length: int) -> bytes: - assert self.fp is not None s = ImageFile._safe_read(self.fp, length) if length < 8: if ImageFile.LOAD_TRUNCATED_IMAGES: @@ -697,7 +666,6 @@ class PngStream(ChunkStream): return s def chunk_fcTL(self, pos: int, length: int) -> bytes: - assert self.fp is not None s = ImageFile._safe_read(self.fp, length) if length < 26: if ImageFile.LOAD_TRUNCATED_IMAGES: @@ -727,7 +695,6 @@ class PngStream(ChunkStream): return s def chunk_fdAT(self, pos: int, length: int) -> bytes: - assert self.fp is not None if length < 4: if ImageFile.LOAD_TRUNCATED_IMAGES: s = ImageFile._safe_read(self.fp, length) @@ -748,7 +715,7 @@ class PngStream(ChunkStream): def _accept(prefix: bytes) -> bool: - return prefix.startswith(_MAGIC) + return prefix[:8] == _MAGIC ## @@ -760,7 +727,6 @@ class PngImageFile(ImageFile.ImageFile): format_description = "Portable network graphics" def _open(self) -> None: - assert self.fp is not None if not _accept(self.fp.read(8)): msg = "not a PNG file" raise SyntaxError(msg) @@ -801,7 +767,7 @@ class PngImageFile(ImageFile.ImageFile): self._mode = self.png.im_mode self._size = self.png.im_size self.info = self.png.im_info - self._text: dict[str, str | iTXt] | None = None + self._text = None self.tile = self.png.im_tile self.custom_mimetype = self.png.im_custom_mimetype self.n_frames = self.png.im_n_frames or 1 @@ -828,7 +794,7 @@ class PngImageFile(ImageFile.ImageFile): self.is_animated = self.n_frames > 1 @property - def text(self) -> dict[str, str | iTXt]: + def text(self): # experimental if self._text is None: # iTxt, tEXt and zTXt chunks may appear at the end of the file @@ -840,7 +806,6 @@ class PngImageFile(ImageFile.ImageFile): self.load() if self.is_animated: self.seek(frame) - assert self._text is not None return self._text def verify(self) -> None: @@ -857,7 +822,9 @@ class PngImageFile(ImageFile.ImageFile): self.png.verify() self.png.close() - super().verify() + if self._exclusive_fp: + self.fp.close() + self.fp = None def seek(self, frame: int) -> None: if not self._seek_check(frame): @@ -876,17 +843,16 @@ class PngImageFile(ImageFile.ImageFile): def _seek(self, frame: int, rewind: bool = False) -> None: assert self.png is not None - if isinstance(self._fp, DeferredError): - raise self._fp.ex self.dispose: _imaging.ImagingCore | None - dispose_extent = None if frame == 0: if rewind: self._fp.seek(self.__rewind) self.png.rewind() self.__prepare_idat = self.__rewind_idat - self._im = None + self.im = None + if self.pyaccess: + self.pyaccess = None self.info = self.png.im_info self.tile = self.png.im_tile self.fp = self._fp @@ -895,7 +861,7 @@ class PngImageFile(ImageFile.ImageFile): self.default_image = self.info.get("default_image", False) self.dispose_op = self.info.get("disposal") self.blend_op = self.info.get("blend") - dispose_extent = self.info.get("bbox") + self.dispose_extent = self.info.get("bbox") self.__frame = 0 else: if frame != self.__frame + 1: @@ -953,13 +919,11 @@ class PngImageFile(ImageFile.ImageFile): self.tile = self.png.im_tile self.dispose_op = self.info.get("disposal") self.blend_op = self.info.get("blend") - dispose_extent = self.info.get("bbox") + self.dispose_extent = self.info.get("bbox") if not self.tile: msg = "image not found in APNG frame" raise EOFError(msg) - if dispose_extent: - self.dispose_extent: tuple[float, float, float, float] = dispose_extent # setup frame disposal (actual disposal done when needed in the next _seek()) if self._prev_im is None and self.dispose_op == Disposal.OP_PREVIOUS: @@ -990,7 +954,6 @@ class PngImageFile(ImageFile.ImageFile): """internal: read more image data""" assert self.png is not None - assert self.fp is not None while self.__idat == 0: # end of chunk, skip forward to next one @@ -1024,7 +987,6 @@ class PngImageFile(ImageFile.ImageFile): def load_end(self) -> None: """internal: finished reading image data""" assert self.png is not None - assert self.fp is not None if self.__idat != 0: self.fp.read(self.__idat) while True: @@ -1074,17 +1036,13 @@ class PngImageFile(ImageFile.ImageFile): "RGBA", self.info["transparency"] ) else: - if self.im.mode == "P" and "transparency" in self.info: - t = self.info["transparency"] - if isinstance(t, bytes): - updated.putpalettealphas(t) - elif isinstance(t, int): - updated.putpalettealpha(t) mask = updated.convert("RGBA") self._prev_im.paste(updated, self.dispose_extent, mask) self.im = self._prev_im + if self.pyaccess: + self.pyaccess = None - def _getexif(self) -> dict[int, Any] | None: + def _getexif(self) -> dict[str, Any] | None: if "exif" not in self.info: self.load() if "exif" not in self.info and "Raw profile type exif" not in self.info: @@ -1121,21 +1079,21 @@ _OUTMODES = { } -def putchunk(fp: IO[bytes], cid: bytes, *data: bytes) -> None: +def putchunk(fp, cid, *data): """Write a PNG chunk (including CRC field)""" - byte_data = b"".join(data) + data = b"".join(data) - fp.write(o32(len(byte_data)) + cid) - fp.write(byte_data) - crc = _crc32(byte_data, _crc32(cid)) + fp.write(o32(len(data)) + cid) + fp.write(data) + crc = _crc32(data, _crc32(cid)) fp.write(o32(crc)) class _idat: # wrap output from the encoder in IDAT chunks - def __init__(self, fp: IO[bytes], chunk: Callable[..., None]) -> None: + def __init__(self, fp, chunk): self.fp = fp self.chunk = chunk @@ -1146,7 +1104,7 @@ class _idat: class _fdat: # wrap encoder output in fdAT chunks - def __init__(self, fp: IO[bytes], chunk: Callable[..., None], seq_num: int) -> None: + def __init__(self, fp, chunk, seq_num): self.fp = fp self.chunk = chunk self.seq_num = seq_num @@ -1156,30 +1114,7 @@ class _fdat: self.seq_num += 1 -def _apply_encoderinfo(im: Image.Image, encoderinfo: dict[str, Any]) -> None: - im.encoderconfig = ( - encoderinfo.get("optimize", False), - encoderinfo.get("compress_level", -1), - encoderinfo.get("compress_type", -1), - encoderinfo.get("dictionary", b""), - ) - - -class _Frame(NamedTuple): - im: Image.Image - bbox: tuple[int, int, int, int] | None - encoderinfo: dict[str, Any] - - -def _write_multiple_frames( - im: Image.Image, - fp: IO[bytes], - chunk: Callable[..., None], - mode: str, - rawmode: str, - default_image: Image.Image | None, - append_images: list[Image.Image], -) -> Image.Image | None: +def _write_multiple_frames(im, fp, chunk, mode, rawmode, default_image, append_images): duration = im.encoderinfo.get("duration") loop = im.encoderinfo.get("loop", im.info.get("loop", 0)) disposal = im.encoderinfo.get("disposal", im.info.get("disposal", Disposal.OP_NONE)) @@ -1190,7 +1125,7 @@ def _write_multiple_frames( else: chain = itertools.chain([im], append_images) - im_frames: list[_Frame] = [] + im_frames = [] frame_count = 0 for im_seq in chain: for im_frame in ImageSequence.Iterator(im_seq): @@ -1211,24 +1146,24 @@ def _write_multiple_frames( if im_frames: previous = im_frames[-1] - prev_disposal = previous.encoderinfo.get("disposal") - prev_blend = previous.encoderinfo.get("blend") + prev_disposal = previous["encoderinfo"].get("disposal") + prev_blend = previous["encoderinfo"].get("blend") if prev_disposal == Disposal.OP_PREVIOUS and len(im_frames) < 2: prev_disposal = Disposal.OP_BACKGROUND if prev_disposal == Disposal.OP_BACKGROUND: - base_im = previous.im.copy() + base_im = previous["im"].copy() dispose = Image.core.fill("RGBA", im.size, (0, 0, 0, 0)) - bbox = previous.bbox + bbox = previous["bbox"] if bbox: dispose = dispose.crop(bbox) else: bbox = (0, 0) + im.size base_im.paste(dispose, bbox) elif prev_disposal == Disposal.OP_PREVIOUS: - base_im = im_frames[-2].im + base_im = im_frames[-2]["im"] else: - base_im = previous.im + base_im = previous["im"] delta = ImageChops.subtract_modulo( im_frame.convert("RGBA"), base_im.convert("RGBA") ) @@ -1239,14 +1174,14 @@ def _write_multiple_frames( and prev_blend == encoderinfo.get("blend") and "duration" in encoderinfo ): - previous.encoderinfo["duration"] += encoderinfo["duration"] + previous["encoderinfo"]["duration"] += encoderinfo["duration"] continue else: bbox = None - im_frames.append(_Frame(im_frame, bbox, encoderinfo)) + im_frames.append({"im": im_frame, "bbox": bbox, "encoderinfo": encoderinfo}) if len(im_frames) == 1 and not default_image: - return im_frames[0].im + return im_frames[0]["im"] # animation control chunk( @@ -1258,29 +1193,21 @@ def _write_multiple_frames( # default image IDAT (if it exists) if default_image: - default_im = im if im.mode == mode else im.convert(mode) - _apply_encoderinfo(default_im, im.encoderinfo) - ImageFile._save( - default_im, - cast(IO[bytes], _idat(fp, chunk)), - [ImageFile._Tile("zip", (0, 0) + im.size, 0, rawmode)], - ) + if im.mode != mode: + im = im.convert(mode) + ImageFile._save(im, _idat(fp, chunk), [("zip", (0, 0) + im.size, 0, rawmode)]) seq_num = 0 for frame, frame_data in enumerate(im_frames): - im_frame = frame_data.im - if not frame_data.bbox: + im_frame = frame_data["im"] + if not frame_data["bbox"]: bbox = (0, 0) + im_frame.size else: - bbox = frame_data.bbox + bbox = frame_data["bbox"] im_frame = im_frame.crop(bbox) size = im_frame.size - encoderinfo = frame_data.encoderinfo - frame_duration = encoderinfo.get("duration", 0) - delay = Fraction(frame_duration / 1000).limit_denominator(65535) - if delay.numerator > 65535: - msg = "cannot write duration" - raise ValueError(msg) + encoderinfo = frame_data["encoderinfo"] + frame_duration = int(round(encoderinfo.get("duration", 0))) frame_disposal = encoderinfo.get("disposal", disposal) frame_blend = encoderinfo.get("blend", blend) # frame control @@ -1292,43 +1219,35 @@ def _write_multiple_frames( o32(size[1]), # height o32(bbox[0]), # x_offset o32(bbox[1]), # y_offset - o16(delay.numerator), # delay_numerator - o16(delay.denominator), # delay_denominator + o16(frame_duration), # delay_numerator + o16(1000), # delay_denominator o8(frame_disposal), # dispose_op o8(frame_blend), # blend_op ) seq_num += 1 # frame data - _apply_encoderinfo(im_frame, im.encoderinfo) if frame == 0 and not default_image: # first frame must be in IDAT chunks for backwards compatibility ImageFile._save( im_frame, - cast(IO[bytes], _idat(fp, chunk)), - [ImageFile._Tile("zip", (0, 0) + im_frame.size, 0, rawmode)], + _idat(fp, chunk), + [("zip", (0, 0) + im_frame.size, 0, rawmode)], ) else: fdat_chunks = _fdat(fp, chunk, seq_num) ImageFile._save( im_frame, - cast(IO[bytes], fdat_chunks), - [ImageFile._Tile("zip", (0, 0) + im_frame.size, 0, rawmode)], + fdat_chunks, + [("zip", (0, 0) + im_frame.size, 0, rawmode)], ) seq_num = fdat_chunks.seq_num - return None def _save_all(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: _save(im, fp, filename, save_all=True) -def _save( - im: Image.Image, - fp: IO[bytes], - filename: str | bytes, - chunk: Callable[..., None] = putchunk, - save_all: bool = False, -) -> None: +def _save(im, fp, filename, chunk=putchunk, save_all=False): # save an image to disk (called by the save method) if save_all: @@ -1375,14 +1294,20 @@ def _save( bits = 4 outmode += f";{bits}" + # encoder options + im.encoderconfig = ( + im.encoderinfo.get("optimize", False), + im.encoderinfo.get("compress_level", -1), + im.encoderinfo.get("compress_type", -1), + im.encoderinfo.get("dictionary", b""), + ) + # get the corresponding PNG mode try: rawmode, bit_depth, color_type = _OUTMODES[outmode] except KeyError as e: msg = f"cannot write mode {mode} as PNG" raise OSError(msg) from e - if outmode == "I": - deprecate("Saving I mode images as PNG", 13, stacklevel=4) # # write minimal PNG file @@ -1401,7 +1326,7 @@ def _save( b"\0", # 12: interlace flag ) - chunks = [b"cHRM", b"cICP", b"gAMA", b"sBIT", b"sRGB", b"tIME"] + chunks = [b"cHRM", b"gAMA", b"sBIT", b"sRGB", b"tIME"] icc = im.encoderinfo.get("icc_profile", im.info.get("icc_profile")) if icc: @@ -1452,7 +1377,7 @@ def _save( chunk(fp, b"tRNS", transparency[:alpha_bytes]) else: transparency = max(0, min(255, transparency)) - alpha = b"\xff" * transparency + b"\0" + alpha = b"\xFF" * transparency + b"\0" chunk(fp, b"tRNS", alpha[:alpha_bytes]) elif im.mode in ("1", "L", "I", "I;16"): transparency = max(0, min(65535, transparency)) @@ -1498,18 +1423,12 @@ def _save( exif = exif[6:] chunk(fp, b"eXIf", exif) - single_im: Image.Image | None = im if save_all: - single_im = _write_multiple_frames( + im = _write_multiple_frames( im, fp, chunk, mode, rawmode, default_image, append_images ) - if single_im: - _apply_encoderinfo(single_im, im.encoderinfo) - ImageFile._save( - single_im, - cast(IO[bytes], _idat(fp, chunk)), - [ImageFile._Tile("zip", (0, 0) + single_im.size, 0, rawmode)], - ) + if im: + ImageFile._save(im, _idat(fp, chunk), [("zip", (0, 0) + im.size, 0, rawmode)]) if info: for info_chunk in info.chunks: @@ -1530,26 +1449,32 @@ def _save( # PNG chunk converter -def getchunks(im: Image.Image, **params: Any) -> list[tuple[bytes, bytes, bytes]]: +def getchunks(im, **params): """Return a list of PNG chunks representing this image.""" - from io import BytesIO - chunks = [] + class collector: + data = [] - def append(fp: IO[bytes], cid: bytes, *data: bytes) -> None: - byte_data = b"".join(data) - crc = o32(_crc32(byte_data, _crc32(cid))) - chunks.append((cid, byte_data, crc)) + def write(self, data: bytes) -> None: + pass - fp = BytesIO() + def append(self, chunk: bytes) -> None: + self.data.append(chunk) + + def append(fp, cid, *data): + data = b"".join(data) + crc = o32(_crc32(data, _crc32(cid))) + fp.append((cid, data, crc)) + + fp = collector() try: im.encoderinfo = params - _save(im, fp, "", append) + _save(im, fp, None, append) finally: del im.encoderinfo - return chunks + return fp.data # -------------------------------------------------------------------- diff --git a/venv/Lib/site-packages/PIL/PpmImagePlugin.py b/venv/Lib/site-packages/PIL/PpmImagePlugin.py index 307bc97..16c9ccb 100644 --- a/venv/Lib/site-packages/PIL/PpmImagePlugin.py +++ b/venv/Lib/site-packages/PIL/PpmImagePlugin.py @@ -47,7 +47,7 @@ MODES = { def _accept(prefix: bytes) -> bool: - return len(prefix) >= 2 and prefix.startswith(b"P") and prefix[1] in b"0123456fy" + return prefix[0:1] == b"P" and prefix[1] in b"0123456fy" ## @@ -94,8 +94,8 @@ class PpmImageFile(ImageFile.ImageFile): msg = "Reached EOF while reading header" raise ValueError(msg) elif len(token) > 10: - msg_too_long = b"Token too long in file header: %s" % token - raise ValueError(msg_too_long) + msg = f"Token too long in file header: {token.decode()}" + raise ValueError(msg) return token def _open(self) -> None: @@ -151,9 +151,7 @@ class PpmImageFile(ImageFile.ImageFile): decoder_name = "ppm" args = rawmode if decoder_name == "raw" else (rawmode, maxval) - self.tile = [ - ImageFile._Tile(decoder_name, (0, 0) + self.size, self.fp.tell(), args) - ] + self.tile = [(decoder_name, (0, 0) + self.size, self.fp.tell(), args)] # @@ -230,7 +228,7 @@ class PpmPlainDecoder(ImageFile.PyDecoder): msg = b"Invalid token for this mode: %s" % bytes([token]) raise ValueError(msg) data = (data + tokens)[:total_bytes] - invert = bytes.maketrans(b"01", b"\xff\x00") + invert = bytes.maketrans(b"01", b"\xFF\x00") return data.translate(invert) def _decode_blocks(self, maxval: int) -> bytearray: @@ -284,7 +282,7 @@ class PpmPlainDecoder(ImageFile.PyDecoder): break return data - def decode(self, buffer: bytes | Image.SupportsArrayInterface) -> tuple[int, int]: + def decode(self, buffer: bytes) -> tuple[int, int]: self._comment_spans = False if self.mode == "1": data = self._decode_bitonal() @@ -300,7 +298,7 @@ class PpmPlainDecoder(ImageFile.PyDecoder): class PpmDecoder(ImageFile.PyDecoder): _pulls_fd = True - def decode(self, buffer: bytes | Image.SupportsArrayInterface) -> tuple[int, int]: + def decode(self, buffer: bytes) -> tuple[int, int]: assert self.fd is not None data = bytearray() @@ -335,7 +333,7 @@ def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: rawmode, head = "1;I", b"P4" elif im.mode == "L": rawmode, head = "L", b"P5" - elif im.mode in ("I", "I;16"): + elif im.mode == "I": rawmode, head = "I;16B", b"P5" elif im.mode in ("RGB", "RGBA"): rawmode, head = "RGB", b"P6" @@ -355,9 +353,7 @@ def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: elif head == b"Pf": fp.write(b"-1.0\n") row_order = -1 if im.mode == "F" else 1 - ImageFile._save( - im, fp, [ImageFile._Tile("raw", (0, 0) + im.size, 0, (rawmode, 0, row_order))] - ) + ImageFile._save(im, fp, [("raw", (0, 0) + im.size, 0, (rawmode, 0, row_order))]) # diff --git a/venv/Lib/site-packages/PIL/PsdImagePlugin.py b/venv/Lib/site-packages/PIL/PsdImagePlugin.py index 69a8703..edf698b 100644 --- a/venv/Lib/site-packages/PIL/PsdImagePlugin.py +++ b/venv/Lib/site-packages/PIL/PsdImagePlugin.py @@ -19,7 +19,6 @@ from __future__ import annotations import io from functools import cached_property -from typing import IO from . import Image, ImageFile, ImagePalette from ._binary import i8 @@ -27,7 +26,6 @@ from ._binary import i16be as i16 from ._binary import i32be as i32 from ._binary import si16be as si16 from ._binary import si32be as si32 -from ._util import DeferredError MODES = { # (photoshop mode, bits) -> (pil mode, required channels) @@ -48,7 +46,7 @@ MODES = { def _accept(prefix: bytes) -> bool: - return prefix.startswith(b"8BPS") + return prefix[:4] == b"8BPS" ## @@ -61,7 +59,6 @@ class PsdImageFile(ImageFile.ImageFile): _close_exclusive_fp_after_loading = False def _open(self) -> None: - assert self.fp is not None read = self.fp.read # @@ -145,13 +142,9 @@ class PsdImageFile(ImageFile.ImageFile): self._min_frame = 1 @cached_property - def layers( - self, - ) -> list[tuple[str, str, tuple[int, int, int, int], list[ImageFile._Tile]]]: + def layers(self): layers = [] if self._layers_position is not None: - if isinstance(self._fp, DeferredError): - raise self._fp.ex self._fp.seek(self._layers_position) _layer_data = io.BytesIO(ImageFile._safe_read(self._fp, self._layers_size)) layers = _layerinfo(_layer_data, self._layers_size) @@ -171,28 +164,28 @@ class PsdImageFile(ImageFile.ImageFile): def seek(self, layer: int) -> None: if not self._seek_check(layer): return - if isinstance(self._fp, DeferredError): - raise self._fp.ex # seek to given layer (1..max) - _, mode, _, tile = self.layers[layer - 1] - self._mode = mode - self.tile = tile - self.frame = layer - self.fp = self._fp + try: + _, mode, _, tile = self.layers[layer - 1] + self._mode = mode + self.tile = tile + self.frame = layer + self.fp = self._fp + except IndexError as e: + msg = "no such layer" + raise EOFError(msg) from e def tell(self) -> int: # return layer number (0=image, 1..max=layers) return self.frame -def _layerinfo( - fp: IO[bytes], ct_bytes: int -) -> list[tuple[str, str, tuple[int, int, int, int], list[ImageFile._Tile]]]: +def _layerinfo(fp, ct_bytes): # read layerinfo block layers = [] - def read(size: int) -> bytes: + def read(size): return ImageFile._safe_read(fp, size) ct = si16(read(2)) @@ -210,7 +203,7 @@ def _layerinfo( x1 = si32(read(4)) # image info - bands = [] + mode = [] ct_types = i16(read(2)) if ct_types > 4: fp.seek(ct_types * 6 + 12, io.SEEK_CUR) @@ -222,23 +215,23 @@ def _layerinfo( type = i16(read(2)) if type == 65535: - b = "A" + m = "A" else: - b = "RGBA"[type] + m = "RGBA"[type] - bands.append(b) + mode.append(m) read(4) # size # figure out the image mode - bands.sort() - if bands == ["R"]: + mode.sort() + if mode == ["R"]: mode = "L" - elif bands == ["B", "G", "R"]: + elif mode == ["B", "G", "R"]: mode = "RGB" - elif bands == ["A", "B", "G", "R"]: + elif mode == ["A", "B", "G", "R"]: mode = "RGBA" else: - mode = "" # unknown + mode = None # unknown # skip over blend flags and extra information read(12) # filler @@ -265,22 +258,19 @@ def _layerinfo( layers.append((name, mode, (x0, y0, x1, y1))) # get tiles - layerinfo = [] for i, (name, mode, bbox) in enumerate(layers): tile = [] for m in mode: t = _maketile(fp, m, bbox, 1) if t: tile.extend(t) - layerinfo.append((name, mode, bbox, tile)) + layers[i] = name, mode, bbox, tile - return layerinfo + return layers -def _maketile( - file: IO[bytes], mode: str, bbox: tuple[int, int, int, int], channels: int -) -> list[ImageFile._Tile]: - tiles = [] +def _maketile(file, mode, bbox, channels): + tile = None read = file.read compression = i16(read(2)) @@ -293,24 +283,26 @@ def _maketile( if compression == 0: # # raw compression + tile = [] for channel in range(channels): layer = mode[channel] if mode == "CMYK": layer += ";I" - tiles.append(ImageFile._Tile("raw", bbox, offset, layer)) + tile.append(("raw", bbox, offset, layer)) offset = offset + xsize * ysize elif compression == 1: # # packbits compression i = 0 + tile = [] bytecount = read(channels * ysize * 2) offset = file.tell() for channel in range(channels): layer = mode[channel] if mode == "CMYK": layer += ";I" - tiles.append(ImageFile._Tile("packbits", bbox, offset, layer)) + tile.append(("packbits", bbox, offset, layer)) for y in range(ysize): offset = offset + i16(bytecount, i) i += 2 @@ -320,7 +312,7 @@ def _maketile( if offset & 1: read(1) # padding - return tiles + return tile # -------------------------------------------------------------------- diff --git a/venv/Lib/site-packages/PIL/PyAccess.py b/venv/Lib/site-packages/PIL/PyAccess.py new file mode 100644 index 0000000..3be1cca --- /dev/null +++ b/venv/Lib/site-packages/PIL/PyAccess.py @@ -0,0 +1,381 @@ +# +# The Python Imaging Library +# Pillow fork +# +# Python implementation of the PixelAccess Object +# +# Copyright (c) 1997-2009 by Secret Labs AB. All rights reserved. +# Copyright (c) 1995-2009 by Fredrik Lundh. +# Copyright (c) 2013 Eric Soroos +# +# See the README file for information on usage and redistribution +# + +# Notes: +# +# * Implements the pixel access object following Access.c +# * Taking only the tuple form, which is used from python. +# * Fill.c uses the integer form, but it's still going to use the old +# Access.c implementation. +# +from __future__ import annotations + +import logging +import sys +from typing import TYPE_CHECKING + +from ._deprecate import deprecate + +FFI: type +try: + from cffi import FFI + + defs = """ + struct Pixel_RGBA { + unsigned char r,g,b,a; + }; + struct Pixel_I16 { + unsigned char l,r; + }; + """ + ffi = FFI() + ffi.cdef(defs) +except ImportError as ex: + # Allow error import for doc purposes, but error out when accessing + # anything in core. + from ._util import DeferredError + + FFI = ffi = DeferredError.new(ex) + +logger = logging.getLogger(__name__) + +if TYPE_CHECKING: + from . import Image + + +class PyAccess: + def __init__(self, img: Image.Image, readonly: bool = False) -> None: + deprecate("PyAccess", 11) + vals = dict(img.im.unsafe_ptrs) + self.readonly = readonly + self.image8 = ffi.cast("unsigned char **", vals["image8"]) + self.image32 = ffi.cast("int **", vals["image32"]) + self.image = ffi.cast("unsigned char **", vals["image"]) + self.xsize, self.ysize = img.im.size + self._img = img + + # Keep pointer to im object to prevent dereferencing. + self._im = img.im + if self._im.mode in ("P", "PA"): + self._palette = img.palette + + # Debugging is polluting test traces, only useful here + # when hacking on PyAccess + # logger.debug("%s", vals) + self._post_init() + + def _post_init(self) -> None: + pass + + def __setitem__( + self, + xy: tuple[int, int] | list[int], + color: float | tuple[int, ...] | list[int], + ) -> None: + """ + Modifies the pixel at x,y. The color is given as a single + numerical value for single band images, and a tuple for + multi-band images. In addition to this, RGB and RGBA tuples + are accepted for P and PA images. + + :param xy: The pixel coordinate, given as (x, y). See + :ref:`coordinate-system`. + :param color: The pixel value. + """ + if self.readonly: + msg = "Attempt to putpixel a read only image" + raise ValueError(msg) + (x, y) = xy + if x < 0: + x = self.xsize + x + if y < 0: + y = self.ysize + y + (x, y) = self.check_xy((x, y)) + + if ( + self._im.mode in ("P", "PA") + and isinstance(color, (list, tuple)) + and len(color) in [3, 4] + ): + # RGB or RGBA value for a P or PA image + if self._im.mode == "PA": + alpha = color[3] if len(color) == 4 else 255 + color = color[:3] + palette_index = self._palette.getcolor(color, self._img) + color = (palette_index, alpha) if self._im.mode == "PA" else palette_index + + return self.set_pixel(x, y, color) + + def __getitem__(self, xy: tuple[int, int] | list[int]) -> float | tuple[int, ...]: + """ + Returns the pixel at x,y. The pixel is returned as a single + value for single band images or a tuple for multiple band + images + + :param xy: The pixel coordinate, given as (x, y). See + :ref:`coordinate-system`. + :returns: a pixel value for single band images, a tuple of + pixel values for multiband images. + """ + (x, y) = xy + if x < 0: + x = self.xsize + x + if y < 0: + y = self.ysize + y + (x, y) = self.check_xy((x, y)) + return self.get_pixel(x, y) + + putpixel = __setitem__ + getpixel = __getitem__ + + def check_xy(self, xy: tuple[int, int]) -> tuple[int, int]: + (x, y) = xy + if not (0 <= x < self.xsize and 0 <= y < self.ysize): + msg = "pixel location out of range" + raise ValueError(msg) + return xy + + def get_pixel(self, x: int, y: int) -> float | tuple[int, ...]: + raise NotImplementedError() + + def set_pixel( + self, x: int, y: int, color: float | tuple[int, ...] | list[int] + ) -> None: + raise NotImplementedError() + + +class _PyAccess32_2(PyAccess): + """PA, LA, stored in first and last bytes of a 32 bit word""" + + def _post_init(self, *args, **kwargs): + self.pixels = ffi.cast("struct Pixel_RGBA **", self.image32) + + def get_pixel(self, x: int, y: int) -> tuple[int, int]: + pixel = self.pixels[y][x] + return pixel.r, pixel.a + + def set_pixel(self, x, y, color): + pixel = self.pixels[y][x] + # tuple + pixel.r = min(color[0], 255) + pixel.a = min(color[1], 255) + + +class _PyAccess32_3(PyAccess): + """RGB and friends, stored in the first three bytes of a 32 bit word""" + + def _post_init(self, *args, **kwargs): + self.pixels = ffi.cast("struct Pixel_RGBA **", self.image32) + + def get_pixel(self, x: int, y: int) -> tuple[int, int, int]: + pixel = self.pixels[y][x] + return pixel.r, pixel.g, pixel.b + + def set_pixel(self, x, y, color): + pixel = self.pixels[y][x] + # tuple + pixel.r = min(color[0], 255) + pixel.g = min(color[1], 255) + pixel.b = min(color[2], 255) + pixel.a = 255 + + +class _PyAccess32_4(PyAccess): + """RGBA etc, all 4 bytes of a 32 bit word""" + + def _post_init(self, *args, **kwargs): + self.pixels = ffi.cast("struct Pixel_RGBA **", self.image32) + + def get_pixel(self, x: int, y: int) -> tuple[int, int, int, int]: + pixel = self.pixels[y][x] + return pixel.r, pixel.g, pixel.b, pixel.a + + def set_pixel(self, x, y, color): + pixel = self.pixels[y][x] + # tuple + pixel.r = min(color[0], 255) + pixel.g = min(color[1], 255) + pixel.b = min(color[2], 255) + pixel.a = min(color[3], 255) + + +class _PyAccess8(PyAccess): + """1, L, P, 8 bit images stored as uint8""" + + def _post_init(self, *args, **kwargs): + self.pixels = self.image8 + + def get_pixel(self, x: int, y: int) -> int: + return self.pixels[y][x] + + def set_pixel(self, x, y, color): + try: + # integer + self.pixels[y][x] = min(color, 255) + except TypeError: + # tuple + self.pixels[y][x] = min(color[0], 255) + + +class _PyAccessI16_N(PyAccess): + """I;16 access, native bitendian without conversion""" + + def _post_init(self, *args, **kwargs): + self.pixels = ffi.cast("unsigned short **", self.image) + + def get_pixel(self, x: int, y: int) -> int: + return self.pixels[y][x] + + def set_pixel(self, x, y, color): + try: + # integer + self.pixels[y][x] = min(color, 65535) + except TypeError: + # tuple + self.pixels[y][x] = min(color[0], 65535) + + +class _PyAccessI16_L(PyAccess): + """I;16L access, with conversion""" + + def _post_init(self, *args, **kwargs): + self.pixels = ffi.cast("struct Pixel_I16 **", self.image) + + def get_pixel(self, x: int, y: int) -> int: + pixel = self.pixels[y][x] + return pixel.l + pixel.r * 256 + + def set_pixel(self, x, y, color): + pixel = self.pixels[y][x] + try: + color = min(color, 65535) + except TypeError: + color = min(color[0], 65535) + + pixel.l = color & 0xFF + pixel.r = color >> 8 + + +class _PyAccessI16_B(PyAccess): + """I;16B access, with conversion""" + + def _post_init(self, *args, **kwargs): + self.pixels = ffi.cast("struct Pixel_I16 **", self.image) + + def get_pixel(self, x: int, y: int) -> int: + pixel = self.pixels[y][x] + return pixel.l * 256 + pixel.r + + def set_pixel(self, x, y, color): + pixel = self.pixels[y][x] + try: + color = min(color, 65535) + except Exception: + color = min(color[0], 65535) + + pixel.l = color >> 8 + pixel.r = color & 0xFF + + +class _PyAccessI32_N(PyAccess): + """Signed Int32 access, native endian""" + + def _post_init(self, *args, **kwargs): + self.pixels = self.image32 + + def get_pixel(self, x: int, y: int) -> int: + return self.pixels[y][x] + + def set_pixel(self, x, y, color): + self.pixels[y][x] = color + + +class _PyAccessI32_Swap(PyAccess): + """I;32L/B access, with byteswapping conversion""" + + def _post_init(self, *args, **kwargs): + self.pixels = self.image32 + + def reverse(self, i): + orig = ffi.new("int *", i) + chars = ffi.cast("unsigned char *", orig) + chars[0], chars[1], chars[2], chars[3] = chars[3], chars[2], chars[1], chars[0] + return ffi.cast("int *", chars)[0] + + def get_pixel(self, x: int, y: int) -> int: + return self.reverse(self.pixels[y][x]) + + def set_pixel(self, x, y, color): + self.pixels[y][x] = self.reverse(color) + + +class _PyAccessF(PyAccess): + """32 bit float access""" + + def _post_init(self, *args, **kwargs): + self.pixels = ffi.cast("float **", self.image32) + + def get_pixel(self, x: int, y: int) -> float: + return self.pixels[y][x] + + def set_pixel(self, x, y, color): + try: + # not a tuple + self.pixels[y][x] = color + except TypeError: + # tuple + self.pixels[y][x] = color[0] + + +mode_map = { + "1": _PyAccess8, + "L": _PyAccess8, + "P": _PyAccess8, + "I;16N": _PyAccessI16_N, + "LA": _PyAccess32_2, + "La": _PyAccess32_2, + "PA": _PyAccess32_2, + "RGB": _PyAccess32_3, + "LAB": _PyAccess32_3, + "HSV": _PyAccess32_3, + "YCbCr": _PyAccess32_3, + "RGBA": _PyAccess32_4, + "RGBa": _PyAccess32_4, + "RGBX": _PyAccess32_4, + "CMYK": _PyAccess32_4, + "F": _PyAccessF, + "I": _PyAccessI32_N, +} + +if sys.byteorder == "little": + mode_map["I;16"] = _PyAccessI16_N + mode_map["I;16L"] = _PyAccessI16_N + mode_map["I;16B"] = _PyAccessI16_B + + mode_map["I;32L"] = _PyAccessI32_N + mode_map["I;32B"] = _PyAccessI32_Swap +else: + mode_map["I;16"] = _PyAccessI16_L + mode_map["I;16L"] = _PyAccessI16_L + mode_map["I;16B"] = _PyAccessI16_N + + mode_map["I;32L"] = _PyAccessI32_Swap + mode_map["I;32B"] = _PyAccessI32_N + + +def new(img: Image.Image, readonly: bool = False) -> PyAccess | None: + access_type = mode_map.get(img.mode, None) + if not access_type: + logger.debug("PyAccess Not Implemented: %s", img.mode) + return None + return access_type(img, readonly) diff --git a/venv/Lib/site-packages/PIL/QoiImagePlugin.py b/venv/Lib/site-packages/PIL/QoiImagePlugin.py index d0709b1..202ef52 100644 --- a/venv/Lib/site-packages/PIL/QoiImagePlugin.py +++ b/venv/Lib/site-packages/PIL/QoiImagePlugin.py @@ -8,16 +8,13 @@ from __future__ import annotations import os -from typing import IO from . import Image, ImageFile from ._binary import i32be as i32 -from ._binary import o8 -from ._binary import o32be as o32 def _accept(prefix: bytes) -> bool: - return prefix.startswith(b"qoif") + return prefix[:4] == b"qoif" class QoiImageFile(ImageFile.ImageFile): @@ -25,18 +22,17 @@ class QoiImageFile(ImageFile.ImageFile): format_description = "Quite OK Image" def _open(self) -> None: - assert self.fp is not None if not _accept(self.fp.read(4)): msg = "not a QOI file" raise SyntaxError(msg) - self._size = i32(self.fp.read(4)), i32(self.fp.read(4)) + self._size = tuple(i32(self.fp.read(4)) for i in range(2)) channels = self.fp.read(1)[0] self._mode = "RGB" if channels == 3 else "RGBA" self.fp.seek(1, os.SEEK_CUR) # colorspace - self.tile = [ImageFile._Tile("qoi", (0, 0) + self._size, self.fp.tell())] + self.tile = [("qoi", (0, 0) + self._size, self.fp.tell(), None)] class QoiDecoder(ImageFile.PyDecoder): @@ -51,11 +47,11 @@ class QoiDecoder(ImageFile.PyDecoder): hash_value = (r * 3 + g * 5 + b * 7 + a * 11) % 64 self._previously_seen_pixels[hash_value] = value - def decode(self, buffer: bytes | Image.SupportsArrayInterface) -> tuple[int, int]: + def decode(self, buffer: bytes) -> tuple[int, int]: assert self.fd is not None self._previously_seen_pixels = {} - self._previous_pixel = bytearray((0, 0, 0, 255)) + self._add_to_previous_pixels(bytearray((0, 0, 0, 255))) data = bytearray() bands = Image.getmodebands(self.mode) @@ -114,122 +110,6 @@ class QoiDecoder(ImageFile.PyDecoder): return -1, 0 -def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: - if im.mode == "RGB": - channels = 3 - elif im.mode == "RGBA": - channels = 4 - else: - msg = "Unsupported QOI image mode" - raise ValueError(msg) - - colorspace = 0 if im.encoderinfo.get("colorspace") == "sRGB" else 1 - - fp.write(b"qoif") - fp.write(o32(im.size[0])) - fp.write(o32(im.size[1])) - fp.write(o8(channels)) - fp.write(o8(colorspace)) - - ImageFile._save(im, fp, [ImageFile._Tile("qoi", (0, 0) + im.size)]) - - -class QoiEncoder(ImageFile.PyEncoder): - _pushes_fd = True - _previous_pixel: tuple[int, int, int, int] | None = None - _previously_seen_pixels: dict[int, tuple[int, int, int, int]] = {} - _run = 0 - - def _write_run(self) -> bytes: - data = o8(0b11000000 | (self._run - 1)) # QOI_OP_RUN - self._run = 0 - return data - - def _delta(self, left: int, right: int) -> int: - result = (left - right) & 255 - if result >= 128: - result -= 256 - return result - - def encode(self, bufsize: int) -> tuple[int, int, bytes]: - assert self.im is not None - - self._previously_seen_pixels = {0: (0, 0, 0, 0)} - self._previous_pixel = (0, 0, 0, 255) - - data = bytearray() - w, h = self.im.size - bands = Image.getmodebands(self.mode) - - for y in range(h): - for x in range(w): - pixel = self.im.getpixel((x, y)) - if bands == 3: - pixel = (*pixel, 255) - - if pixel == self._previous_pixel: - self._run += 1 - if self._run == 62: - data += self._write_run() - else: - if self._run: - data += self._write_run() - - r, g, b, a = pixel - hash_value = (r * 3 + g * 5 + b * 7 + a * 11) % 64 - if self._previously_seen_pixels.get(hash_value) == pixel: - data += o8(hash_value) # QOI_OP_INDEX - elif self._previous_pixel: - self._previously_seen_pixels[hash_value] = pixel - - prev_r, prev_g, prev_b, prev_a = self._previous_pixel - if prev_a == a: - delta_r = self._delta(r, prev_r) - delta_g = self._delta(g, prev_g) - delta_b = self._delta(b, prev_b) - - if ( - -2 <= delta_r < 2 - and -2 <= delta_g < 2 - and -2 <= delta_b < 2 - ): - data += o8( - 0b01000000 - | (delta_r + 2) << 4 - | (delta_g + 2) << 2 - | (delta_b + 2) - ) # QOI_OP_DIFF - else: - delta_gr = self._delta(delta_r, delta_g) - delta_gb = self._delta(delta_b, delta_g) - if ( - -8 <= delta_gr < 8 - and -32 <= delta_g < 32 - and -8 <= delta_gb < 8 - ): - data += o8( - 0b10000000 | (delta_g + 32) - ) # QOI_OP_LUMA - data += o8((delta_gr + 8) << 4 | (delta_gb + 8)) - else: - data += o8(0b11111110) # QOI_OP_RGB - data += bytes(pixel[:3]) - else: - data += o8(0b11111111) # QOI_OP_RGBA - data += bytes(pixel) - - self._previous_pixel = pixel - - if self._run: - data += self._write_run() - data += bytes((0, 0, 0, 0, 0, 0, 0, 1)) # padding - - return len(data), 0, data - - Image.register_open(QoiImageFile.format, QoiImageFile, _accept) Image.register_decoder("qoi", QoiDecoder) Image.register_extension(QoiImageFile.format, ".qoi") - -Image.register_save(QoiImageFile.format, _save) -Image.register_encoder("qoi", QoiEncoder) diff --git a/venv/Lib/site-packages/PIL/SgiImagePlugin.py b/venv/Lib/site-packages/PIL/SgiImagePlugin.py index 8530221..50d9791 100644 --- a/venv/Lib/site-packages/PIL/SgiImagePlugin.py +++ b/venv/Lib/site-packages/PIL/SgiImagePlugin.py @@ -82,10 +82,17 @@ class SgiImageFile(ImageFile.ImageFile): # zsize : channels count zsize = i16(s, 10) + # layout + layout = bpc, dimension, zsize + # determine mode from bits/zsize + rawmode = "" try: - rawmode = MODES[(bpc, dimension, zsize)] + rawmode = MODES[layout] except KeyError: + pass + + if rawmode == "": msg = "Unsupported SGI image mode" raise ValueError(msg) @@ -102,28 +109,19 @@ class SgiImageFile(ImageFile.ImageFile): pagesize = xsize * ysize * bpc if bpc == 2: self.tile = [ - ImageFile._Tile( - "SGI16", - (0, 0) + self.size, - headlen, - (self.mode, 0, orientation), - ) + ("SGI16", (0, 0) + self.size, headlen, (self.mode, 0, orientation)) ] else: self.tile = [] offset = headlen for layer in self.mode: self.tile.append( - ImageFile._Tile( - "raw", (0, 0) + self.size, offset, (layer, 0, orientation) - ) + ("raw", (0, 0) + self.size, offset, (layer, 0, orientation)) ) offset += pagesize elif compression == 1: self.tile = [ - ImageFile._Tile( - "sgi_rle", (0, 0) + self.size, headlen, (rawmode, orientation, bpc) - ) + ("sgi_rle", (0, 0) + self.size, headlen, (rawmode, orientation, bpc)) ] @@ -149,15 +147,24 @@ def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: # Run-Length Encoding Compression - Unsupported at this time rle = 0 + # Number of dimensions (x,y,z) + dim = 3 # X Dimension = width / Y Dimension = height x, y = im.size + if im.mode == "L" and y == 1: + dim = 1 + elif im.mode == "L": + dim = 2 # Z Dimension: Number of channels z = len(im.mode) - # Number of dimensions (x,y,z) - if im.mode == "L": - dimension = 1 if y == 1 else 2 - else: - dimension = 3 + + if dim in {1, 2}: + z = 1 + + # assert we've got the right number of bands. + if len(im.getbands()) != z: + msg = f"incorrect number of bands in SGI write: {z} vs {len(im.getbands())}" + raise ValueError(msg) # Minimum Byte value pinmin = 0 @@ -172,7 +179,7 @@ def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: fp.write(struct.pack(">h", magic_number)) fp.write(o8(rle)) fp.write(o8(bpc)) - fp.write(struct.pack(">H", dimension)) + fp.write(struct.pack(">H", dim)) fp.write(struct.pack(">H", x)) fp.write(struct.pack(">H", y)) fp.write(struct.pack(">H", z)) @@ -198,7 +205,7 @@ def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: class SGI16Decoder(ImageFile.PyDecoder): _pulls_fd = True - def decode(self, buffer: bytes | Image.SupportsArrayInterface) -> tuple[int, int]: + def decode(self, buffer: bytes) -> tuple[int, int]: assert self.fd is not None assert self.im is not None diff --git a/venv/Lib/site-packages/PIL/SpiderImagePlugin.py b/venv/Lib/site-packages/PIL/SpiderImagePlugin.py index 8662922..f5a09c3 100644 --- a/venv/Lib/site-packages/PIL/SpiderImagePlugin.py +++ b/venv/Lib/site-packages/PIL/SpiderImagePlugin.py @@ -37,12 +37,9 @@ from __future__ import annotations import os import struct import sys -from typing import IO, Any, cast +from typing import IO, TYPE_CHECKING, Any, Tuple, cast from . import Image, ImageFile -from ._util import DeferredError - -TYPE_CHECKING = False def isInt(f: Any) -> int: @@ -104,7 +101,6 @@ class SpiderImageFile(ImageFile.ImageFile): def _open(self) -> None: # check header n = 27 * 4 # read 27 float values - assert self.fp is not None f = self.fp.read(n) try: @@ -158,7 +154,7 @@ class SpiderImageFile(ImageFile.ImageFile): self.rawmode = "F;32F" self._mode = "F" - self.tile = [ImageFile._Tile("raw", (0, 0) + self.size, offset, self.rawmode)] + self.tile = [("raw", (0, 0) + self.size, offset, (self.rawmode, 0, 1))] self._fp = self.fp # FIXME: hack @property @@ -182,8 +178,6 @@ class SpiderImageFile(ImageFile.ImageFile): raise EOFError(msg) if not self._seek_check(frame): return - if isinstance(self._fp, DeferredError): - raise self._fp.ex self.stkoffset = self.hdrlen + frame * (self.hdrlen + self.imgbytes) self.fp = self._fp self.fp.seek(self.stkoffset) @@ -193,7 +187,7 @@ class SpiderImageFile(ImageFile.ImageFile): def convert2byte(self, depth: int = 255) -> Image.Image: extrema = self.getextrema() assert isinstance(extrema[0], float) - minimum, maximum = cast(tuple[float, float], extrema) + minimum, maximum = cast(Tuple[float, float], extrema) m: float = 1 if maximum != minimum: m = depth / (maximum - minimum) @@ -215,27 +209,26 @@ class SpiderImageFile(ImageFile.ImageFile): # given a list of filenames, return a list of images -def loadImageSeries(filelist: list[str] | None = None) -> list[Image.Image] | None: +def loadImageSeries(filelist: list[str] | None = None) -> list[SpiderImageFile] | None: """create a list of :py:class:`~PIL.Image.Image` objects for use in a montage""" if filelist is None or len(filelist) < 1: return None - byte_imgs = [] + imglist = [] for img in filelist: if not os.path.exists(img): print(f"unable to find {img}") continue try: with Image.open(img) as im: - assert isinstance(im, SpiderImageFile) - byte_im = im.convert2byte() + im = im.convert2byte() except Exception: if not isSpiderImage(img): print(f"{img} is not a Spider image file") continue - byte_im.info["filename"] = img - byte_imgs.append(byte_im) - return byte_imgs + im.info["filename"] = img + imglist.append(im) + return imglist # -------------------------------------------------------------------- @@ -273,7 +266,7 @@ def makeSpiderHeader(im: Image.Image) -> list[bytes]: def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: - if im.mode != "F": + if im.mode[0] != "F": im = im.convert("F") hdr = makeSpiderHeader(im) @@ -285,7 +278,7 @@ def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: fp.writelines(hdr) rawmode = "F;32NF" # 32-bit native floating point - ImageFile._save(im, fp, [ImageFile._Tile("raw", (0, 0) + im.size, 0, rawmode)]) + ImageFile._save(im, fp, [("raw", (0, 0) + im.size, 0, (rawmode, 0, 1))]) def _save_spider(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: @@ -324,9 +317,9 @@ if __name__ == "__main__": outfile = sys.argv[2] # perform some image operation - transposed_im = im.transpose(Image.Transpose.FLIP_LEFT_RIGHT) + im = im.transpose(Image.Transpose.FLIP_LEFT_RIGHT) print( f"saving a flipped version of {os.path.basename(filename)} " f"as {outfile} " ) - transposed_im.save(outfile, SpiderImageFile.format) + im.save(outfile, SpiderImageFile.format) diff --git a/venv/Lib/site-packages/PIL/SunImagePlugin.py b/venv/Lib/site-packages/PIL/SunImagePlugin.py index 8912379..4e09847 100644 --- a/venv/Lib/site-packages/PIL/SunImagePlugin.py +++ b/venv/Lib/site-packages/PIL/SunImagePlugin.py @@ -124,13 +124,9 @@ class SunImageFile(ImageFile.ImageFile): # (https://www.fileformat.info/format/sunraster/egff.htm) if file_type in (0, 1, 3, 4, 5): - self.tile = [ - ImageFile._Tile("raw", (0, 0) + self.size, offset, (rawmode, stride)) - ] + self.tile = [("raw", (0, 0) + self.size, offset, (rawmode, stride))] elif file_type == 2: - self.tile = [ - ImageFile._Tile("sun_rle", (0, 0) + self.size, offset, rawmode) - ] + self.tile = [("sun_rle", (0, 0) + self.size, offset, rawmode)] else: msg = "Unsupported Sun Raster file type" raise SyntaxError(msg) diff --git a/venv/Lib/site-packages/PIL/TarIO.py b/venv/Lib/site-packages/PIL/TarIO.py index 86490a4..cba26d4 100644 --- a/venv/Lib/site-packages/PIL/TarIO.py +++ b/venv/Lib/site-packages/PIL/TarIO.py @@ -35,16 +35,12 @@ class TarIO(ContainerIO.ContainerIO[bytes]): while True: s = self.fh.read(512) if len(s) != 512: - self.fh.close() - msg = "unexpected end of tar file" raise OSError(msg) name = s[:100].decode("utf-8") i = name.find("\0") if i == 0: - self.fh.close() - msg = "cannot find subfile" raise OSError(msg) if i > 0: @@ -59,3 +55,13 @@ class TarIO(ContainerIO.ContainerIO[bytes]): # Open region super().__init__(self.fh, self.fh.tell(), size) + + # Context manager support + def __enter__(self) -> TarIO: + return self + + def __exit__(self, *args: object) -> None: + self.close() + + def close(self) -> None: + self.fh.close() diff --git a/venv/Lib/site-packages/PIL/TgaImagePlugin.py b/venv/Lib/site-packages/PIL/TgaImagePlugin.py index 90d5b5c..39104ae 100644 --- a/venv/Lib/site-packages/PIL/TgaImagePlugin.py +++ b/venv/Lib/site-packages/PIL/TgaImagePlugin.py @@ -137,7 +137,7 @@ class TgaImageFile(ImageFile.ImageFile): if imagetype & 8: # compressed self.tile = [ - ImageFile._Tile( + ( "tga_rle", (0, 0) + self.size, self.fp.tell(), @@ -146,7 +146,7 @@ class TgaImageFile(ImageFile.ImageFile): ] else: self.tile = [ - ImageFile._Tile( + ( "raw", (0, 0) + self.size, self.fp.tell(), @@ -158,6 +158,7 @@ class TgaImageFile(ImageFile.ImageFile): def load_end(self) -> None: if self._flip_horizontally: + assert self.im is not None self.im = self.im.transpose(Image.Transpose.FLIP_LEFT_RIGHT) @@ -199,6 +200,7 @@ def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: warnings.warn("id_section has been trimmed to 255 characters") if colormaptype: + assert im.im is not None palette = im.im.getpalette("RGB", "BGR") colormaplength, colormapentry = len(palette) // 3, 24 else: @@ -236,15 +238,11 @@ def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: if rle: ImageFile._save( - im, - fp, - [ImageFile._Tile("tga_rle", (0, 0) + im.size, 0, (rawmode, orientation))], + im, fp, [("tga_rle", (0, 0) + im.size, 0, (rawmode, orientation))] ) else: ImageFile._save( - im, - fp, - [ImageFile._Tile("raw", (0, 0) + im.size, 0, (rawmode, 0, orientation))], + im, fp, [("raw", (0, 0) + im.size, 0, (rawmode, 0, orientation))] ) # write targa version 2 footer diff --git a/venv/Lib/site-packages/PIL/TiffImagePlugin.py b/venv/Lib/site-packages/PIL/TiffImagePlugin.py index de2ce06..ac5b63c 100644 --- a/venv/Lib/site-packages/PIL/TiffImagePlugin.py +++ b/venv/Lib/site-packages/PIL/TiffImagePlugin.py @@ -47,30 +47,24 @@ import math import os import struct import warnings -from collections.abc import Callable, MutableMapping +from collections.abc import MutableMapping from fractions import Fraction from numbers import Number, Rational -from typing import IO, Any, cast +from typing import IO, TYPE_CHECKING, Any, Callable, NoReturn from . import ExifTags, Image, ImageFile, ImageOps, ImagePalette, TiffTags from ._binary import i16be as i16 from ._binary import i32be as i32 from ._binary import o8 -from ._util import DeferredError, is_path +from ._deprecate import deprecate from .TiffTags import TYPES -TYPE_CHECKING = False -if TYPE_CHECKING: - from collections.abc import Iterator - from typing import NoReturn - - from ._typing import Buffer, IntegralLike, StrOrBytesPath - logger = logging.getLogger(__name__) # Set these to true to force use of libtiff for reading or writing. READ_LIBTIFF = False WRITE_LIBTIFF = False +IFD_LEGACY_API = True STRIP_SIZE = 65536 II = b"II" # little-endian (Intel style) @@ -252,7 +246,6 @@ OPEN_INFO = { (II, 3, (1,), 1, (8,), ()): ("P", "P"), (MM, 3, (1,), 1, (8,), ()): ("P", "P"), (II, 3, (1,), 1, (8, 8), (0,)): ("P", "PX"), - (MM, 3, (1,), 1, (8, 8), (0,)): ("P", "PX"), (II, 3, (1,), 1, (8, 8), (2,)): ("PA", "PA"), (MM, 3, (1,), 1, (8, 8), (2,)): ("PA", "PA"), (II, 3, (1,), 2, (8,), ()): ("P", "P;R"), @@ -264,7 +257,6 @@ OPEN_INFO = { (II, 5, (1,), 1, (8, 8, 8, 8, 8, 8), (0, 0)): ("CMYK", "CMYKXX"), (MM, 5, (1,), 1, (8, 8, 8, 8, 8, 8), (0, 0)): ("CMYK", "CMYKXX"), (II, 5, (1,), 1, (16, 16, 16, 16), ()): ("CMYK", "CMYK;16L"), - (MM, 5, (1,), 1, (16, 16, 16, 16), ()): ("CMYK", "CMYK;16B"), (II, 6, (1,), 1, (8,), ()): ("L", "L"), (MM, 6, (1,), 1, (8,), ()): ("L", "L"), # JPEG compressed images handled by LibTiff and auto-converted to RGBX @@ -278,39 +270,38 @@ OPEN_INFO = { MAX_SAMPLESPERPIXEL = max(len(key_tp[4]) for key_tp in OPEN_INFO) PREFIXES = [ - b"MM\x00\x2a", # Valid TIFF header with big-endian byte order - b"II\x2a\x00", # Valid TIFF header with little-endian byte order - b"MM\x2a\x00", # Invalid TIFF header, assume big-endian - b"II\x00\x2a", # Invalid TIFF header, assume little-endian - b"MM\x00\x2b", # BigTIFF with big-endian byte order - b"II\x2b\x00", # BigTIFF with little-endian byte order + b"MM\x00\x2A", # Valid TIFF header with big-endian byte order + b"II\x2A\x00", # Valid TIFF header with little-endian byte order + b"MM\x2A\x00", # Invalid TIFF header, assume big-endian + b"II\x00\x2A", # Invalid TIFF header, assume little-endian + b"MM\x00\x2B", # BigTIFF with big-endian byte order + b"II\x2B\x00", # BigTIFF with little-endian byte order ] +if not getattr(Image.core, "libtiff_support_custom_tags", True): + deprecate("Support for LibTIFF earlier than version 4", 12) + def _accept(prefix: bytes) -> bool: - return prefix.startswith(tuple(PREFIXES)) + return prefix[:4] in PREFIXES -def _limit_rational( - val: float | Fraction | IFDRational, max_val: int -) -> tuple[IntegralLike, IntegralLike]: +def _limit_rational(val, max_val): inv = abs(val) > 1 n_d = IFDRational(1 / val if inv else val).limit_rational(max_val) return n_d[::-1] if inv else n_d -def _limit_signed_rational( - val: IFDRational, max_val: int, min_val: int -) -> tuple[IntegralLike, IntegralLike]: +def _limit_signed_rational(val, max_val, min_val): frac = Fraction(val) - n_d: tuple[IntegralLike, IntegralLike] = frac.numerator, frac.denominator + n_d = frac.numerator, frac.denominator - if min(float(i) for i in n_d) < min_val: + if min(n_d) < min_val: n_d = _limit_rational(val, abs(min_val)) - n_d_float = tuple(float(i) for i in n_d) - if max(n_d_float) > max_val: - n_d = _limit_rational(n_d_float[0] / n_d_float[1], max_val) + if max(n_d) > max_val: + val = Fraction(*n_d) + n_d = _limit_rational(val, max_val) return n_d @@ -322,10 +313,8 @@ _load_dispatch = {} _write_dispatch = {} -def _delegate(op: str) -> Any: - def delegate( - self: IFDRational, *args: tuple[float, ...] - ) -> bool | float | Fraction: +def _delegate(op): + def delegate(self, *args): return getattr(self._val, op)(*args) return delegate @@ -345,15 +334,12 @@ class IFDRational(Rational): __slots__ = ("_numerator", "_denominator", "_val") - def __init__( - self, value: float | Fraction | IFDRational, denominator: int = 1 - ) -> None: + def __init__(self, value, denominator=1): """ :param value: either an integer numerator, a float/rational/other number, or an IFDRational :param denominator: Optional integer denominator """ - self._val: Fraction | float if isinstance(value, IFDRational): self._numerator = value.numerator self._denominator = value.denominator @@ -364,30 +350,25 @@ class IFDRational(Rational): self._numerator = value.numerator self._denominator = value.denominator else: - if TYPE_CHECKING: - self._numerator = cast(IntegralLike, value) - else: - self._numerator = value + self._numerator = value self._denominator = denominator if denominator == 0: self._val = float("nan") elif denominator == 1: self._val = Fraction(value) - elif int(value) == value: - self._val = Fraction(int(value), denominator) else: - self._val = Fraction(value / denominator) + self._val = Fraction(value, denominator) @property - def numerator(self) -> IntegralLike: + def numerator(self): return self._numerator @property - def denominator(self) -> int: + def denominator(self): return self._denominator - def limit_rational(self, max_denominator: int) -> tuple[IntegralLike, int]: + def limit_rational(self, max_denominator): """ :param max_denominator: Integer, the maximum denominator value @@ -397,14 +378,13 @@ class IFDRational(Rational): if self.denominator == 0: return self.numerator, self.denominator - assert isinstance(self._val, Fraction) f = self._val.limit_denominator(max_denominator) return f.numerator, f.denominator def __repr__(self) -> str: return str(float(self._val)) - def __hash__(self) -> int: # type: ignore[override] + def __hash__(self) -> int: return self._val.__hash__() def __eq__(self, other: object) -> bool: @@ -415,19 +395,14 @@ class IFDRational(Rational): val = float(val) return val == other - def __getstate__(self) -> list[float | Fraction | IntegralLike]: + def __getstate__(self): return [self._val, self._numerator, self._denominator] - def __setstate__(self, state: list[float | Fraction | IntegralLike]) -> None: + def __setstate__(self, state): IFDRational.__init__(self, 0) _val, _numerator, _denominator = state - assert isinstance(_val, (float, Fraction)) self._val = _val - if TYPE_CHECKING: - self._numerator = cast(IntegralLike, _numerator) - else: - self._numerator = _numerator - assert isinstance(_denominator, int) + self._numerator = _numerator self._denominator = _denominator """ a = ['add','radd', 'sub', 'rsub', 'mul', 'rmul', @@ -469,11 +444,8 @@ class IFDRational(Rational): __int__ = _delegate("__int__") -_LoaderFunc = Callable[["ImageFileDirectory_v2", bytes, bool], Any] - - -def _register_loader(idx: int, size: int) -> Callable[[_LoaderFunc], _LoaderFunc]: - def decorator(func: _LoaderFunc) -> _LoaderFunc: +def _register_loader(idx, size): + def decorator(func): from .TiffTags import TYPES if func.__name__.startswith("load_"): @@ -484,27 +456,26 @@ def _register_loader(idx: int, size: int) -> Callable[[_LoaderFunc], _LoaderFunc return decorator -def _register_writer(idx: int) -> Callable[[Callable[..., Any]], Callable[..., Any]]: - def decorator(func: Callable[..., Any]) -> Callable[..., Any]: +def _register_writer(idx): + def decorator(func): _write_dispatch[idx] = func # noqa: F821 return func return decorator -def _register_basic(idx_fmt_name: tuple[int, str, str]) -> None: +def _register_basic(idx_fmt_name): from .TiffTags import TYPES idx, fmt, name = idx_fmt_name TYPES[idx] = name size = struct.calcsize(f"={fmt}") - - def basic_handler( - self: ImageFileDirectory_v2, data: bytes, legacy_api: bool = True - ) -> tuple[Any, ...]: - return self._unpack(f"{len(data) // size}{fmt}", data) - - _load_dispatch[idx] = size, basic_handler # noqa: F821 + _load_dispatch[idx] = ( # noqa: F821 + size, + lambda self, data, legacy_api=True: ( + self._unpack(f"{len(data) // size}{fmt}", data) + ), + ) _write_dispatch[idx] = lambda self, *values: ( # noqa: F821 b"".join(self._pack(fmt, value) for value in values) ) @@ -577,12 +548,12 @@ class ImageFileDirectory_v2(_IFDv2Base): """ - _load_dispatch: dict[int, tuple[int, _LoaderFunc]] = {} + _load_dispatch: dict[int, Callable[[ImageFileDirectory_v2, bytes, bool], Any]] = {} _write_dispatch: dict[int, Callable[..., Any]] = {} def __init__( self, - ifh: bytes = b"II\x2a\x00\x00\x00\x00\x00", + ifh: bytes = b"II\052\0\0\0\0\0", prefix: bytes | None = None, group: int | None = None, ) -> None: @@ -612,10 +583,8 @@ class ImageFileDirectory_v2(_IFDv2Base): self.tagtype: dict[int, int] = {} """ Dictionary of tag types """ self.reset() - self.next = ( - self._unpack("Q", ifh[8:])[0] - if self._bigtiff - else self._unpack("L", ifh[4:])[0] + (self.next,) = ( + self._unpack("Q", ifh[8:]) if self._bigtiff else self._unpack("L", ifh[4:]) ) self._legacy_api = False @@ -637,12 +606,12 @@ class ImageFileDirectory_v2(_IFDv2Base): self._tagdata: dict[int, bytes] = {} self.tagtype = {} # added 2008-06-05 by Florian Hoech self._next = None - self._offset: int | None = None + self._offset = None def __str__(self) -> str: return str(dict(self)) - def named(self) -> dict[str, Any]: + def named(self): """ :returns: dict of name|key: value @@ -656,7 +625,7 @@ class ImageFileDirectory_v2(_IFDv2Base): def __len__(self) -> int: return len(set(self._tagdata) | set(self._tags_v2)) - def __getitem__(self, tag: int) -> Any: + def __getitem__(self, tag): if tag not in self._tags_v2: # unpack on the fly data = self._tagdata[tag] typ = self.tagtype[tag] @@ -667,13 +636,13 @@ class ImageFileDirectory_v2(_IFDv2Base): val = (val,) return val - def __contains__(self, tag: object) -> bool: + def __contains__(self, tag): return tag in self._tags_v2 or tag in self._tagdata - def __setitem__(self, tag: int, value: Any) -> None: + def __setitem__(self, tag, value): self._setitem(tag, value, self.legacy_api) - def _setitem(self, tag: int, value: Any, legacy_api: bool) -> None: + def _setitem(self, tag, value, legacy_api): basetypes = (Number, bytes, str) info = TiffTags.lookup(tag, self.group) @@ -685,33 +654,22 @@ class ImageFileDirectory_v2(_IFDv2Base): else: self.tagtype[tag] = TiffTags.UNDEFINED if all(isinstance(v, IFDRational) for v in values): - for v in values: - assert isinstance(v, IFDRational) - if v < 0: - self.tagtype[tag] = TiffTags.SIGNED_RATIONAL - break - else: - self.tagtype[tag] = TiffTags.RATIONAL + self.tagtype[tag] = ( + TiffTags.RATIONAL + if all(v >= 0 for v in values) + else TiffTags.SIGNED_RATIONAL + ) elif all(isinstance(v, int) for v in values): - short = True - signed_short = True - long = True - for v in values: - assert isinstance(v, int) - if short and not (0 <= v < 2**16): - short = False - if signed_short and not (-(2**15) < v < 2**15): - signed_short = False - if long and v < 0: - long = False - if short: + if all(0 <= v < 2**16 for v in values): self.tagtype[tag] = TiffTags.SHORT - elif signed_short: + elif all(-(2**15) < v < 2**15 for v in values): self.tagtype[tag] = TiffTags.SIGNED_SHORT - elif long: - self.tagtype[tag] = TiffTags.LONG else: - self.tagtype[tag] = TiffTags.SIGNED_LONG + self.tagtype[tag] = ( + TiffTags.LONG + if all(v >= 0 for v in values) + else TiffTags.SIGNED_LONG + ) elif all(isinstance(v, float) for v in values): self.tagtype[tag] = TiffTags.DOUBLE elif all(isinstance(v, str) for v in values): @@ -729,10 +687,7 @@ class ImageFileDirectory_v2(_IFDv2Base): is_ifd = self.tagtype[tag] == TiffTags.LONG and isinstance(values, dict) if not is_ifd: - values = tuple( - info.cvt_enum(value) if isinstance(value, str) else value - for value in values - ) + values = tuple(info.cvt_enum(value) for value in values) dest = self._tags_v1 if legacy_api else self._tags_v2 @@ -772,13 +727,13 @@ class ImageFileDirectory_v2(_IFDv2Base): self._tags_v1.pop(tag, None) self._tagdata.pop(tag, None) - def __iter__(self) -> Iterator[int]: + def __iter__(self): return iter(set(self._tagdata) | set(self._tags_v2)) - def _unpack(self, fmt: str, data: bytes) -> tuple[Any, ...]: + def _unpack(self, fmt, data): return struct.unpack(self._endian + fmt, data) - def _pack(self, fmt: str, *values: Any) -> bytes: + def _pack(self, fmt, *values): return struct.pack(self._endian + fmt, *values) list( @@ -799,11 +754,11 @@ class ImageFileDirectory_v2(_IFDv2Base): ) @_register_loader(1, 1) # Basic type, except for the legacy API. - def load_byte(self, data: bytes, legacy_api: bool = True) -> bytes: + def load_byte(self, data, legacy_api=True): return data @_register_writer(1) # Basic type, except for the legacy API. - def write_byte(self, data: bytes | int | IFDRational) -> bytes: + def write_byte(self, data): if isinstance(data, IFDRational): data = int(data) if isinstance(data, int): @@ -811,13 +766,13 @@ class ImageFileDirectory_v2(_IFDv2Base): return data @_register_loader(2, 1) - def load_string(self, data: bytes, legacy_api: bool = True) -> str: + def load_string(self, data, legacy_api=True): if data.endswith(b"\0"): data = data[:-1] return data.decode("latin-1", "replace") @_register_writer(2) - def write_string(self, value: str | bytes | int) -> bytes: + def write_string(self, value): # remerge of https://github.com/python-pillow/Pillow/pull/1416 if isinstance(value, int): value = str(value) @@ -826,28 +781,26 @@ class ImageFileDirectory_v2(_IFDv2Base): return value + b"\0" @_register_loader(5, 8) - def load_rational( - self, data: bytes, legacy_api: bool = True - ) -> tuple[tuple[int, int] | IFDRational, ...]: + def load_rational(self, data, legacy_api=True): vals = self._unpack(f"{len(data) // 4}L", data) - def combine(a: int, b: int) -> tuple[int, int] | IFDRational: + def combine(a, b): return (a, b) if legacy_api else IFDRational(a, b) return tuple(combine(num, denom) for num, denom in zip(vals[::2], vals[1::2])) @_register_writer(5) - def write_rational(self, *values: IFDRational) -> bytes: + def write_rational(self, *values): return b"".join( self._pack("2L", *_limit_rational(frac, 2**32 - 1)) for frac in values ) @_register_loader(7, 1) - def load_undefined(self, data: bytes, legacy_api: bool = True) -> bytes: + def load_undefined(self, data, legacy_api=True): return data @_register_writer(7) - def write_undefined(self, value: bytes | int | IFDRational) -> bytes: + def write_undefined(self, value): if isinstance(value, IFDRational): value = int(value) if isinstance(value, int): @@ -855,24 +808,22 @@ class ImageFileDirectory_v2(_IFDv2Base): return value @_register_loader(10, 8) - def load_signed_rational( - self, data: bytes, legacy_api: bool = True - ) -> tuple[tuple[int, int] | IFDRational, ...]: + def load_signed_rational(self, data, legacy_api=True): vals = self._unpack(f"{len(data) // 4}l", data) - def combine(a: int, b: int) -> tuple[int, int] | IFDRational: + def combine(a, b): return (a, b) if legacy_api else IFDRational(a, b) return tuple(combine(num, denom) for num, denom in zip(vals[::2], vals[1::2])) @_register_writer(10) - def write_signed_rational(self, *values: IFDRational) -> bytes: + def write_signed_rational(self, *values): return b"".join( self._pack("2l", *_limit_signed_rational(frac, 2**31 - 1, -(2**31))) for frac in values ) - def _ensure_read(self, fp: IO[bytes], size: int) -> bytes: + def _ensure_read(self, fp, size): ret = fp.read(size) if len(ret) != size: msg = ( @@ -882,7 +833,7 @@ class ImageFileDirectory_v2(_IFDv2Base): raise OSError(msg) return ret - def load(self, fp: IO[bytes]) -> None: + def load(self, fp): self.reset() self._offset = fp.tell() @@ -935,9 +886,9 @@ class ImageFileDirectory_v2(_IFDv2Base): self._tagdata[tag] = data self.tagtype[tag] = typ - msg += " - value: " - msg += f"" if size > 32 else repr(data) - + msg += " - value: " + ( + "" % size if size > 32 else repr(data) + ) logger.debug(msg) (self.next,) = ( @@ -949,25 +900,12 @@ class ImageFileDirectory_v2(_IFDv2Base): warnings.warn(str(msg)) return - def _get_ifh(self) -> bytes: - ifh = self._prefix + self._pack("H", 43 if self._bigtiff else 42) - if self._bigtiff: - ifh += self._pack("HH", 8, 0) - ifh += self._pack("Q", 16) if self._bigtiff else self._pack("L", 8) - - return ifh - - def tobytes(self, offset: int = 0) -> bytes: + def tobytes(self, offset=0): # FIXME What about tagdata? - result = self._pack("Q" if self._bigtiff else "H", len(self._tags_v2)) + result = self._pack("H", len(self._tags_v2)) - entries: list[tuple[int, int, int, bytes, bytes]] = [] - - fmt = "Q" if self._bigtiff else "L" - fmt_size = 8 if self._bigtiff else 4 - offset += ( - len(result) + len(self._tags_v2) * (20 if self._bigtiff else 12) + fmt_size - ) + entries = [] + offset = offset + len(result) + len(self._tags_v2) * 12 + 4 stripoffsets = None # pass 1: convert tags to binary format @@ -975,11 +913,15 @@ class ImageFileDirectory_v2(_IFDv2Base): for tag, value in sorted(self._tags_v2.items()): if tag == STRIPOFFSETS: stripoffsets = len(entries) - typ = self.tagtype[tag] + typ = self.tagtype.get(tag) logger.debug("Tag %s, Type: %s, Value: %s", tag, typ, repr(value)) is_ifd = typ == TiffTags.LONG and isinstance(value, dict) if is_ifd: - ifd = ImageFileDirectory_v2(self._get_ifh(), group=tag) + if self._endian == "<": + ifh = b"II\x2A\x00\x08\x00\x00\x00" + else: + ifh = b"MM\x00\x2A\x00\x00\x00\x08" + ifd = ImageFileDirectory_v2(ifh, group=tag) values = self._tags_v2[tag] for ifd_tag, ifd_value in values.items(): ifd[ifd_tag] = ifd_value @@ -990,8 +932,10 @@ class ImageFileDirectory_v2(_IFDv2Base): tagname = TiffTags.lookup(tag, self.group).name typname = "ifd" if is_ifd else TYPES.get(typ, "unknown") - msg = f"save: {tagname} ({tag}) - type: {typname} ({typ}) - value: " - msg += f"" if len(data) >= 16 else str(values) + msg = f"save: {tagname} ({tag}) - type: {typname} ({typ})" + msg += " - value: " + ( + "" % len(data) if len(data) >= 16 else str(values) + ) logger.debug(msg) # count is sum of lengths for string and arbitrary data @@ -1002,32 +946,28 @@ class ImageFileDirectory_v2(_IFDv2Base): else: count = len(values) # figure out if data fits into the entry - if len(data) <= fmt_size: - entries.append((tag, typ, count, data.ljust(fmt_size, b"\0"), b"")) + if len(data) <= 4: + entries.append((tag, typ, count, data.ljust(4, b"\0"), b"")) else: - entries.append((tag, typ, count, self._pack(fmt, offset), data)) + entries.append((tag, typ, count, self._pack("L", offset), data)) offset += (len(data) + 1) // 2 * 2 # pad to word # update strip offset data to point beyond auxiliary data if stripoffsets is not None: tag, typ, count, value, data = entries[stripoffsets] if data: - size, handler = self._load_dispatch[typ] - values = [val + offset for val in handler(self, data, self.legacy_api)] - data = self._write_dispatch[typ](self, *values) - else: - value = self._pack(fmt, self._unpack(fmt, value)[0] + offset) + msg = "multistrip support not yet implemented" + raise NotImplementedError(msg) + value = self._pack("L", self._unpack("L", value)[0] + offset) entries[stripoffsets] = tag, typ, count, value, data # pass 2: write entries to file for tag, typ, count, value, data in entries: logger.debug("%s %s %s %s %s", tag, typ, count, repr(value), repr(data)) - result += self._pack( - "HHQ8s" if self._bigtiff else "HHL4s", tag, typ, count, value - ) + result += self._pack("HHL4s", tag, typ, count, value) # -- overwrite here for multi-page -- - result += self._pack(fmt, 0) # end of entries + result += b"\0\0\0\0" # end of entries # pass 3: write auxiliary data to file for tag, typ, count, value, data in entries: @@ -1037,9 +977,10 @@ class ImageFileDirectory_v2(_IFDv2Base): return result - def save(self, fp: IO[bytes]) -> int: + def save(self, fp): if fp.tell() == 0: # skip TIFF header on subsequent pages - fp.write(self._get_ifh()) + # tiff header -- PIL always starts the first IFD at offset 8 + fp.write(self._prefix + self._pack("HL", 42, 8)) offset = fp.tell() result = self.tobytes(offset) @@ -1076,7 +1017,7 @@ class ImageFileDirectory_v1(ImageFileDirectory_v2): .. deprecated:: 3.0.0 """ - def __init__(self, *args: Any, **kwargs: Any) -> None: + def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self._legacy_api = True @@ -1088,7 +1029,7 @@ class ImageFileDirectory_v1(ImageFileDirectory_v2): """Dictionary of tag types""" @classmethod - def from_v2(cls, original: ImageFileDirectory_v2) -> ImageFileDirectory_v1: + def from_v2(cls, original): """Returns an :py:class:`~PIL.TiffImagePlugin.ImageFileDirectory_v1` instance with the same data as is contained in the original @@ -1122,20 +1063,20 @@ class ImageFileDirectory_v1(ImageFileDirectory_v2): ifd._tags_v2 = dict(self._tags_v2) return ifd - def __contains__(self, tag: object) -> bool: + def __contains__(self, tag): return tag in self._tags_v1 or tag in self._tagdata def __len__(self) -> int: return len(set(self._tagdata) | set(self._tags_v1)) - def __iter__(self) -> Iterator[int]: + def __iter__(self): return iter(set(self._tagdata) | set(self._tags_v1)) - def __setitem__(self, tag: int, value: Any) -> None: + def __setitem__(self, tag, value): for legacy_api in (False, True): self._setitem(tag, value, legacy_api) - def __getitem__(self, tag: int) -> Any: + def __getitem__(self, tag): if tag not in self._tags_v1: # unpack on the fly data = self._tagdata[tag] typ = self.tagtype[tag] @@ -1148,7 +1089,7 @@ class ImageFileDirectory_v1(ImageFileDirectory_v2): return val -# undone -- switch this pointer +# undone -- switch this pointer when IFD_LEGACY_API == False ImageFileDirectory = ImageFileDirectory_v1 @@ -1161,15 +1102,11 @@ class TiffImageFile(ImageFile.ImageFile): format_description = "Adobe TIFF" _close_exclusive_fp_after_loading = False - def __init__( - self, - fp: StrOrBytesPath | IO[bytes], - filename: str | bytes | None = None, - ) -> None: - self.tag_v2: ImageFileDirectory_v2 + def __init__(self, fp=None, filename=None): + self.tag_v2 = None """ Image file directory (tag dictionary) """ - self.tag: ImageFileDirectory_v1 + self.tag = None """ Legacy tag entries """ super().__init__(fp, filename) @@ -1178,13 +1115,15 @@ class TiffImageFile(ImageFile.ImageFile): """Open the first image in a TIFF file""" # Header - assert self.fp is not None ifh = self.fp.read(8) if ifh[2] == 43: ifh += self.fp.read(8) self.tag_v2 = ImageFileDirectory_v2(ifh) + # legacy IFD entries will be filled in later + self.ifd = None + # setup frame pointers self.__first = self.__next = self.tag_v2.next self.__frame = -1 @@ -1200,15 +1139,13 @@ class TiffImageFile(ImageFile.ImageFile): self._seek(0) @property - def n_frames(self) -> int: - current_n_frames = self._n_frames - if current_n_frames is None: + def n_frames(self): + if self._n_frames is None: current = self.tell() self._seek(len(self._frame_pos)) while self._n_frames is None: self._seek(self.tell() + 1) self.seek(current) - assert self._n_frames is not None return self._n_frames def seek(self, frame: int) -> None: @@ -1216,18 +1153,19 @@ class TiffImageFile(ImageFile.ImageFile): if not self._seek_check(frame): return self._seek(frame) - if self._im is not None and ( - self.im.size != self._tile_size - or self.im.mode != self.mode - or self.readonly - ): - self._im = None + # Create a new core image object on second and + # subsequent frames in the image. Image may be + # different size/mode. + Image._decompression_bomb_check(self.size) + self.im = Image.core.new(self.mode, self.size) def _seek(self, frame: int) -> None: - if isinstance(self._fp, DeferredError): - raise self._fp.ex self.fp = self._fp + # reset buffered io handle in case fp + # was passed to libtiff, invalidating the buffer + self.fp.tell() + while len(self._frame_pos) <= frame: if not self.__next: msg = "no more images in TIFF file" @@ -1260,10 +1198,7 @@ class TiffImageFile(ImageFile.ImageFile): self.fp.seek(self._frame_pos[frame]) self.tag_v2.load(self.fp) if XMP in self.tag_v2: - xmp = self.tag_v2[XMP] - if isinstance(xmp, tuple) and len(xmp) == 1: - xmp = xmp[0] - self.info["xmp"] = xmp + self.info["xmp"] = self.tag_v2[XMP] elif "xmp" in self.info: del self.info["xmp"] self._reload_exif() @@ -1276,7 +1211,7 @@ class TiffImageFile(ImageFile.ImageFile): """Return the current frame number""" return self.__frame - def get_photoshop_blocks(self) -> dict[int, dict[str, bytes]]: + def get_photoshop_blocks(self): """ Returns a dictionary of Photoshop "Image Resource Blocks". The keys are the image resource ID. For more information, see @@ -1287,7 +1222,7 @@ class TiffImageFile(ImageFile.ImageFile): blocks = {} val = self.tag_v2.get(ExifTags.Base.ImageResources) if val: - while val.startswith(b"8BIM"): + while val[:4] == b"8BIM": id = i16(val[4:6]) n = math.ceil((val[6] + 1) / 2) * 2 size = i32(val[6 + n : 10 + n]) @@ -1297,23 +1232,21 @@ class TiffImageFile(ImageFile.ImageFile): val = val[math.ceil((10 + n + size) / 2) * 2 :] return blocks - def load(self) -> Image.core.PixelAccess | None: + def load(self): if self.tile and self.use_load_libtiff: return self._load_libtiff() return super().load() - def load_prepare(self) -> None: - if self._im is None: - Image._decompression_bomb_check(self._tile_size) - self.im = Image.core.new(self.mode, self._tile_size) - ImageFile.ImageFile.load_prepare(self) - def load_end(self) -> None: # allow closing if we're on the first frame, there's no next # This is the ImageFile.load path only, libtiff specific below. if not self.is_animated: self._close_exclusive_fp_after_loading = True + # reset buffered io handle in case fp + # was passed to libtiff, invalidating the buffer + self.fp.tell() + # load IFD data from fp before it is closed exif = self.getexif() for key in TiffTags.TAGS_V2_GROUPS: @@ -1325,7 +1258,7 @@ class TiffImageFile(ImageFile.ImageFile): if ExifTags.Base.Orientation in self.tag_v2: del self.tag_v2[ExifTags.Base.Orientation] - def _load_libtiff(self) -> Image.core.PixelAccess | None: + def _load_libtiff(self): """Overload method triggered when we detect a compressed tiff Calls out to libtiff""" @@ -1340,12 +1273,11 @@ class TiffImageFile(ImageFile.ImageFile): # (self._compression, (extents tuple), # 0, (rawmode, self._compression, fp)) extents = self.tile[0][1] - args = self.tile[0][3] + args = list(self.tile[0][3]) # To be nice on memory footprint, if there's a # file descriptor, use that instead of reading # into a string in python. - assert self.fp is not None try: fp = hasattr(self.fp, "fileno") and self.fp.fileno() # flush the file descriptor, prevents error on pypy 2.4+ @@ -1359,12 +1291,11 @@ class TiffImageFile(ImageFile.ImageFile): fp = False if fp: - assert isinstance(args, tuple) - args_list = list(args) - args_list[2] = fp - args = tuple(args_list) + args[2] = fp - decoder = Image._getdecoder(self.mode, "libtiff", args, self.decoderconfig) + decoder = Image._getdecoder( + self.mode, "libtiff", tuple(args), self.decoderconfig + ) try: decoder.setimage(self.im, extents) except ValueError as e: @@ -1389,17 +1320,8 @@ class TiffImageFile(ImageFile.ImageFile): logger.debug("have fileno, calling fileno version of the decoder.") if not close_self_fp: self.fp.seek(0) - # Save and restore the file position, because libtiff will move it - # outside of the Python runtime, and that will confuse - # io.BufferedReader and possible others. - # NOTE: This must use os.lseek(), and not fp.tell()/fp.seek(), - # because the buffer read head already may not equal the actual - # file position, and fp.seek() may just adjust it's internal - # pointer and not actually seek the OS file handle. - pos = os.lseek(fp, 0, os.SEEK_CUR) # 4 bytes, otherwise the trace might error out n, err = decoder.decode(b"fpfp") - os.lseek(fp, pos, os.SEEK_SET) else: # we have something else. logger.debug("don't have fileno or getvalue. just reading") @@ -1417,12 +1339,11 @@ class TiffImageFile(ImageFile.ImageFile): self.fp = None # might be shared if err < 0: - msg = f"decoder error {err}" - raise OSError(msg) + raise OSError(err) return Image.Image.load(self) - def _setup(self) -> None: + def _setup(self): """Setup this image object based on current tags""" if 0xBC01 in self.tag_v2: @@ -1448,24 +1369,12 @@ class TiffImageFile(ImageFile.ImageFile): logger.debug("- photometric_interpretation: %s", photo) logger.debug("- planar_configuration: %s", self._planar_configuration) logger.debug("- fill_order: %s", fillorder) - logger.debug("- YCbCr subsampling: %s", self.tag_v2.get(YCBCRSUBSAMPLING)) + logger.debug("- YCbCr subsampling: %s", self.tag.get(YCBCRSUBSAMPLING)) # size - try: - xsize = self.tag_v2[IMAGEWIDTH] - ysize = self.tag_v2[IMAGELENGTH] - except KeyError as e: - msg = "Missing dimensions" - raise TypeError(msg) from e - if not isinstance(xsize, int) or not isinstance(ysize, int): - msg = "Invalid dimensions" - raise ValueError(msg) - self._tile_size = xsize, ysize - orientation = self.tag_v2.get(ExifTags.Base.Orientation) - if orientation in (5, 6, 7, 8): - self._size = ysize, xsize - else: - self._size = xsize, ysize + xsize = int(self.tag_v2.get(IMAGEWIDTH)) + ysize = int(self.tag_v2.get(IMAGELENGTH)) + self._size = xsize, ysize logger.debug("- size: %s", self.size) @@ -1578,6 +1487,17 @@ class TiffImageFile(ImageFile.ImageFile): # fillorder==2 modes have a corresponding # fillorder=1 mode self._mode, rawmode = OPEN_INFO[key] + # libtiff always returns the bytes in native order. + # we're expecting image byte order. So, if the rawmode + # contains I;16, we need to convert from native to image + # byte order. + if rawmode == "I;16": + rawmode = "I;16N" + if ";16B" in rawmode: + rawmode = rawmode.replace(";16B", ";16N") + if ";16L" in rawmode: + rawmode = rawmode.replace(";16L", ";16N") + # YCbCr images with new jpeg compression with pixels in one plane # unpacked straight into RGB values if ( @@ -1586,39 +1506,23 @@ class TiffImageFile(ImageFile.ImageFile): and self._planar_configuration == 1 ): rawmode = "RGB" - # libtiff always returns the bytes in native order. - # we're expecting image byte order. So, if the rawmode - # contains I;16, we need to convert from native to image - # byte order. - elif rawmode == "I;16": - rawmode = "I;16N" - elif rawmode.endswith((";16B", ";16L")): - rawmode = rawmode[:-1] + "N" # Offset in the tile tuple is 0, we go from 0,0 to # w,h, and we only do this once -- eds a = (rawmode, self._compression, False, self.tag_v2.offset) - self.tile.append(ImageFile._Tile("libtiff", (0, 0, xsize, ysize), 0, a)) + self.tile.append(("libtiff", (0, 0, xsize, ysize), 0, a)) elif STRIPOFFSETS in self.tag_v2 or TILEOFFSETS in self.tag_v2: # striped image if STRIPOFFSETS in self.tag_v2: offsets = self.tag_v2[STRIPOFFSETS] h = self.tag_v2.get(ROWSPERSTRIP, ysize) - w = xsize + w = self.size[0] else: # tiled image offsets = self.tag_v2[TILEOFFSETS] - tilewidth = self.tag_v2.get(TILEWIDTH) + w = self.tag_v2.get(TILEWIDTH) h = self.tag_v2.get(TILELENGTH) - if not isinstance(tilewidth, int) or not isinstance(h, int): - msg = "Invalid tile dimensions" - raise ValueError(msg) - w = tilewidth - - if w == xsize and h == ysize and self._planar_configuration != 2: - # Every tile covers the image. Only use the last offset - offsets = offsets[-1:] for offset in offsets: if x + w > xsize: @@ -1633,20 +1537,20 @@ class TiffImageFile(ImageFile.ImageFile): # adjust stride width accordingly stride /= bps_count - args = (tile_rawmode, int(stride), 1) + a = (tile_rawmode, int(stride), 1) self.tile.append( - ImageFile._Tile( + ( self._compression, (x, y, min(x + w, xsize), min(y + h, ysize)), offset, - args, + a, ) ) - x += w - if x >= xsize: + x = x + w + if x >= self.size[0]: x, y = 0, y + h - if y >= ysize: - y = 0 + if y >= self.size[1]: + x = y = 0 layer += 1 else: logger.debug("- unsupported data organization") @@ -1681,7 +1585,7 @@ SAVE_INFO = { "PA": ("PA", II, 3, 1, (8, 8), 2), "I": ("I;32S", II, 1, 2, (32,), None), "I;16": ("I;16", II, 1, 1, (16,), None), - "I;16L": ("I;16L", II, 1, 1, (16,), None), + "I;16S": ("I;16S", II, 1, 2, (16,), None), "F": ("F;32F", II, 1, 3, (32,), None), "RGB": ("RGB", II, 2, 1, (8, 8, 8), None), "RGBX": ("RGBX", II, 2, 1, (8, 8, 8, 8), 0), @@ -1689,24 +1593,24 @@ SAVE_INFO = { "CMYK": ("CMYK", II, 5, 1, (8, 8, 8, 8), None), "YCbCr": ("YCbCr", II, 6, 1, (8, 8, 8), None), "LAB": ("LAB", II, 8, 1, (8, 8, 8), None), + "I;32BS": ("I;32BS", MM, 1, 2, (32,), None), "I;16B": ("I;16B", MM, 1, 1, (16,), None), + "I;16BS": ("I;16BS", MM, 1, 2, (16,), None), + "F;32BF": ("F;32BF", MM, 1, 3, (32,), None), } -def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: +def _save(im, fp, filename): try: rawmode, prefix, photo, format, bits, extra = SAVE_INFO[im.mode] except KeyError as e: msg = f"cannot write mode {im.mode} as TIFF" raise OSError(msg) from e + ifd = ImageFileDirectory_v2(prefix=prefix) + encoderinfo = im.encoderinfo encoderconfig = im.encoderconfig - - ifd = ImageFileDirectory_v2(prefix=prefix) - if encoderinfo.get("big_tiff"): - ifd._bigtiff = True - try: compression = encoderinfo["compression"] except KeyError: @@ -1832,11 +1736,10 @@ def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: if im.mode == "1": inverted_im = im.copy() px = inverted_im.load() - if px is not None: - for y in range(inverted_im.height): - for x in range(inverted_im.width): - px[x, y] = 0 if px[x, y] == 255 else 255 - im = inverted_im + for y in range(inverted_im.height): + for x in range(inverted_im.width): + px[x, y] = 0 if px[x, y] == 255 else 255 + im = inverted_im else: im = ImageOps.invert(im) @@ -1878,11 +1781,11 @@ def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: ifd[COMPRESSION] = COMPRESSION_INFO_REV.get(compression, 1) if im.mode == "YCbCr": - for tag, default_value in { + for tag, value in { YCBCRSUBSAMPLING: (1, 1), REFERENCEBLACKWHITE: (0, 255, 128, 255, 128, 255), }.items(): - ifd.setdefault(tag, default_value) + ifd.setdefault(tag, value) blocklist = [TILEWIDTH, TILELENGTH, TILEOFFSETS, TILEBYTECOUNTS] if libtiff: @@ -1902,7 +1805,7 @@ def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: if hasattr(fp, "fileno"): try: fp.seek(0) - _fp = fp.fileno() + _fp = os.dup(fp.fileno()) except io.UnsupportedOperation: pass @@ -1925,7 +1828,7 @@ def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: ] # bits per sample is a single short in the tiff directory, not a list. - atts: dict[int, Any] = {BITSPERSAMPLE: bits[0]} + atts = {BITSPERSAMPLE: bits[0]} # Merge the ones that we have with (optional) more bits from # the original file, e.g x,y resolution so that we can # save(load('')) == original file. @@ -1935,14 +1838,14 @@ def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: # Custom items are supported for int, float, unicode, string and byte # values. Other types and tuples require a tagtype. if tag not in TiffTags.LIBTIFF_CORE: - if tag in TiffTags.TAGS_V2_GROUPS: - types[tag] = TiffTags.LONG8 - elif tag in ifd.tagtype: + if not getattr(Image.core, "libtiff_support_custom_tags", False): + continue + + if tag in ifd.tagtype: types[tag] = ifd.tagtype[tag] - elif isinstance(value, (int, float, str, bytes)) or ( - isinstance(value, tuple) - and all(isinstance(v, (int, float, IFDRational)) for v in value) - ): + elif not (isinstance(value, (int, float, str, bytes))): + continue + else: type = TiffTags.lookup(tag).type if type: types[tag] = type @@ -1963,7 +1866,7 @@ def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: # we're storing image byte order. So, if the rawmode # contains I;16, we need to convert from native to image # byte order. - if im.mode in ("I;16", "I;16B", "I;16L"): + if im.mode in ("I;16B", "I;16"): rawmode = "I;16N" # Pass tags as sorted list so that the tags are set in a fixed order. @@ -1975,11 +1878,17 @@ def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: encoder = Image._getencoder(im.mode, "libtiff", a, encoderconfig) encoder.setimage(im.im, (0, 0) + im.size) while True: - errcode, data = encoder.encode(ImageFile.MAXBLOCK)[1:] + # undone, change to self.decodermaxblock: + errcode, data = encoder.encode(16 * 1024)[1:] if not _fp: fp.write(data) if errcode: break + if _fp: + try: + os.close(_fp) + except OSError: + pass if errcode < 0: msg = f"encoder error {errcode} when writing image file" raise OSError(msg) @@ -1990,18 +1899,16 @@ def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: offset = ifd.save(fp) ImageFile._save( - im, - fp, - [ImageFile._Tile("raw", (0, 0) + im.size, offset, (rawmode, stride, 1))], + im, fp, [("raw", (0, 0) + im.size, offset, (rawmode, stride, 1))] ) # -- helper for multi-page save -- if "_debug_multipage" in encoderinfo: # just to access o32 and o16 (using correct byte order) - setattr(im, "_debug_multipage", ifd) + im._debug_multipage = ifd -class AppendingTiffWriter(io.BytesIO): +class AppendingTiffWriter: fieldSizes = [ 0, # None 1, # byte @@ -2031,18 +1938,17 @@ class AppendingTiffWriter(io.BytesIO): 521, # JPEGACTables } - def __init__(self, fn: StrOrBytesPath | IO[bytes], new: bool = False) -> None: - self.f: IO[bytes] - if is_path(fn): + def __init__(self, fn, new=False): + if hasattr(fn, "read"): + self.f = fn + self.close_fp = False + else: self.name = fn self.close_fp = True try: self.f = open(fn, "w+b" if new else "r+b") except OSError: self.f = open(fn, "w+b") - else: - self.f = cast(IO[bytes], fn) - self.close_fp = False self.beginning = self.f.tell() self.setup() @@ -2050,25 +1956,24 @@ class AppendingTiffWriter(io.BytesIO): # Reset everything. self.f.seek(self.beginning, os.SEEK_SET) - self.whereToWriteNewIFDOffset: int | None = None + self.whereToWriteNewIFDOffset = None self.offsetOfNewPage = 0 self.IIMM = iimm = self.f.read(4) - self._bigtiff = b"\x2b" in iimm if not iimm: # empty file - first page self.isFirst = True return self.isFirst = False - if iimm not in PREFIXES: + if iimm == b"II\x2a\x00": + self.setEndian("<") + elif iimm == b"MM\x00\x2a": + self.setEndian(">") + else: msg = "Invalid TIFF file header" raise RuntimeError(msg) - self.setEndian("<" if iimm.startswith(II) else ">") - - if self._bigtiff: - self.f.seek(4, os.SEEK_CUR) self.skipIFDs() self.goToEnd() @@ -2088,13 +1993,10 @@ class AppendingTiffWriter(io.BytesIO): msg = "IIMM of new page doesn't match IIMM of first page" raise RuntimeError(msg) - if self._bigtiff: - self.f.seek(4, os.SEEK_CUR) - ifd_offset = self._read(8 if self._bigtiff else 4) + ifd_offset = self.readLong() ifd_offset += self.offsetOfNewPage - assert self.whereToWriteNewIFDOffset is not None self.f.seek(self.whereToWriteNewIFDOffset) - self._write(ifd_offset, 8 if self._bigtiff else 4) + self.writeLong(ifd_offset) self.f.seek(ifd_offset) self.fixIFD() @@ -2113,13 +2015,7 @@ class AppendingTiffWriter(io.BytesIO): def tell(self) -> int: return self.f.tell() - self.offsetOfNewPage - def seek(self, offset: int, whence: int = io.SEEK_SET) -> int: - """ - :param offset: Distance to seek. - :param whence: Whether the distance is relative to the start, - end or current position. - :returns: The resulting position, relative to the start. - """ + def seek(self, offset, whence=io.SEEK_SET): if whence == os.SEEK_SET: offset += self.offsetOfNewPage @@ -2140,169 +2036,134 @@ class AppendingTiffWriter(io.BytesIO): self.endian = endian self.longFmt = f"{self.endian}L" self.shortFmt = f"{self.endian}H" - self.tagFormat = f"{self.endian}HH" + ("Q" if self._bigtiff else "L") + self.tagFormat = f"{self.endian}HHL" def skipIFDs(self) -> None: while True: - ifd_offset = self._read(8 if self._bigtiff else 4) + ifd_offset = self.readLong() if ifd_offset == 0: - self.whereToWriteNewIFDOffset = self.f.tell() - ( - 8 if self._bigtiff else 4 - ) + self.whereToWriteNewIFDOffset = self.f.tell() - 4 break self.f.seek(ifd_offset) - num_tags = self._read(8 if self._bigtiff else 2) - self.f.seek(num_tags * (20 if self._bigtiff else 12), os.SEEK_CUR) + num_tags = self.readShort() + self.f.seek(num_tags * 12, os.SEEK_CUR) - def write(self, data: Buffer, /) -> int: + def write(self, data: bytes) -> int | None: return self.f.write(data) - def _fmt(self, field_size: int) -> str: - try: - return {2: "H", 4: "L", 8: "Q"}[field_size] - except KeyError: - msg = "offset is not supported" - raise RuntimeError(msg) - - def _read(self, field_size: int) -> int: - (value,) = struct.unpack( - self.endian + self._fmt(field_size), self.f.read(field_size) - ) + def readShort(self) -> int: + (value,) = struct.unpack(self.shortFmt, self.f.read(2)) return value - def readShort(self) -> int: - return self._read(2) - def readLong(self) -> int: - return self._read(4) - - @staticmethod - def _verify_bytes_written(bytes_written: int | None, expected: int) -> None: - if bytes_written is not None and bytes_written != expected: - msg = f"wrote only {bytes_written} bytes but wanted {expected}" - raise RuntimeError(msg) - - def _rewriteLast( - self, value: int, field_size: int, new_field_size: int = 0 - ) -> None: - self.f.seek(-field_size, os.SEEK_CUR) - if not new_field_size: - new_field_size = field_size - bytes_written = self.f.write( - struct.pack(self.endian + self._fmt(new_field_size), value) - ) - self._verify_bytes_written(bytes_written, new_field_size) + (value,) = struct.unpack(self.longFmt, self.f.read(4)) + return value def rewriteLastShortToLong(self, value: int) -> None: - self._rewriteLast(value, 2, 4) + self.f.seek(-2, os.SEEK_CUR) + bytes_written = self.f.write(struct.pack(self.longFmt, value)) + if bytes_written is not None and bytes_written != 4: + msg = f"wrote only {bytes_written} bytes but wanted 4" + raise RuntimeError(msg) def rewriteLastShort(self, value: int) -> None: - return self._rewriteLast(value, 2) + self.f.seek(-2, os.SEEK_CUR) + bytes_written = self.f.write(struct.pack(self.shortFmt, value)) + if bytes_written is not None and bytes_written != 2: + msg = f"wrote only {bytes_written} bytes but wanted 2" + raise RuntimeError(msg) def rewriteLastLong(self, value: int) -> None: - return self._rewriteLast(value, 4) - - def _write(self, value: int, field_size: int) -> None: - bytes_written = self.f.write( - struct.pack(self.endian + self._fmt(field_size), value) - ) - self._verify_bytes_written(bytes_written, field_size) + self.f.seek(-4, os.SEEK_CUR) + bytes_written = self.f.write(struct.pack(self.longFmt, value)) + if bytes_written is not None and bytes_written != 4: + msg = f"wrote only {bytes_written} bytes but wanted 4" + raise RuntimeError(msg) def writeShort(self, value: int) -> None: - self._write(value, 2) + bytes_written = self.f.write(struct.pack(self.shortFmt, value)) + if bytes_written is not None and bytes_written != 2: + msg = f"wrote only {bytes_written} bytes but wanted 2" + raise RuntimeError(msg) def writeLong(self, value: int) -> None: - self._write(value, 4) + bytes_written = self.f.write(struct.pack(self.longFmt, value)) + if bytes_written is not None and bytes_written != 4: + msg = f"wrote only {bytes_written} bytes but wanted 4" + raise RuntimeError(msg) def close(self) -> None: self.finalize() - if self.close_fp: - self.f.close() + self.f.close() def fixIFD(self) -> None: - num_tags = self._read(8 if self._bigtiff else 2) + num_tags = self.readShort() for i in range(num_tags): - tag, field_type, count = struct.unpack( - self.tagFormat, self.f.read(12 if self._bigtiff else 8) - ) + tag, field_type, count = struct.unpack(self.tagFormat, self.f.read(8)) field_size = self.fieldSizes[field_type] total_size = field_size * count - fmt_size = 8 if self._bigtiff else 4 - is_local = total_size <= fmt_size + is_local = total_size <= 4 + offset: int | None if not is_local: - offset = self._read(fmt_size) + self.offsetOfNewPage - self._rewriteLast(offset, fmt_size) + offset = self.readLong() + self.offsetOfNewPage + self.rewriteLastLong(offset) if tag in self.Tags: cur_pos = self.f.tell() - logger.debug( - "fixIFD: %s (%d) - type: %s (%d) - type size: %d - count: %d", - TiffTags.lookup(tag).name, - tag, - TYPES.get(field_type, "unknown"), - field_type, - field_size, - count, - ) - if is_local: - self._fixOffsets(count, field_size) - self.f.seek(cur_pos + fmt_size) + self.fixOffsets( + count, isShort=(field_size == 2), isLong=(field_size == 4) + ) + self.f.seek(cur_pos + 4) else: self.f.seek(offset) - self._fixOffsets(count, field_size) + self.fixOffsets( + count, isShort=(field_size == 2), isLong=(field_size == 4) + ) self.f.seek(cur_pos) + offset = cur_pos = None + elif is_local: # skip the locally stored value that is not an offset - self.f.seek(fmt_size, os.SEEK_CUR) + self.f.seek(4, os.SEEK_CUR) + + def fixOffsets( + self, count: int, isShort: bool = False, isLong: bool = False + ) -> None: + if not isShort and not isLong: + msg = "offset is neither short nor long" + raise RuntimeError(msg) - def _fixOffsets(self, count: int, field_size: int) -> None: for i in range(count): - offset = self._read(field_size) + offset = self.readShort() if isShort else self.readLong() offset += self.offsetOfNewPage - - new_field_size = 0 - if self._bigtiff and field_size in (2, 4) and offset >= 2**32: - # offset is now too large - we must convert long to long8 - new_field_size = 8 - elif field_size == 2 and offset >= 2**16: - # offset is now too large - we must convert short to long - new_field_size = 4 - if new_field_size: + if isShort and offset >= 65536: + # offset is now too large - we must convert shorts to longs if count != 1: msg = "not implemented" raise RuntimeError(msg) # XXX TODO # simple case - the offset is just one and therefore it is # local (not referenced with another offset) - self._rewriteLast(offset, field_size, new_field_size) - # Move back past the new offset, past 'count', and before 'field_type' - rewind = -new_field_size - 4 - 2 - self.f.seek(rewind, os.SEEK_CUR) - self.writeShort(new_field_size) # rewrite the type - self.f.seek(2 - rewind, os.SEEK_CUR) + self.rewriteLastShortToLong(offset) + self.f.seek(-10, os.SEEK_CUR) + self.writeShort(TiffTags.LONG) # rewrite the type to LONG + self.f.seek(8, os.SEEK_CUR) + elif isShort: + self.rewriteLastShort(offset) else: - self._rewriteLast(offset, field_size) - - def fixOffsets( - self, count: int, isShort: bool = False, isLong: bool = False - ) -> None: - if isShort: - field_size = 2 - elif isLong: - field_size = 4 - else: - field_size = 0 - return self._fixOffsets(count, field_size) + self.rewriteLastLong(offset) def _save_all(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: - append_images = list(im.encoderinfo.get("append_images", [])) + encoderinfo = im.encoderinfo.copy() + encoderconfig = im.encoderconfig + append_images = list(encoderinfo.get("append_images", [])) if not hasattr(im, "n_frames") and not append_images: return _save(im, fp, filename) @@ -2310,17 +2171,18 @@ def _save_all(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: try: with AppendingTiffWriter(fp) as tf: for ims in [im] + append_images: - encoderinfo = ims._attach_default_encoderinfo(im) - if not hasattr(ims, "encoderconfig"): - ims.encoderconfig = () - nfr = getattr(ims, "n_frames", 1) + ims.encoderinfo = encoderinfo + ims.encoderconfig = encoderconfig + if not hasattr(ims, "n_frames"): + nfr = 1 + else: + nfr = ims.n_frames for idx in range(nfr): ims.seek(idx) ims.load() _save(ims, tf, filename) tf.newFrame() - ims.encoderinfo = encoderinfo finally: im.seek(cur_idx) diff --git a/venv/Lib/site-packages/PIL/TiffTags.py b/venv/Lib/site-packages/PIL/TiffTags.py index 613a3b7..e318c87 100644 --- a/venv/Lib/site-packages/PIL/TiffTags.py +++ b/venv/Lib/site-packages/PIL/TiffTags.py @@ -32,24 +32,17 @@ class _TagInfo(NamedTuple): class TagInfo(_TagInfo): __slots__: list[str] = [] - def __new__( - cls, - value: int | None = None, - name: str = "unknown", - type: int | None = None, - length: int | None = None, - enum: dict[str, int] | None = None, - ) -> TagInfo: + def __new__(cls, value=None, name="unknown", type=None, length=None, enum=None): return super().__new__(cls, value, name, type, length, enum or {}) - def cvt_enum(self, value: str) -> int | str: + def cvt_enum(self, value): # Using get will call hash(value), which can be expensive # for some types (e.g. Fraction). Since self.enum is rarely # used, it's usually better to test it first. return self.enum.get(value, value) if self.enum else value -def lookup(tag: int, group: int | None = None) -> TagInfo: +def lookup(tag, group=None): """ :param tag: Integer tag number :param group: Which :py:data:`~PIL.TiffTags.TAGS_V2_GROUPS` to look in @@ -96,7 +89,7 @@ DOUBLE = 12 IFD = 13 LONG8 = 16 -_tags_v2: dict[int, tuple[str, int, int] | tuple[str, int, int, dict[str, int]]] = { +_tags_v2 = { 254: ("NewSubfileType", LONG, 1), 255: ("SubfileType", SHORT, 1), 256: ("ImageWidth", LONG, 1), @@ -203,11 +196,6 @@ _tags_v2: dict[int, tuple[str, int, int] | tuple[str, int, int, dict[str, int]]] 531: ("YCbCrPositioning", SHORT, 1), 532: ("ReferenceBlackWhite", RATIONAL, 6), 700: ("XMP", BYTE, 0), - # Four private SGI tags - 32995: ("Matteing", SHORT, 1), - 32996: ("DataType", SHORT, 0), - 32997: ("ImageDepth", LONG, 1), - 32998: ("TileDepth", LONG, 1), 33432: ("Copyright", ASCII, 1), 33723: ("IptcNaaInfo", UNDEFINED, 1), 34377: ("PhotoshopInfo", BYTE, 0), @@ -245,7 +233,7 @@ _tags_v2: dict[int, tuple[str, int, int] | tuple[str, int, int, dict[str, int]]] 50838: ("ImageJMetaDataByteCounts", LONG, 0), # Can be more than one 50839: ("ImageJMetaData", UNDEFINED, 1), # see Issue #2006 } -_tags_v2_groups = { +TAGS_V2_GROUPS = { # ExifIFD 34665: { 36864: ("ExifVersion", UNDEFINED, 1), @@ -293,7 +281,7 @@ _tags_v2_groups = { # Legacy Tags structure # these tags aren't included above, but were in the previous versions -TAGS: dict[int | tuple[int, int], str] = { +TAGS = { 347: "JPEGTables", 700: "XMP", # Additional Exif Info @@ -438,10 +426,9 @@ TAGS: dict[int | tuple[int, int], str] = { } TAGS_V2: dict[int, TagInfo] = {} -TAGS_V2_GROUPS: dict[int, dict[int, TagInfo]] = {} -def _populate() -> None: +def _populate(): for k, v in _tags_v2.items(): # Populate legacy structure. TAGS[k] = v[0] @@ -451,8 +438,9 @@ def _populate() -> None: TAGS_V2[k] = TagInfo(k, *v) - for group, tags in _tags_v2_groups.items(): - TAGS_V2_GROUPS[group] = {k: TagInfo(k, *v) for k, v in tags.items()} + for tags in TAGS_V2_GROUPS.values(): + for k, v in tags.items(): + tags[k] = TagInfo(k, *v) _populate() @@ -558,6 +546,7 @@ LIBTIFF_CORE = { LIBTIFF_CORE.remove(255) # We don't have support for subfiletypes LIBTIFF_CORE.remove(322) # We don't have support for writing tiled images with libtiff LIBTIFF_CORE.remove(323) # Tiled images +LIBTIFF_CORE.remove(333) # Ink Names either # Note to advanced users: There may be combinations of these # parameters and values that when added properly, will work and diff --git a/venv/Lib/site-packages/PIL/WalImageFile.py b/venv/Lib/site-packages/PIL/WalImageFile.py index fb3e1c0..fbd7be6 100644 --- a/venv/Lib/site-packages/PIL/WalImageFile.py +++ b/venv/Lib/site-packages/PIL/WalImageFile.py @@ -24,11 +24,8 @@ and has been tested with a few sample files found using google. """ from __future__ import annotations -from typing import IO - from . import Image, ImageFile from ._binary import i32le as i32 -from ._typing import StrOrBytesPath class WalImageFile(ImageFile.ImageFile): @@ -39,7 +36,6 @@ class WalImageFile(ImageFile.ImageFile): self._mode = "P" # read header fields - assert self.fp is not None header = self.fp.read(32 + 24 + 32 + 12) self._size = i32(header, 32), i32(header, 36) Image._decompression_bomb_check(self.size) @@ -50,19 +46,19 @@ class WalImageFile(ImageFile.ImageFile): # strings are null-terminated self.info["name"] = header[:32].split(b"\0", 1)[0] - if next_name := header[56 : 56 + 32].split(b"\0", 1)[0]: + next_name = header[56 : 56 + 32].split(b"\0", 1)[0] + if next_name: self.info["next_name"] = next_name - def load(self) -> Image.core.PixelAccess | None: - if self._im is None: - assert self.fp is not None + def load(self): + if not self.im: self.im = Image.core.new(self.mode, self.size) self.frombytes(self.fp.read(self.size[0] * self.size[1])) self.putpalette(quake2palette) return Image.Image.load(self) -def open(filename: StrOrBytesPath | IO[bytes]) -> WalImageFile: +def open(filename): """ Load texture from a Quake2 WAL texture file. diff --git a/venv/Lib/site-packages/PIL/WebPImagePlugin.py b/venv/Lib/site-packages/PIL/WebPImagePlugin.py index e20e40d..59be5bf 100644 --- a/venv/Lib/site-packages/PIL/WebPImagePlugin.py +++ b/venv/Lib/site-packages/PIL/WebPImagePlugin.py @@ -1,6 +1,7 @@ from __future__ import annotations from io import BytesIO +from typing import IO, Any from . import Image, ImageFile @@ -11,9 +12,10 @@ try: except ImportError: SUPPORTED = False -TYPE_CHECKING = False -if TYPE_CHECKING: - from typing import IO, Any + +_VALID_WEBP_MODES = {"RGBX": True, "RGBA": True, "RGB": True} + +_VALID_WEBP_LEGACY_MODES = {"RGB": True, "RGBA": True} _VP8_MODES_BY_IDENTIFIER = { b"VP8 ": "RGB", @@ -23,7 +25,7 @@ _VP8_MODES_BY_IDENTIFIER = { def _accept(prefix: bytes) -> bool | str: - is_riff_file_format = prefix.startswith(b"RIFF") + is_riff_file_format = prefix[:4] == b"RIFF" is_webp_file = prefix[8:12] == b"WEBP" is_valid_vp8_mode = prefix[12:16] in _VP8_MODES_BY_IDENTIFIER @@ -43,37 +45,58 @@ class WebPImageFile(ImageFile.ImageFile): __logical_frame = 0 def _open(self) -> None: + if not _webp.HAVE_WEBPANIM: + # Legacy mode + data, width, height, self._mode, icc_profile, exif = _webp.WebPDecode( + self.fp.read() + ) + if icc_profile: + self.info["icc_profile"] = icc_profile + if exif: + self.info["exif"] = exif + self._size = width, height + self.fp = BytesIO(data) + self.tile = [("raw", (0, 0) + self.size, 0, self.mode)] + self.n_frames = 1 + self.is_animated = False + return + # Use the newer AnimDecoder API to parse the (possibly) animated file, # and access muxed chunks like ICC/EXIF/XMP. - assert self.fp is not None self._decoder = _webp.WebPAnimDecoder(self.fp.read()) # Get info from decoder - self._size, self.info["loop"], bgcolor, self.n_frames, self.rawmode = ( - self._decoder.get_info() - ) - self.info["background"] = ( - (bgcolor >> 16) & 0xFF, # R - (bgcolor >> 8) & 0xFF, # G - bgcolor & 0xFF, # B - (bgcolor >> 24) & 0xFF, # A + width, height, loop_count, bgcolor, frame_count, mode = self._decoder.get_info() + self._size = width, height + self.info["loop"] = loop_count + bg_a, bg_r, bg_g, bg_b = ( + (bgcolor >> 24) & 0xFF, + (bgcolor >> 16) & 0xFF, + (bgcolor >> 8) & 0xFF, + bgcolor & 0xFF, ) + self.info["background"] = (bg_r, bg_g, bg_b, bg_a) + self.n_frames = frame_count self.is_animated = self.n_frames > 1 - self._mode = "RGB" if self.rawmode == "RGBX" else self.rawmode + self._mode = "RGB" if mode == "RGBX" else mode + self.rawmode = mode + self.tile = [] # Attempt to read ICC / EXIF / XMP chunks from file - for key, chunk_name in { - "icc_profile": "ICCP", - "exif": "EXIF", - "xmp": "XMP ", - }.items(): - if value := self._decoder.get_chunk(chunk_name): - self.info[key] = value + icc_profile = self._decoder.get_chunk("ICCP") + exif = self._decoder.get_chunk("EXIF") + xmp = self._decoder.get_chunk("XMP ") + if icc_profile: + self.info["icc_profile"] = icc_profile + if exif: + self.info["exif"] = exif + if xmp: + self.info["xmp"] = xmp # Initialize seek state self._reset(reset=False) - def _getexif(self) -> dict[int, Any] | None: + def _getexif(self) -> dict[str, Any] | None: if "exif" not in self.info: return None return self.getexif()._get_merged_dict() @@ -92,7 +115,7 @@ class WebPImageFile(ImageFile.ImageFile): self.__loaded = -1 self.__timestamp = 0 - def _get_next(self) -> tuple[bytes, int, int]: + def _get_next(self): # Get next frame ret = self._decoder.get_next() self.__physical_frame += 1 @@ -121,19 +144,22 @@ class WebPImageFile(ImageFile.ImageFile): while self.__physical_frame < frame: self._get_next() # Advance to the requested frame - def load(self) -> Image.core.PixelAccess | None: - if self.__loaded != self.__logical_frame: - self._seek(self.__logical_frame) + def load(self): + if _webp.HAVE_WEBPANIM: + if self.__loaded != self.__logical_frame: + self._seek(self.__logical_frame) - # We need to load the image data for this frame - data, self.info["timestamp"], self.info["duration"] = self._get_next() - self.__loaded = self.__logical_frame + # We need to load the image data for this frame + data, timestamp, duration = self._get_next() + self.info["timestamp"] = timestamp + self.info["duration"] = duration + self.__loaded = self.__logical_frame - # Set tile - if self.fp and self._exclusive_fp: - self.fp.close() - self.fp = BytesIO(data) - self.tile = [ImageFile._Tile("raw", (0, 0) + self.size, 0, self.rawmode)] + # Set tile + if self.fp and self._exclusive_fp: + self.fp.close() + self.fp = BytesIO(data) + self.tile = [("raw", (0, 0) + self.size, 0, self.rawmode)] return super().load() @@ -141,16 +167,12 @@ class WebPImageFile(ImageFile.ImageFile): pass def tell(self) -> int: + if not _webp.HAVE_WEBPANIM: + return super().tell() + return self.__logical_frame -def _convert_frame(im: Image.Image) -> Image.Image: - # Make sure image mode is supported - if im.mode not in ("RGBX", "RGBA", "RGB"): - im = im.convert("RGBA" if im.has_transparency_data else "RGB") - return im - - def _save_all(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: encoderinfo = im.encoderinfo.copy() append_images = list(encoderinfo.get("append_images", [])) @@ -219,7 +241,8 @@ def _save_all(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: # Setup the WebP animation encoder enc = _webp.WebPAnimEncoder( - im.size, + im.size[0], + im.size[1], background, loop, minimize_size, @@ -235,18 +258,36 @@ def _save_all(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: cur_idx = im.tell() try: for ims in [im] + append_images: - # Get number of frames in this image + # Get # of frames in this image nfr = getattr(ims, "n_frames", 1) for idx in range(nfr): ims.seek(idx) + ims.load() - frame = _convert_frame(ims) + # Make sure image mode is supported + frame = ims + rawmode = ims.mode + if ims.mode not in _VALID_WEBP_MODES: + alpha = ( + "A" in ims.mode + or "a" in ims.mode + or (ims.mode == "P" and "A" in ims.im.getpalettemode()) + ) + rawmode = "RGBA" if alpha else "RGB" + frame = ims.convert(rawmode) + + if rawmode == "RGB": + # For faster conversion, use RGBX + rawmode = "RGBX" # Append the frame to the animation encoder enc.add( - frame.getim(), + frame.tobytes("raw", rawmode), round(timestamp), + frame.size[0], + frame.size[1], + rawmode, lossless, quality, alpha_quality, @@ -264,7 +305,7 @@ def _save_all(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: im.seek(cur_idx) # Force encoder to flush frames - enc.add(None, round(timestamp), lossless, quality, alpha_quality, 0) + enc.add(None, round(timestamp), 0, 0, "", lossless, quality, alpha_quality, 0) # Get the final output from the encoder data = enc.assemble(icc_profile, exif, xmp) @@ -289,13 +330,17 @@ def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: method = im.encoderinfo.get("method", 4) exact = 1 if im.encoderinfo.get("exact") else 0 - im = _convert_frame(im) + if im.mode not in _VALID_WEBP_LEGACY_MODES: + im = im.convert("RGBA" if im.has_transparency_data else "RGB") data = _webp.WebPEncode( - im.getim(), + im.tobytes(), + im.size[0], + im.size[1], lossless, float(quality), float(alpha_quality), + im.mode, icc_profile, method, exact, @@ -312,6 +357,7 @@ def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: Image.register_open(WebPImageFile.format, WebPImageFile, _accept) if SUPPORTED: Image.register_save(WebPImageFile.format, _save) - Image.register_save_all(WebPImageFile.format, _save_all) + if _webp.HAVE_WEBPANIM: + Image.register_save_all(WebPImageFile.format, _save_all) Image.register_extension(WebPImageFile.format, ".webp") Image.register_mime(WebPImageFile.format, "image/webp") diff --git a/venv/Lib/site-packages/PIL/WmfImagePlugin.py b/venv/Lib/site-packages/PIL/WmfImagePlugin.py index 3ae8624..3d5cddc 100644 --- a/venv/Lib/site-packages/PIL/WmfImagePlugin.py +++ b/venv/Lib/site-packages/PIL/WmfImagePlugin.py @@ -49,7 +49,6 @@ if hasattr(Image.core, "drawwmf"): self.bbox = im.info["wmf_bbox"] def load(self, im: ImageFile.StubImageFile) -> Image.Image: - assert im.fp is not None im.fp.seek(0) # rewind return Image.frombytes( "RGB", @@ -69,7 +68,9 @@ if hasattr(Image.core, "drawwmf"): def _accept(prefix: bytes) -> bool: - return prefix.startswith((b"\xd7\xcd\xc6\x9a\x00\x00", b"\x01\x00\x00\x00")) + return ( + prefix[:6] == b"\xd7\xcd\xc6\x9a\x00\x00" or prefix[:4] == b"\x01\x00\x00\x00" + ) ## @@ -81,19 +82,16 @@ class WmfStubImageFile(ImageFile.StubImageFile): format_description = "Windows Metafile" def _open(self) -> None: - # check placeable header - assert self.fp is not None - s = self.fp.read(44) + self._inch = None - if s.startswith(b"\xd7\xcd\xc6\x9a\x00\x00"): + # check placable header + s = self.fp.read(80) + + if s[:6] == b"\xd7\xcd\xc6\x9a\x00\x00": # placeable windows metafile # get units per inch - inch = word(s, 14) - if inch == 0: - msg = "Invalid inch" - raise ValueError(msg) - self._inch: tuple[float, float] = inch, inch + self._inch = word(s, 14) # get bounding box x0 = short(s, 6) @@ -104,8 +102,8 @@ class WmfStubImageFile(ImageFile.StubImageFile): # normalize size to 72 dots per inch self.info["dpi"] = 72 size = ( - (x1 - x0) * self.info["dpi"] // inch, - (y1 - y0) * self.info["dpi"] // inch, + (x1 - x0) * self.info["dpi"] // self._inch, + (y1 - y0) * self.info["dpi"] // self._inch, ) self.info["wmf_bbox"] = x0, y0, x1, y1 @@ -115,7 +113,7 @@ class WmfStubImageFile(ImageFile.StubImageFile): msg = "Unsupported WMF file format" raise SyntaxError(msg) - elif s.startswith(b"\x01\x00\x00\x00") and s[40:44] == b" EMF": + elif s[:4] == b"\x01\x00\x00\x00" and s[40:44] == b" EMF": # enhanced metafile # get bounding box @@ -130,7 +128,7 @@ class WmfStubImageFile(ImageFile.StubImageFile): size = x1 - x0, y1 - y0 # calculate dots per inch from bbox and frame - xdpi = 2540.0 * (x1 - x0) / (frame[2] - frame[0]) + xdpi = 2540.0 * (x1 - y0) / (frame[2] - frame[0]) ydpi = 2540.0 * (y1 - y0) / (frame[3] - frame[1]) self.info["wmf_bbox"] = x0, y0, x1, y1 @@ -139,7 +137,6 @@ class WmfStubImageFile(ImageFile.StubImageFile): self.info["dpi"] = xdpi else: self.info["dpi"] = xdpi, ydpi - self._inch = xdpi, ydpi else: msg = "Unsupported file format" @@ -155,17 +152,13 @@ class WmfStubImageFile(ImageFile.StubImageFile): def _load(self) -> ImageFile.StubHandler | None: return _handler - def load( - self, dpi: float | tuple[float, float] | None = None - ) -> Image.core.PixelAccess | None: - if dpi is not None: + def load(self, dpi=None): + if dpi is not None and self._inch is not None: self.info["dpi"] = dpi x0, y0, x1, y1 = self.info["wmf_bbox"] - if not isinstance(dpi, tuple): - dpi = dpi, dpi self._size = ( - int((x1 - x0) * dpi[0] / self._inch[0]), - int((y1 - y0) * dpi[1] / self._inch[1]), + (x1 - x0) * self.info["dpi"] // self._inch, + (y1 - y0) * self.info["dpi"] // self._inch, ) return super().load() diff --git a/venv/Lib/site-packages/PIL/XVThumbImagePlugin.py b/venv/Lib/site-packages/PIL/XVThumbImagePlugin.py index 192c041..c84adac 100644 --- a/venv/Lib/site-packages/PIL/XVThumbImagePlugin.py +++ b/venv/Lib/site-packages/PIL/XVThumbImagePlugin.py @@ -34,7 +34,7 @@ for r in range(8): def _accept(prefix: bytes) -> bool: - return prefix.startswith(_MAGIC) + return prefix[:6] == _MAGIC ## @@ -66,16 +66,14 @@ class XVThumbImageFile(ImageFile.ImageFile): break # parse header line (already read) - w, h = s.strip().split(maxsplit=2)[:2] + s = s.strip().split() self._mode = "P" - self._size = int(w), int(h) + self._size = int(s[0]), int(s[1]) self.palette = ImagePalette.raw("RGB", PALETTE) - self.tile = [ - ImageFile._Tile("raw", (0, 0) + self.size, self.fp.tell(), self.mode) - ] + self.tile = [("raw", (0, 0) + self.size, self.fp.tell(), (self.mode, 0, 1))] # -------------------------------------------------------------------- diff --git a/venv/Lib/site-packages/PIL/XbmImagePlugin.py b/venv/Lib/site-packages/PIL/XbmImagePlugin.py index 1e57aa1..6d11bbf 100644 --- a/venv/Lib/site-packages/PIL/XbmImagePlugin.py +++ b/venv/Lib/site-packages/PIL/XbmImagePlugin.py @@ -38,7 +38,7 @@ xbm_head = re.compile( def _accept(prefix: bytes) -> bool: - return prefix.lstrip().startswith(b"#define") + return prefix.lstrip()[:7] == b"#define" ## @@ -67,7 +67,7 @@ class XbmImageFile(ImageFile.ImageFile): self._mode = "1" self._size = xsize, ysize - self.tile = [ImageFile._Tile("xbm", (0, 0) + self.size, m.end())] + self.tile = [("xbm", (0, 0) + self.size, m.end(), None)] def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: @@ -85,7 +85,7 @@ def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: fp.write(b"static char im_bits[] = {\n") - ImageFile._save(im, fp, [ImageFile._Tile("xbm", (0, 0) + im.size)]) + ImageFile._save(im, fp, [("xbm", (0, 0) + im.size, 0, None)]) fp.write(b"};\n") diff --git a/venv/Lib/site-packages/PIL/XpmImagePlugin.py b/venv/Lib/site-packages/PIL/XpmImagePlugin.py index 3be240f..8d56331 100644 --- a/venv/Lib/site-packages/PIL/XpmImagePlugin.py +++ b/venv/Lib/site-packages/PIL/XpmImagePlugin.py @@ -25,7 +25,7 @@ xpm_head = re.compile(b'"([0-9]*) ([0-9]*) ([0-9]*) ([0-9]*)') def _accept(prefix: bytes) -> bool: - return prefix.startswith(b"/* XPM */") + return prefix[:9] == b"/* XPM */" ## @@ -37,36 +37,43 @@ class XpmImageFile(ImageFile.ImageFile): format_description = "X11 Pixel Map" def _open(self) -> None: - assert self.fp is not None if not _accept(self.fp.read(9)): msg = "not an XPM file" raise SyntaxError(msg) # skip forward to next string while True: - line = self.fp.readline() - if not line: + s = self.fp.readline() + if not s: msg = "broken XPM file" raise SyntaxError(msg) - m = xpm_head.match(line) + m = xpm_head.match(s) if m: break self._size = int(m.group(1)), int(m.group(2)) - palette_length = int(m.group(3)) + pal = int(m.group(3)) bpp = int(m.group(4)) + if pal > 256 or bpp != 1: + msg = "cannot read this XPM file" + raise ValueError(msg) + # # load palette description - palette = {} + palette = [b"\0\0\0"] * 256 - for _ in range(palette_length): - line = self.fp.readline().rstrip() + for _ in range(pal): + s = self.fp.readline() + if s[-2:] == b"\r\n": + s = s[:-2] + elif s[-1:] in b"\r\n": + s = s[:-1] - c = line[1 : bpp + 1] - s = line[bpp + 1 : -2].split() + c = s[1] + s = s[2:-2].split() for i in range(0, len(s), 2): if s[i] == b"c": @@ -74,12 +81,11 @@ class XpmImageFile(ImageFile.ImageFile): rgb = s[i + 1] if rgb == b"None": self.info["transparency"] = c - elif rgb.startswith(b"#"): - rgb_int = int(rgb[1:], 16) + elif rgb[:1] == b"#": + # FIXME: handle colour names (see ImagePalette.py) + rgb = int(rgb[1:], 16) palette[c] = ( - o8((rgb_int >> 16) & 255) - + o8((rgb_int >> 8) & 255) - + o8(rgb_int & 255) + o8((rgb >> 16) & 255) + o8((rgb >> 8) & 255) + o8(rgb & 255) ) else: # unknown colour @@ -92,16 +98,10 @@ class XpmImageFile(ImageFile.ImageFile): msg = "cannot read this XPM file" raise ValueError(msg) - args: tuple[int, dict[bytes, bytes] | tuple[bytes, ...]] - if palette_length > 256: - self._mode = "RGB" - args = (bpp, palette) - else: - self._mode = "P" - self.palette = ImagePalette.raw("RGB", b"".join(palette.values())) - args = (bpp, tuple(palette.keys())) + self._mode = "P" + self.palette = ImagePalette.raw("RGB", b"".join(palette)) - self.tile = [ImageFile._Tile("xpm", (0, 0) + self.size, self.fp.tell(), args)] + self.tile = [("raw", (0, 0) + self.size, self.fp.tell(), ("P", 0, 1))] def load_read(self, read_bytes: int) -> bytes: # @@ -109,48 +109,16 @@ class XpmImageFile(ImageFile.ImageFile): xsize, ysize = self.size - assert self.fp is not None s = [self.fp.readline()[1 : xsize + 1].ljust(xsize) for i in range(ysize)] return b"".join(s) -class XpmDecoder(ImageFile.PyDecoder): - _pulls_fd = True - - def decode(self, buffer: bytes | Image.SupportsArrayInterface) -> tuple[int, int]: - assert self.fd is not None - - data = bytearray() - bpp, palette = self.args - dest_length = self.state.xsize * self.state.ysize - if self.mode == "RGB": - dest_length *= 3 - pixel_header = False - while len(data) < dest_length: - line = self.fd.readline() - if not line: - break - if line.rstrip() == b"/* pixels */" and not pixel_header: - pixel_header = True - continue - line = b'"'.join(line.split(b'"')[1:-1]) - for i in range(0, len(line), bpp): - key = line[i : i + bpp] - if self.mode == "RGB": - data += palette[key] - else: - data += o8(palette.index(key)) - self.set_as_raw(bytes(data)) - return -1, 0 - - # # Registry Image.register_open(XpmImageFile.format, XpmImageFile, _accept) -Image.register_decoder("xpm", XpmDecoder) Image.register_extension(XpmImageFile.format, ".xpm") diff --git a/venv/Lib/site-packages/PIL/__init__.py b/venv/Lib/site-packages/PIL/__init__.py index 6e4c23f..09546fe 100644 --- a/venv/Lib/site-packages/PIL/__init__.py +++ b/venv/Lib/site-packages/PIL/__init__.py @@ -25,7 +25,6 @@ del _version _plugins = [ - "AvifImagePlugin", "BlpImagePlugin", "BmpImagePlugin", "BufrStubImagePlugin", diff --git a/venv/Lib/site-packages/PIL/__pycache__/AvifImagePlugin.cpython-312.pyc b/venv/Lib/site-packages/PIL/__pycache__/AvifImagePlugin.cpython-312.pyc deleted file mode 100644 index 6e7a4f1..0000000 Binary files a/venv/Lib/site-packages/PIL/__pycache__/AvifImagePlugin.cpython-312.pyc and /dev/null differ diff --git a/venv/Lib/site-packages/PIL/__pycache__/BdfFontFile.cpython-312.pyc b/venv/Lib/site-packages/PIL/__pycache__/BdfFontFile.cpython-312.pyc index fa135d2..dee3dd6 100644 Binary files a/venv/Lib/site-packages/PIL/__pycache__/BdfFontFile.cpython-312.pyc and b/venv/Lib/site-packages/PIL/__pycache__/BdfFontFile.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/PIL/__pycache__/BlpImagePlugin.cpython-312.pyc b/venv/Lib/site-packages/PIL/__pycache__/BlpImagePlugin.cpython-312.pyc index 18f93fd..6e9b850 100644 Binary files a/venv/Lib/site-packages/PIL/__pycache__/BlpImagePlugin.cpython-312.pyc and b/venv/Lib/site-packages/PIL/__pycache__/BlpImagePlugin.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/PIL/__pycache__/BmpImagePlugin.cpython-312.pyc b/venv/Lib/site-packages/PIL/__pycache__/BmpImagePlugin.cpython-312.pyc index d9f3f32..d60ff55 100644 Binary files a/venv/Lib/site-packages/PIL/__pycache__/BmpImagePlugin.cpython-312.pyc and b/venv/Lib/site-packages/PIL/__pycache__/BmpImagePlugin.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/PIL/__pycache__/BufrStubImagePlugin.cpython-312.pyc b/venv/Lib/site-packages/PIL/__pycache__/BufrStubImagePlugin.cpython-312.pyc index 1d83e60..21c44d3 100644 Binary files a/venv/Lib/site-packages/PIL/__pycache__/BufrStubImagePlugin.cpython-312.pyc and b/venv/Lib/site-packages/PIL/__pycache__/BufrStubImagePlugin.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/PIL/__pycache__/ContainerIO.cpython-312.pyc b/venv/Lib/site-packages/PIL/__pycache__/ContainerIO.cpython-312.pyc index 9a40051..ccb930a 100644 Binary files a/venv/Lib/site-packages/PIL/__pycache__/ContainerIO.cpython-312.pyc and b/venv/Lib/site-packages/PIL/__pycache__/ContainerIO.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/PIL/__pycache__/CurImagePlugin.cpython-312.pyc b/venv/Lib/site-packages/PIL/__pycache__/CurImagePlugin.cpython-312.pyc index f5b8958..abcda4e 100644 Binary files a/venv/Lib/site-packages/PIL/__pycache__/CurImagePlugin.cpython-312.pyc and b/venv/Lib/site-packages/PIL/__pycache__/CurImagePlugin.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/PIL/__pycache__/DcxImagePlugin.cpython-312.pyc b/venv/Lib/site-packages/PIL/__pycache__/DcxImagePlugin.cpython-312.pyc index 9c2361c..6e9bc00 100644 Binary files a/venv/Lib/site-packages/PIL/__pycache__/DcxImagePlugin.cpython-312.pyc and b/venv/Lib/site-packages/PIL/__pycache__/DcxImagePlugin.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/PIL/__pycache__/DdsImagePlugin.cpython-312.pyc b/venv/Lib/site-packages/PIL/__pycache__/DdsImagePlugin.cpython-312.pyc index da5126b..5ce0fde 100644 Binary files a/venv/Lib/site-packages/PIL/__pycache__/DdsImagePlugin.cpython-312.pyc and b/venv/Lib/site-packages/PIL/__pycache__/DdsImagePlugin.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/PIL/__pycache__/EpsImagePlugin.cpython-312.pyc b/venv/Lib/site-packages/PIL/__pycache__/EpsImagePlugin.cpython-312.pyc index d15eb72..b0f64df 100644 Binary files a/venv/Lib/site-packages/PIL/__pycache__/EpsImagePlugin.cpython-312.pyc and b/venv/Lib/site-packages/PIL/__pycache__/EpsImagePlugin.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/PIL/__pycache__/ExifTags.cpython-312.pyc b/venv/Lib/site-packages/PIL/__pycache__/ExifTags.cpython-312.pyc index 88a6e7f..7b1cbb7 100644 Binary files a/venv/Lib/site-packages/PIL/__pycache__/ExifTags.cpython-312.pyc and b/venv/Lib/site-packages/PIL/__pycache__/ExifTags.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/PIL/__pycache__/FitsImagePlugin.cpython-312.pyc b/venv/Lib/site-packages/PIL/__pycache__/FitsImagePlugin.cpython-312.pyc index 4817d5f..42fb6da 100644 Binary files a/venv/Lib/site-packages/PIL/__pycache__/FitsImagePlugin.cpython-312.pyc and b/venv/Lib/site-packages/PIL/__pycache__/FitsImagePlugin.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/PIL/__pycache__/FliImagePlugin.cpython-312.pyc b/venv/Lib/site-packages/PIL/__pycache__/FliImagePlugin.cpython-312.pyc index 88a4abb..efcaaf9 100644 Binary files a/venv/Lib/site-packages/PIL/__pycache__/FliImagePlugin.cpython-312.pyc and b/venv/Lib/site-packages/PIL/__pycache__/FliImagePlugin.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/PIL/__pycache__/FontFile.cpython-312.pyc b/venv/Lib/site-packages/PIL/__pycache__/FontFile.cpython-312.pyc index feebeb7..2204cec 100644 Binary files a/venv/Lib/site-packages/PIL/__pycache__/FontFile.cpython-312.pyc and b/venv/Lib/site-packages/PIL/__pycache__/FontFile.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/PIL/__pycache__/FpxImagePlugin.cpython-312.pyc b/venv/Lib/site-packages/PIL/__pycache__/FpxImagePlugin.cpython-312.pyc index 90e0810..dc0efdd 100644 Binary files a/venv/Lib/site-packages/PIL/__pycache__/FpxImagePlugin.cpython-312.pyc and b/venv/Lib/site-packages/PIL/__pycache__/FpxImagePlugin.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/PIL/__pycache__/FtexImagePlugin.cpython-312.pyc b/venv/Lib/site-packages/PIL/__pycache__/FtexImagePlugin.cpython-312.pyc index 304d7dc..70ad03a 100644 Binary files a/venv/Lib/site-packages/PIL/__pycache__/FtexImagePlugin.cpython-312.pyc and b/venv/Lib/site-packages/PIL/__pycache__/FtexImagePlugin.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/PIL/__pycache__/GbrImagePlugin.cpython-312.pyc b/venv/Lib/site-packages/PIL/__pycache__/GbrImagePlugin.cpython-312.pyc index 554d211..76d2498 100644 Binary files a/venv/Lib/site-packages/PIL/__pycache__/GbrImagePlugin.cpython-312.pyc and b/venv/Lib/site-packages/PIL/__pycache__/GbrImagePlugin.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/PIL/__pycache__/GdImageFile.cpython-312.pyc b/venv/Lib/site-packages/PIL/__pycache__/GdImageFile.cpython-312.pyc index 7c92365..814e562 100644 Binary files a/venv/Lib/site-packages/PIL/__pycache__/GdImageFile.cpython-312.pyc and b/venv/Lib/site-packages/PIL/__pycache__/GdImageFile.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/PIL/__pycache__/GifImagePlugin.cpython-312.pyc b/venv/Lib/site-packages/PIL/__pycache__/GifImagePlugin.cpython-312.pyc index 88ffe3f..465464a 100644 Binary files a/venv/Lib/site-packages/PIL/__pycache__/GifImagePlugin.cpython-312.pyc and b/venv/Lib/site-packages/PIL/__pycache__/GifImagePlugin.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/PIL/__pycache__/GimpGradientFile.cpython-312.pyc b/venv/Lib/site-packages/PIL/__pycache__/GimpGradientFile.cpython-312.pyc index 5c333e2..8818914 100644 Binary files a/venv/Lib/site-packages/PIL/__pycache__/GimpGradientFile.cpython-312.pyc and b/venv/Lib/site-packages/PIL/__pycache__/GimpGradientFile.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/PIL/__pycache__/GimpPaletteFile.cpython-312.pyc b/venv/Lib/site-packages/PIL/__pycache__/GimpPaletteFile.cpython-312.pyc index d4ec75c..369179d 100644 Binary files a/venv/Lib/site-packages/PIL/__pycache__/GimpPaletteFile.cpython-312.pyc and b/venv/Lib/site-packages/PIL/__pycache__/GimpPaletteFile.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/PIL/__pycache__/GribStubImagePlugin.cpython-312.pyc b/venv/Lib/site-packages/PIL/__pycache__/GribStubImagePlugin.cpython-312.pyc index 3f55a95..351bf4c 100644 Binary files a/venv/Lib/site-packages/PIL/__pycache__/GribStubImagePlugin.cpython-312.pyc and b/venv/Lib/site-packages/PIL/__pycache__/GribStubImagePlugin.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/PIL/__pycache__/Hdf5StubImagePlugin.cpython-312.pyc b/venv/Lib/site-packages/PIL/__pycache__/Hdf5StubImagePlugin.cpython-312.pyc index 2651b6a..6201c54 100644 Binary files a/venv/Lib/site-packages/PIL/__pycache__/Hdf5StubImagePlugin.cpython-312.pyc and b/venv/Lib/site-packages/PIL/__pycache__/Hdf5StubImagePlugin.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/PIL/__pycache__/IcnsImagePlugin.cpython-312.pyc b/venv/Lib/site-packages/PIL/__pycache__/IcnsImagePlugin.cpython-312.pyc index a6d446a..0e77735 100644 Binary files a/venv/Lib/site-packages/PIL/__pycache__/IcnsImagePlugin.cpython-312.pyc and b/venv/Lib/site-packages/PIL/__pycache__/IcnsImagePlugin.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/PIL/__pycache__/IcoImagePlugin.cpython-312.pyc b/venv/Lib/site-packages/PIL/__pycache__/IcoImagePlugin.cpython-312.pyc index fce6958..443d529 100644 Binary files a/venv/Lib/site-packages/PIL/__pycache__/IcoImagePlugin.cpython-312.pyc and b/venv/Lib/site-packages/PIL/__pycache__/IcoImagePlugin.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/PIL/__pycache__/ImImagePlugin.cpython-312.pyc b/venv/Lib/site-packages/PIL/__pycache__/ImImagePlugin.cpython-312.pyc index 402e2c9..03a116f 100644 Binary files a/venv/Lib/site-packages/PIL/__pycache__/ImImagePlugin.cpython-312.pyc and b/venv/Lib/site-packages/PIL/__pycache__/ImImagePlugin.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/PIL/__pycache__/Image.cpython-312.pyc b/venv/Lib/site-packages/PIL/__pycache__/Image.cpython-312.pyc index b1496ad..f85b330 100644 Binary files a/venv/Lib/site-packages/PIL/__pycache__/Image.cpython-312.pyc and b/venv/Lib/site-packages/PIL/__pycache__/Image.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/PIL/__pycache__/ImageChops.cpython-312.pyc b/venv/Lib/site-packages/PIL/__pycache__/ImageChops.cpython-312.pyc index 50b4a2a..fdb882b 100644 Binary files a/venv/Lib/site-packages/PIL/__pycache__/ImageChops.cpython-312.pyc and b/venv/Lib/site-packages/PIL/__pycache__/ImageChops.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/PIL/__pycache__/ImageCms.cpython-312.pyc b/venv/Lib/site-packages/PIL/__pycache__/ImageCms.cpython-312.pyc index 318c87a..b6409de 100644 Binary files a/venv/Lib/site-packages/PIL/__pycache__/ImageCms.cpython-312.pyc and b/venv/Lib/site-packages/PIL/__pycache__/ImageCms.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/PIL/__pycache__/ImageColor.cpython-312.pyc b/venv/Lib/site-packages/PIL/__pycache__/ImageColor.cpython-312.pyc index 17ea92e..6632568 100644 Binary files a/venv/Lib/site-packages/PIL/__pycache__/ImageColor.cpython-312.pyc and b/venv/Lib/site-packages/PIL/__pycache__/ImageColor.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/PIL/__pycache__/ImageDraw.cpython-312.pyc b/venv/Lib/site-packages/PIL/__pycache__/ImageDraw.cpython-312.pyc index 3173cf5..f87544c 100644 Binary files a/venv/Lib/site-packages/PIL/__pycache__/ImageDraw.cpython-312.pyc and b/venv/Lib/site-packages/PIL/__pycache__/ImageDraw.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/PIL/__pycache__/ImageDraw2.cpython-312.pyc b/venv/Lib/site-packages/PIL/__pycache__/ImageDraw2.cpython-312.pyc index c39a7c2..d61b68c 100644 Binary files a/venv/Lib/site-packages/PIL/__pycache__/ImageDraw2.cpython-312.pyc and b/venv/Lib/site-packages/PIL/__pycache__/ImageDraw2.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/PIL/__pycache__/ImageEnhance.cpython-312.pyc b/venv/Lib/site-packages/PIL/__pycache__/ImageEnhance.cpython-312.pyc index 160d0d6..236d5a5 100644 Binary files a/venv/Lib/site-packages/PIL/__pycache__/ImageEnhance.cpython-312.pyc and b/venv/Lib/site-packages/PIL/__pycache__/ImageEnhance.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/PIL/__pycache__/ImageFile.cpython-312.pyc b/venv/Lib/site-packages/PIL/__pycache__/ImageFile.cpython-312.pyc index 8dccaf0..cf80cdc 100644 Binary files a/venv/Lib/site-packages/PIL/__pycache__/ImageFile.cpython-312.pyc and b/venv/Lib/site-packages/PIL/__pycache__/ImageFile.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/PIL/__pycache__/ImageFilter.cpython-312.pyc b/venv/Lib/site-packages/PIL/__pycache__/ImageFilter.cpython-312.pyc index d7a92bb..223cde4 100644 Binary files a/venv/Lib/site-packages/PIL/__pycache__/ImageFilter.cpython-312.pyc and b/venv/Lib/site-packages/PIL/__pycache__/ImageFilter.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/PIL/__pycache__/ImageFont.cpython-312.pyc b/venv/Lib/site-packages/PIL/__pycache__/ImageFont.cpython-312.pyc index a5b5373..3a7c823 100644 Binary files a/venv/Lib/site-packages/PIL/__pycache__/ImageFont.cpython-312.pyc and b/venv/Lib/site-packages/PIL/__pycache__/ImageFont.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/PIL/__pycache__/ImageGrab.cpython-312.pyc b/venv/Lib/site-packages/PIL/__pycache__/ImageGrab.cpython-312.pyc index d142646..914f875 100644 Binary files a/venv/Lib/site-packages/PIL/__pycache__/ImageGrab.cpython-312.pyc and b/venv/Lib/site-packages/PIL/__pycache__/ImageGrab.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/PIL/__pycache__/ImageMath.cpython-312.pyc b/venv/Lib/site-packages/PIL/__pycache__/ImageMath.cpython-312.pyc index 063392c..ae64a40 100644 Binary files a/venv/Lib/site-packages/PIL/__pycache__/ImageMath.cpython-312.pyc and b/venv/Lib/site-packages/PIL/__pycache__/ImageMath.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/PIL/__pycache__/ImageMode.cpython-312.pyc b/venv/Lib/site-packages/PIL/__pycache__/ImageMode.cpython-312.pyc index 6a65bba..6b3f7f9 100644 Binary files a/venv/Lib/site-packages/PIL/__pycache__/ImageMode.cpython-312.pyc and b/venv/Lib/site-packages/PIL/__pycache__/ImageMode.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/PIL/__pycache__/ImageMorph.cpython-312.pyc b/venv/Lib/site-packages/PIL/__pycache__/ImageMorph.cpython-312.pyc index ed93379..226f0fd 100644 Binary files a/venv/Lib/site-packages/PIL/__pycache__/ImageMorph.cpython-312.pyc and b/venv/Lib/site-packages/PIL/__pycache__/ImageMorph.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/PIL/__pycache__/ImageOps.cpython-312.pyc b/venv/Lib/site-packages/PIL/__pycache__/ImageOps.cpython-312.pyc index b3390b6..e861c40 100644 Binary files a/venv/Lib/site-packages/PIL/__pycache__/ImageOps.cpython-312.pyc and b/venv/Lib/site-packages/PIL/__pycache__/ImageOps.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/PIL/__pycache__/ImagePalette.cpython-312.pyc b/venv/Lib/site-packages/PIL/__pycache__/ImagePalette.cpython-312.pyc index 00ef20e..87d0185 100644 Binary files a/venv/Lib/site-packages/PIL/__pycache__/ImagePalette.cpython-312.pyc and b/venv/Lib/site-packages/PIL/__pycache__/ImagePalette.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/PIL/__pycache__/ImagePath.cpython-312.pyc b/venv/Lib/site-packages/PIL/__pycache__/ImagePath.cpython-312.pyc index e8e3003..c005f09 100644 Binary files a/venv/Lib/site-packages/PIL/__pycache__/ImagePath.cpython-312.pyc and b/venv/Lib/site-packages/PIL/__pycache__/ImagePath.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/PIL/__pycache__/ImageQt.cpython-312.pyc b/venv/Lib/site-packages/PIL/__pycache__/ImageQt.cpython-312.pyc index 1052de2..1cab947 100644 Binary files a/venv/Lib/site-packages/PIL/__pycache__/ImageQt.cpython-312.pyc and b/venv/Lib/site-packages/PIL/__pycache__/ImageQt.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/PIL/__pycache__/ImageSequence.cpython-312.pyc b/venv/Lib/site-packages/PIL/__pycache__/ImageSequence.cpython-312.pyc index a9d70ee..ab45ac5 100644 Binary files a/venv/Lib/site-packages/PIL/__pycache__/ImageSequence.cpython-312.pyc and b/venv/Lib/site-packages/PIL/__pycache__/ImageSequence.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/PIL/__pycache__/ImageShow.cpython-312.pyc b/venv/Lib/site-packages/PIL/__pycache__/ImageShow.cpython-312.pyc index ea7fc24..f97760a 100644 Binary files a/venv/Lib/site-packages/PIL/__pycache__/ImageShow.cpython-312.pyc and b/venv/Lib/site-packages/PIL/__pycache__/ImageShow.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/PIL/__pycache__/ImageStat.cpython-312.pyc b/venv/Lib/site-packages/PIL/__pycache__/ImageStat.cpython-312.pyc index c873956..949574a 100644 Binary files a/venv/Lib/site-packages/PIL/__pycache__/ImageStat.cpython-312.pyc and b/venv/Lib/site-packages/PIL/__pycache__/ImageStat.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/PIL/__pycache__/ImageText.cpython-312.pyc b/venv/Lib/site-packages/PIL/__pycache__/ImageText.cpython-312.pyc deleted file mode 100644 index 990bee6..0000000 Binary files a/venv/Lib/site-packages/PIL/__pycache__/ImageText.cpython-312.pyc and /dev/null differ diff --git a/venv/Lib/site-packages/PIL/__pycache__/ImageTk.cpython-312.pyc b/venv/Lib/site-packages/PIL/__pycache__/ImageTk.cpython-312.pyc index b433e72..596deee 100644 Binary files a/venv/Lib/site-packages/PIL/__pycache__/ImageTk.cpython-312.pyc and b/venv/Lib/site-packages/PIL/__pycache__/ImageTk.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/PIL/__pycache__/ImageTransform.cpython-312.pyc b/venv/Lib/site-packages/PIL/__pycache__/ImageTransform.cpython-312.pyc index c1e7a18..55c88ec 100644 Binary files a/venv/Lib/site-packages/PIL/__pycache__/ImageTransform.cpython-312.pyc and b/venv/Lib/site-packages/PIL/__pycache__/ImageTransform.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/PIL/__pycache__/ImageWin.cpython-312.pyc b/venv/Lib/site-packages/PIL/__pycache__/ImageWin.cpython-312.pyc index 9148e6c..2a2fe0a 100644 Binary files a/venv/Lib/site-packages/PIL/__pycache__/ImageWin.cpython-312.pyc and b/venv/Lib/site-packages/PIL/__pycache__/ImageWin.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/PIL/__pycache__/ImtImagePlugin.cpython-312.pyc b/venv/Lib/site-packages/PIL/__pycache__/ImtImagePlugin.cpython-312.pyc index 96387b9..84009ea 100644 Binary files a/venv/Lib/site-packages/PIL/__pycache__/ImtImagePlugin.cpython-312.pyc and b/venv/Lib/site-packages/PIL/__pycache__/ImtImagePlugin.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/PIL/__pycache__/IptcImagePlugin.cpython-312.pyc b/venv/Lib/site-packages/PIL/__pycache__/IptcImagePlugin.cpython-312.pyc index 34e725a..1ddb344 100644 Binary files a/venv/Lib/site-packages/PIL/__pycache__/IptcImagePlugin.cpython-312.pyc and b/venv/Lib/site-packages/PIL/__pycache__/IptcImagePlugin.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/PIL/__pycache__/Jpeg2KImagePlugin.cpython-312.pyc b/venv/Lib/site-packages/PIL/__pycache__/Jpeg2KImagePlugin.cpython-312.pyc index 77094b7..c159282 100644 Binary files a/venv/Lib/site-packages/PIL/__pycache__/Jpeg2KImagePlugin.cpython-312.pyc and b/venv/Lib/site-packages/PIL/__pycache__/Jpeg2KImagePlugin.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/PIL/__pycache__/JpegImagePlugin.cpython-312.pyc b/venv/Lib/site-packages/PIL/__pycache__/JpegImagePlugin.cpython-312.pyc index 790b2f9..f7b5e5c 100644 Binary files a/venv/Lib/site-packages/PIL/__pycache__/JpegImagePlugin.cpython-312.pyc and b/venv/Lib/site-packages/PIL/__pycache__/JpegImagePlugin.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/PIL/__pycache__/JpegPresets.cpython-312.pyc b/venv/Lib/site-packages/PIL/__pycache__/JpegPresets.cpython-312.pyc index bd9c425..9ccdbff 100644 Binary files a/venv/Lib/site-packages/PIL/__pycache__/JpegPresets.cpython-312.pyc and b/venv/Lib/site-packages/PIL/__pycache__/JpegPresets.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/PIL/__pycache__/McIdasImagePlugin.cpython-312.pyc b/venv/Lib/site-packages/PIL/__pycache__/McIdasImagePlugin.cpython-312.pyc index a94ea62..7c41a6c 100644 Binary files a/venv/Lib/site-packages/PIL/__pycache__/McIdasImagePlugin.cpython-312.pyc and b/venv/Lib/site-packages/PIL/__pycache__/McIdasImagePlugin.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/PIL/__pycache__/MicImagePlugin.cpython-312.pyc b/venv/Lib/site-packages/PIL/__pycache__/MicImagePlugin.cpython-312.pyc index 6cd2b7c..e4b3624 100644 Binary files a/venv/Lib/site-packages/PIL/__pycache__/MicImagePlugin.cpython-312.pyc and b/venv/Lib/site-packages/PIL/__pycache__/MicImagePlugin.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/PIL/__pycache__/MpegImagePlugin.cpython-312.pyc b/venv/Lib/site-packages/PIL/__pycache__/MpegImagePlugin.cpython-312.pyc index 6ce3b6c..39094c2 100644 Binary files a/venv/Lib/site-packages/PIL/__pycache__/MpegImagePlugin.cpython-312.pyc and b/venv/Lib/site-packages/PIL/__pycache__/MpegImagePlugin.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/PIL/__pycache__/MpoImagePlugin.cpython-312.pyc b/venv/Lib/site-packages/PIL/__pycache__/MpoImagePlugin.cpython-312.pyc index e6d010b..e537c13 100644 Binary files a/venv/Lib/site-packages/PIL/__pycache__/MpoImagePlugin.cpython-312.pyc and b/venv/Lib/site-packages/PIL/__pycache__/MpoImagePlugin.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/PIL/__pycache__/MspImagePlugin.cpython-312.pyc b/venv/Lib/site-packages/PIL/__pycache__/MspImagePlugin.cpython-312.pyc index 82475d2..481b7e4 100644 Binary files a/venv/Lib/site-packages/PIL/__pycache__/MspImagePlugin.cpython-312.pyc and b/venv/Lib/site-packages/PIL/__pycache__/MspImagePlugin.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/PIL/__pycache__/PSDraw.cpython-312.pyc b/venv/Lib/site-packages/PIL/__pycache__/PSDraw.cpython-312.pyc index 4deeff5..6647a9e 100644 Binary files a/venv/Lib/site-packages/PIL/__pycache__/PSDraw.cpython-312.pyc and b/venv/Lib/site-packages/PIL/__pycache__/PSDraw.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/PIL/__pycache__/PaletteFile.cpython-312.pyc b/venv/Lib/site-packages/PIL/__pycache__/PaletteFile.cpython-312.pyc index 3a5365e..d4e1ef2 100644 Binary files a/venv/Lib/site-packages/PIL/__pycache__/PaletteFile.cpython-312.pyc and b/venv/Lib/site-packages/PIL/__pycache__/PaletteFile.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/PIL/__pycache__/PalmImagePlugin.cpython-312.pyc b/venv/Lib/site-packages/PIL/__pycache__/PalmImagePlugin.cpython-312.pyc index b13ad73..2415a33 100644 Binary files a/venv/Lib/site-packages/PIL/__pycache__/PalmImagePlugin.cpython-312.pyc and b/venv/Lib/site-packages/PIL/__pycache__/PalmImagePlugin.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/PIL/__pycache__/PcdImagePlugin.cpython-312.pyc b/venv/Lib/site-packages/PIL/__pycache__/PcdImagePlugin.cpython-312.pyc index cb36818..7b5ca4b 100644 Binary files a/venv/Lib/site-packages/PIL/__pycache__/PcdImagePlugin.cpython-312.pyc and b/venv/Lib/site-packages/PIL/__pycache__/PcdImagePlugin.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/PIL/__pycache__/PcfFontFile.cpython-312.pyc b/venv/Lib/site-packages/PIL/__pycache__/PcfFontFile.cpython-312.pyc index 356995b..4008389 100644 Binary files a/venv/Lib/site-packages/PIL/__pycache__/PcfFontFile.cpython-312.pyc and b/venv/Lib/site-packages/PIL/__pycache__/PcfFontFile.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/PIL/__pycache__/PcxImagePlugin.cpython-312.pyc b/venv/Lib/site-packages/PIL/__pycache__/PcxImagePlugin.cpython-312.pyc index e4d0a38..0f851df 100644 Binary files a/venv/Lib/site-packages/PIL/__pycache__/PcxImagePlugin.cpython-312.pyc and b/venv/Lib/site-packages/PIL/__pycache__/PcxImagePlugin.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/PIL/__pycache__/PdfImagePlugin.cpython-312.pyc b/venv/Lib/site-packages/PIL/__pycache__/PdfImagePlugin.cpython-312.pyc index 29bd43e..fd2a35c 100644 Binary files a/venv/Lib/site-packages/PIL/__pycache__/PdfImagePlugin.cpython-312.pyc and b/venv/Lib/site-packages/PIL/__pycache__/PdfImagePlugin.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/PIL/__pycache__/PdfParser.cpython-312.pyc b/venv/Lib/site-packages/PIL/__pycache__/PdfParser.cpython-312.pyc index c3d145b..dd405c1 100644 Binary files a/venv/Lib/site-packages/PIL/__pycache__/PdfParser.cpython-312.pyc and b/venv/Lib/site-packages/PIL/__pycache__/PdfParser.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/PIL/__pycache__/PixarImagePlugin.cpython-312.pyc b/venv/Lib/site-packages/PIL/__pycache__/PixarImagePlugin.cpython-312.pyc index a83264e..023edde 100644 Binary files a/venv/Lib/site-packages/PIL/__pycache__/PixarImagePlugin.cpython-312.pyc and b/venv/Lib/site-packages/PIL/__pycache__/PixarImagePlugin.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/PIL/__pycache__/PngImagePlugin.cpython-312.pyc b/venv/Lib/site-packages/PIL/__pycache__/PngImagePlugin.cpython-312.pyc index ba91ceb..319cf4f 100644 Binary files a/venv/Lib/site-packages/PIL/__pycache__/PngImagePlugin.cpython-312.pyc and b/venv/Lib/site-packages/PIL/__pycache__/PngImagePlugin.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/PIL/__pycache__/PpmImagePlugin.cpython-312.pyc b/venv/Lib/site-packages/PIL/__pycache__/PpmImagePlugin.cpython-312.pyc index 752a356..1bdeada 100644 Binary files a/venv/Lib/site-packages/PIL/__pycache__/PpmImagePlugin.cpython-312.pyc and b/venv/Lib/site-packages/PIL/__pycache__/PpmImagePlugin.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/PIL/__pycache__/PsdImagePlugin.cpython-312.pyc b/venv/Lib/site-packages/PIL/__pycache__/PsdImagePlugin.cpython-312.pyc index 21c9db2..972e754 100644 Binary files a/venv/Lib/site-packages/PIL/__pycache__/PsdImagePlugin.cpython-312.pyc and b/venv/Lib/site-packages/PIL/__pycache__/PsdImagePlugin.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/PIL/__pycache__/PyAccess.cpython-312.pyc b/venv/Lib/site-packages/PIL/__pycache__/PyAccess.cpython-312.pyc new file mode 100644 index 0000000..ed156da Binary files /dev/null and b/venv/Lib/site-packages/PIL/__pycache__/PyAccess.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/PIL/__pycache__/QoiImagePlugin.cpython-312.pyc b/venv/Lib/site-packages/PIL/__pycache__/QoiImagePlugin.cpython-312.pyc index 5e83af3..bc05a75 100644 Binary files a/venv/Lib/site-packages/PIL/__pycache__/QoiImagePlugin.cpython-312.pyc and b/venv/Lib/site-packages/PIL/__pycache__/QoiImagePlugin.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/PIL/__pycache__/SgiImagePlugin.cpython-312.pyc b/venv/Lib/site-packages/PIL/__pycache__/SgiImagePlugin.cpython-312.pyc index 6c57eb3..125af06 100644 Binary files a/venv/Lib/site-packages/PIL/__pycache__/SgiImagePlugin.cpython-312.pyc and b/venv/Lib/site-packages/PIL/__pycache__/SgiImagePlugin.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/PIL/__pycache__/SpiderImagePlugin.cpython-312.pyc b/venv/Lib/site-packages/PIL/__pycache__/SpiderImagePlugin.cpython-312.pyc index dd669f5..4853cef 100644 Binary files a/venv/Lib/site-packages/PIL/__pycache__/SpiderImagePlugin.cpython-312.pyc and b/venv/Lib/site-packages/PIL/__pycache__/SpiderImagePlugin.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/PIL/__pycache__/SunImagePlugin.cpython-312.pyc b/venv/Lib/site-packages/PIL/__pycache__/SunImagePlugin.cpython-312.pyc index b1af32c..3a27cde 100644 Binary files a/venv/Lib/site-packages/PIL/__pycache__/SunImagePlugin.cpython-312.pyc and b/venv/Lib/site-packages/PIL/__pycache__/SunImagePlugin.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/PIL/__pycache__/TarIO.cpython-312.pyc b/venv/Lib/site-packages/PIL/__pycache__/TarIO.cpython-312.pyc index 789dd33..22ccc74 100644 Binary files a/venv/Lib/site-packages/PIL/__pycache__/TarIO.cpython-312.pyc and b/venv/Lib/site-packages/PIL/__pycache__/TarIO.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/PIL/__pycache__/TgaImagePlugin.cpython-312.pyc b/venv/Lib/site-packages/PIL/__pycache__/TgaImagePlugin.cpython-312.pyc index ed15da8..2269f9a 100644 Binary files a/venv/Lib/site-packages/PIL/__pycache__/TgaImagePlugin.cpython-312.pyc and b/venv/Lib/site-packages/PIL/__pycache__/TgaImagePlugin.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/PIL/__pycache__/TiffImagePlugin.cpython-312.pyc b/venv/Lib/site-packages/PIL/__pycache__/TiffImagePlugin.cpython-312.pyc index bc869cc..ab455f9 100644 Binary files a/venv/Lib/site-packages/PIL/__pycache__/TiffImagePlugin.cpython-312.pyc and b/venv/Lib/site-packages/PIL/__pycache__/TiffImagePlugin.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/PIL/__pycache__/TiffTags.cpython-312.pyc b/venv/Lib/site-packages/PIL/__pycache__/TiffTags.cpython-312.pyc index a0d2538..f7a8bf2 100644 Binary files a/venv/Lib/site-packages/PIL/__pycache__/TiffTags.cpython-312.pyc and b/venv/Lib/site-packages/PIL/__pycache__/TiffTags.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/PIL/__pycache__/WalImageFile.cpython-312.pyc b/venv/Lib/site-packages/PIL/__pycache__/WalImageFile.cpython-312.pyc index 218872a..ab11415 100644 Binary files a/venv/Lib/site-packages/PIL/__pycache__/WalImageFile.cpython-312.pyc and b/venv/Lib/site-packages/PIL/__pycache__/WalImageFile.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/PIL/__pycache__/WebPImagePlugin.cpython-312.pyc b/venv/Lib/site-packages/PIL/__pycache__/WebPImagePlugin.cpython-312.pyc index 773916c..150dd1c 100644 Binary files a/venv/Lib/site-packages/PIL/__pycache__/WebPImagePlugin.cpython-312.pyc and b/venv/Lib/site-packages/PIL/__pycache__/WebPImagePlugin.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/PIL/__pycache__/WmfImagePlugin.cpython-312.pyc b/venv/Lib/site-packages/PIL/__pycache__/WmfImagePlugin.cpython-312.pyc index 1d061ed..bc269bf 100644 Binary files a/venv/Lib/site-packages/PIL/__pycache__/WmfImagePlugin.cpython-312.pyc and b/venv/Lib/site-packages/PIL/__pycache__/WmfImagePlugin.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/PIL/__pycache__/XVThumbImagePlugin.cpython-312.pyc b/venv/Lib/site-packages/PIL/__pycache__/XVThumbImagePlugin.cpython-312.pyc index cab96b0..6424332 100644 Binary files a/venv/Lib/site-packages/PIL/__pycache__/XVThumbImagePlugin.cpython-312.pyc and b/venv/Lib/site-packages/PIL/__pycache__/XVThumbImagePlugin.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/PIL/__pycache__/XbmImagePlugin.cpython-312.pyc b/venv/Lib/site-packages/PIL/__pycache__/XbmImagePlugin.cpython-312.pyc index c53dfeb..6b4d0c5 100644 Binary files a/venv/Lib/site-packages/PIL/__pycache__/XbmImagePlugin.cpython-312.pyc and b/venv/Lib/site-packages/PIL/__pycache__/XbmImagePlugin.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/PIL/__pycache__/XpmImagePlugin.cpython-312.pyc b/venv/Lib/site-packages/PIL/__pycache__/XpmImagePlugin.cpython-312.pyc index 4a3b62c..7059192 100644 Binary files a/venv/Lib/site-packages/PIL/__pycache__/XpmImagePlugin.cpython-312.pyc and b/venv/Lib/site-packages/PIL/__pycache__/XpmImagePlugin.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/PIL/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/PIL/__pycache__/__init__.cpython-312.pyc index 8cd322c..96d69e6 100644 Binary files a/venv/Lib/site-packages/PIL/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/PIL/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/PIL/__pycache__/__main__.cpython-312.pyc b/venv/Lib/site-packages/PIL/__pycache__/__main__.cpython-312.pyc index 8e21158..3bb7631 100644 Binary files a/venv/Lib/site-packages/PIL/__pycache__/__main__.cpython-312.pyc and b/venv/Lib/site-packages/PIL/__pycache__/__main__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/PIL/__pycache__/_binary.cpython-312.pyc b/venv/Lib/site-packages/PIL/__pycache__/_binary.cpython-312.pyc index 985ecd7..31bb51e 100644 Binary files a/venv/Lib/site-packages/PIL/__pycache__/_binary.cpython-312.pyc and b/venv/Lib/site-packages/PIL/__pycache__/_binary.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/PIL/__pycache__/_deprecate.cpython-312.pyc b/venv/Lib/site-packages/PIL/__pycache__/_deprecate.cpython-312.pyc index 95c9194..6198aa2 100644 Binary files a/venv/Lib/site-packages/PIL/__pycache__/_deprecate.cpython-312.pyc and b/venv/Lib/site-packages/PIL/__pycache__/_deprecate.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/PIL/__pycache__/_tkinter_finder.cpython-312.pyc b/venv/Lib/site-packages/PIL/__pycache__/_tkinter_finder.cpython-312.pyc index da317f9..33b4037 100644 Binary files a/venv/Lib/site-packages/PIL/__pycache__/_tkinter_finder.cpython-312.pyc and b/venv/Lib/site-packages/PIL/__pycache__/_tkinter_finder.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/PIL/__pycache__/_typing.cpython-312.pyc b/venv/Lib/site-packages/PIL/__pycache__/_typing.cpython-312.pyc index f00ec22..0f52c56 100644 Binary files a/venv/Lib/site-packages/PIL/__pycache__/_typing.cpython-312.pyc and b/venv/Lib/site-packages/PIL/__pycache__/_typing.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/PIL/__pycache__/_util.cpython-312.pyc b/venv/Lib/site-packages/PIL/__pycache__/_util.cpython-312.pyc index b28fd58..9d170f0 100644 Binary files a/venv/Lib/site-packages/PIL/__pycache__/_util.cpython-312.pyc and b/venv/Lib/site-packages/PIL/__pycache__/_util.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/PIL/__pycache__/_version.cpython-312.pyc b/venv/Lib/site-packages/PIL/__pycache__/_version.cpython-312.pyc index 58bedb1..7423e65 100644 Binary files a/venv/Lib/site-packages/PIL/__pycache__/_version.cpython-312.pyc and b/venv/Lib/site-packages/PIL/__pycache__/_version.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/PIL/__pycache__/features.cpython-312.pyc b/venv/Lib/site-packages/PIL/__pycache__/features.cpython-312.pyc index 846ba0c..003d0cf 100644 Binary files a/venv/Lib/site-packages/PIL/__pycache__/features.cpython-312.pyc and b/venv/Lib/site-packages/PIL/__pycache__/features.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/PIL/__pycache__/report.cpython-312.pyc b/venv/Lib/site-packages/PIL/__pycache__/report.cpython-312.pyc index a0e386d..6d4895c 100644 Binary files a/venv/Lib/site-packages/PIL/__pycache__/report.cpython-312.pyc and b/venv/Lib/site-packages/PIL/__pycache__/report.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/PIL/_avif.cp312-win_amd64.pyd b/venv/Lib/site-packages/PIL/_avif.cp312-win_amd64.pyd deleted file mode 100644 index 394db75..0000000 Binary files a/venv/Lib/site-packages/PIL/_avif.cp312-win_amd64.pyd and /dev/null differ diff --git a/venv/Lib/site-packages/PIL/_avif.pyi b/venv/Lib/site-packages/PIL/_avif.pyi deleted file mode 100644 index e27843e..0000000 --- a/venv/Lib/site-packages/PIL/_avif.pyi +++ /dev/null @@ -1,3 +0,0 @@ -from typing import Any - -def __getattr__(name: str) -> Any: ... diff --git a/venv/Lib/site-packages/PIL/_deprecate.py b/venv/Lib/site-packages/PIL/_deprecate.py index 711c62a..33a0e07 100644 --- a/venv/Lib/site-packages/PIL/_deprecate.py +++ b/venv/Lib/site-packages/PIL/_deprecate.py @@ -12,7 +12,6 @@ def deprecate( *, action: str | None = None, plural: bool = False, - stacklevel: int = 3, ) -> None: """ Deprecations helper. @@ -46,10 +45,10 @@ def deprecate( elif when <= int(__version__.split(".")[0]): msg = f"{deprecated} {is_} deprecated and should be removed." raise RuntimeError(msg) - elif when == 13: - removed = "Pillow 13 (2026-10-15)" - elif when == 14: - removed = "Pillow 14 (2027-10-15)" + elif when == 11: + removed = "Pillow 11 (2024-10-15)" + elif when == 12: + removed = "Pillow 12 (2025-10-15)" else: msg = f"Unknown removal version: {when}. Update {__name__}?" raise ValueError(msg) @@ -68,5 +67,5 @@ def deprecate( warnings.warn( f"{deprecated} {is_} deprecated and will be removed in {removed}{action}", DeprecationWarning, - stacklevel=stacklevel, + stacklevel=3, ) diff --git a/venv/Lib/site-packages/PIL/_imaging.cp312-win_amd64.pyd b/venv/Lib/site-packages/PIL/_imaging.cp312-win_amd64.pyd index cb0bd1f..c380321 100644 Binary files a/venv/Lib/site-packages/PIL/_imaging.cp312-win_amd64.pyd and b/venv/Lib/site-packages/PIL/_imaging.cp312-win_amd64.pyd differ diff --git a/venv/Lib/site-packages/PIL/_imaging.pyi b/venv/Lib/site-packages/PIL/_imaging.pyi index 81028a5..8cccd3a 100644 --- a/venv/Lib/site-packages/PIL/_imaging.pyi +++ b/venv/Lib/site-packages/PIL/_imaging.pyi @@ -1,7 +1,6 @@ from typing import Any class ImagingCore: - def __getitem__(self, index: int) -> float | tuple[int, ...] | None: ... def __getattr__(self, name: str) -> Any: ... class ImagingFont: diff --git a/venv/Lib/site-packages/PIL/_imagingcms.cp312-win_amd64.pyd b/venv/Lib/site-packages/PIL/_imagingcms.cp312-win_amd64.pyd index 5646c4e..91c1b05 100644 Binary files a/venv/Lib/site-packages/PIL/_imagingcms.cp312-win_amd64.pyd and b/venv/Lib/site-packages/PIL/_imagingcms.cp312-win_amd64.pyd differ diff --git a/venv/Lib/site-packages/PIL/_imagingcms.pyi b/venv/Lib/site-packages/PIL/_imagingcms.pyi index 4fc0d60..2abd6d0 100644 --- a/venv/Lib/site-packages/PIL/_imagingcms.pyi +++ b/venv/Lib/site-packages/PIL/_imagingcms.pyi @@ -1,14 +1,12 @@ import datetime import sys -from typing import Literal, SupportsFloat, TypeAlias, TypedDict - -from ._typing import CapsuleType +from typing import Literal, SupportsFloat, TypedDict littlecms_version: str | None -_Tuple3f: TypeAlias = tuple[float, float, float] -_Tuple2x3f: TypeAlias = tuple[_Tuple3f, _Tuple3f] -_Tuple3x3f: TypeAlias = tuple[_Tuple3f, _Tuple3f, _Tuple3f] +_Tuple3f = tuple[float, float, float] +_Tuple2x3f = tuple[_Tuple3f, _Tuple3f] +_Tuple3x3f = tuple[_Tuple3f, _Tuple3f, _Tuple3f] class _IccMeasurementCondition(TypedDict): observer: int @@ -110,7 +108,7 @@ class CmsProfile: def is_intent_supported(self, intent: int, direction: int, /) -> int: ... class CmsTransform: - def apply(self, id_in: CapsuleType, id_out: CapsuleType) -> int: ... + def apply(self, id_in: int, id_out: int) -> int: ... def profile_open(profile: str, /) -> CmsProfile: ... def profile_frombytes(profile: bytes, /) -> CmsProfile: ... diff --git a/venv/Lib/site-packages/PIL/_imagingft.cp312-win_amd64.pyd b/venv/Lib/site-packages/PIL/_imagingft.cp312-win_amd64.pyd index bb2609c..f6db636 100644 Binary files a/venv/Lib/site-packages/PIL/_imagingft.cp312-win_amd64.pyd and b/venv/Lib/site-packages/PIL/_imagingft.cp312-win_amd64.pyd differ diff --git a/venv/Lib/site-packages/PIL/_imagingft.pyi b/venv/Lib/site-packages/PIL/_imagingft.pyi index 2136810..5e97b40 100644 --- a/venv/Lib/site-packages/PIL/_imagingft.pyi +++ b/venv/Lib/site-packages/PIL/_imagingft.pyi @@ -1,7 +1,12 @@ -from collections.abc import Callable -from typing import Any +from typing import Any, TypedDict -from . import ImageFont, _imaging +from . import _imaging + +class _Axis(TypedDict): + minimum: int | None + default: int | None + maximum: int | None + name: bytes | None class Font: @property @@ -23,48 +28,42 @@ class Font: def render( self, string: str | bytes, - fill: Callable[[int, int], _imaging.ImagingCore], - mode: str, - dir: str | None, - features: list[str] | None, - lang: str | None, - stroke_width: float, - stroke_filled: bool, - anchor: str | None, - foreground_ink_long: int, - start: tuple[float, float], + fill, + mode=..., + dir=..., + features=..., + lang=..., + stroke_width=..., + anchor=..., + foreground_ink_long=..., + x_start=..., + y_start=..., /, ) -> tuple[_imaging.ImagingCore, tuple[int, int]]: ... def getsize( self, string: str | bytes | bytearray, - mode: str, - dir: str | None, - features: list[str] | None, - lang: str | None, - anchor: str | None, + mode=..., + dir=..., + features=..., + lang=..., + anchor=..., /, ) -> tuple[tuple[int, int], tuple[int, int]]: ... def getlength( - self, - string: str | bytes, - mode: str, - dir: str | None, - features: list[str] | None, - lang: str | None, - /, + self, string: str | bytes, mode=..., dir=..., features=..., lang=..., / ) -> float: ... def getvarnames(self) -> list[bytes]: ... - def getvaraxes(self) -> list[ImageFont.Axis]: ... + def getvaraxes(self) -> list[_Axis] | None: ... def setvarname(self, instance_index: int, /) -> None: ... def setvaraxes(self, axes: list[float], /) -> None: ... def getfont( filename: str | bytes, size: float, - index: int, - encoding: str, - font_bytes: bytes, - layout_engine: int, + index=..., + encoding=..., + font_bytes=..., + layout_engine=..., ) -> Font: ... def __getattr__(name: str) -> Any: ... diff --git a/venv/Lib/site-packages/PIL/_imagingmath.cp312-win_amd64.pyd b/venv/Lib/site-packages/PIL/_imagingmath.cp312-win_amd64.pyd index fa932ce..29316fa 100644 Binary files a/venv/Lib/site-packages/PIL/_imagingmath.cp312-win_amd64.pyd and b/venv/Lib/site-packages/PIL/_imagingmath.cp312-win_amd64.pyd differ diff --git a/venv/Lib/site-packages/PIL/_imagingmorph.cp312-win_amd64.pyd b/venv/Lib/site-packages/PIL/_imagingmorph.cp312-win_amd64.pyd index 3a27ecf..ee4d30e 100644 Binary files a/venv/Lib/site-packages/PIL/_imagingmorph.cp312-win_amd64.pyd and b/venv/Lib/site-packages/PIL/_imagingmorph.cp312-win_amd64.pyd differ diff --git a/venv/Lib/site-packages/PIL/_imagingtk.cp312-win_amd64.pyd b/venv/Lib/site-packages/PIL/_imagingtk.cp312-win_amd64.pyd index 2cf632f..8da18a8 100644 Binary files a/venv/Lib/site-packages/PIL/_imagingtk.cp312-win_amd64.pyd and b/venv/Lib/site-packages/PIL/_imagingtk.cp312-win_amd64.pyd differ diff --git a/venv/Lib/site-packages/PIL/_imagingtk.pyi b/venv/Lib/site-packages/PIL/_imagingtk.pyi deleted file mode 100644 index e27843e..0000000 --- a/venv/Lib/site-packages/PIL/_imagingtk.pyi +++ /dev/null @@ -1,3 +0,0 @@ -from typing import Any - -def __getattr__(name: str) -> Any: ... diff --git a/venv/Lib/site-packages/PIL/_tkinter_finder.py b/venv/Lib/site-packages/PIL/_tkinter_finder.py index 9c01430..beddfb0 100644 --- a/venv/Lib/site-packages/PIL/_tkinter_finder.py +++ b/venv/Lib/site-packages/PIL/_tkinter_finder.py @@ -1,4 +1,5 @@ -"""Find compiled module linking to Tcl / Tk libraries""" +""" Find compiled module linking to Tcl / Tk libraries +""" from __future__ import annotations diff --git a/venv/Lib/site-packages/PIL/_typing.py b/venv/Lib/site-packages/PIL/_typing.py index a941f89..09ece18 100644 --- a/venv/Lib/site-packages/PIL/_typing.py +++ b/venv/Lib/site-packages/PIL/_typing.py @@ -2,44 +2,38 @@ from __future__ import annotations import os import sys -from collections.abc import Sequence -from typing import Any, Protocol, TypeVar +from typing import Any, Protocol, Sequence, TypeVar, Union -TYPE_CHECKING = False -if TYPE_CHECKING: - from numbers import _IntegralLike as IntegralLike +try: + import numpy.typing as npt + NumpyArray = npt.NDArray[Any] +except ImportError: + pass + +if sys.version_info >= (3, 10): + from typing import TypeGuard +else: try: - import numpy.typing as npt - - NumpyArray = npt.NDArray[Any] + from typing_extensions import TypeGuard except ImportError: - pass -if sys.version_info >= (3, 13): - from types import CapsuleType -else: - CapsuleType = object - -if sys.version_info >= (3, 12): - from collections.abc import Buffer -else: - Buffer = Any + class TypeGuard: # type: ignore[no-redef] + def __class_getitem__(cls, item: Any) -> type[bool]: + return bool -_Ink = float | tuple[int, ...] | str - -Coords = Sequence[float] | Sequence[Sequence[float]] +Coords = Union[Sequence[float], Sequence[Sequence[float]]] _T_co = TypeVar("_T_co", covariant=True) class SupportsRead(Protocol[_T_co]): - def read(self, length: int = ..., /) -> _T_co: ... + def read(self, __length: int = ...) -> _T_co: ... -StrOrBytesPath = str | bytes | os.PathLike[str] | os.PathLike[bytes] +StrOrBytesPath = Union[str, bytes, "os.PathLike[str]", "os.PathLike[bytes]"] -__all__ = ["Buffer", "IntegralLike", "StrOrBytesPath", "SupportsRead"] +__all__ = ["TypeGuard", "StrOrBytesPath", "SupportsRead"] diff --git a/venv/Lib/site-packages/PIL/_util.py b/venv/Lib/site-packages/PIL/_util.py index b1fa6a0..6bc7628 100644 --- a/venv/Lib/site-packages/PIL/_util.py +++ b/venv/Lib/site-packages/PIL/_util.py @@ -1,18 +1,20 @@ from __future__ import annotations import os +from typing import Any, NoReturn -TYPE_CHECKING = False -if TYPE_CHECKING: - from typing import Any, NoReturn, TypeGuard - - from ._typing import StrOrBytesPath +from ._typing import StrOrBytesPath, TypeGuard def is_path(f: Any) -> TypeGuard[StrOrBytesPath]: return isinstance(f, (bytes, str, os.PathLike)) +def is_directory(f: Any) -> TypeGuard[StrOrBytesPath]: + """Checks if an object is a string, and that it points to a directory.""" + return is_path(f) and os.path.isdir(f) + + class DeferredError: def __init__(self, ex: BaseException): self.ex = ex diff --git a/venv/Lib/site-packages/PIL/_version.py b/venv/Lib/site-packages/PIL/_version.py index b32ff44..cebfd86 100644 --- a/venv/Lib/site-packages/PIL/_version.py +++ b/venv/Lib/site-packages/PIL/_version.py @@ -1,4 +1,4 @@ # Master version for Pillow from __future__ import annotations -__version__ = "12.1.0" +__version__ = "10.4.0" diff --git a/venv/Lib/site-packages/PIL/_webp.cp312-win_amd64.pyd b/venv/Lib/site-packages/PIL/_webp.cp312-win_amd64.pyd index 5f1d989..5421a7e 100644 Binary files a/venv/Lib/site-packages/PIL/_webp.cp312-win_amd64.pyd and b/venv/Lib/site-packages/PIL/_webp.cp312-win_amd64.pyd differ diff --git a/venv/Lib/site-packages/PIL/features.py b/venv/Lib/site-packages/PIL/features.py index ff32c25..13908c4 100644 --- a/venv/Lib/site-packages/PIL/features.py +++ b/venv/Lib/site-packages/PIL/features.py @@ -16,7 +16,6 @@ modules = { "freetype2": ("PIL._imagingft", "freetype2_version"), "littlecms2": ("PIL._imagingcms", "littlecms_version"), "webp": ("PIL._webp", "webpdecoder_version"), - "avif": ("PIL._avif", "libavif_version"), } @@ -119,13 +118,14 @@ def get_supported_codecs() -> list[str]: return [f for f in codecs if check_codec(f)] -features: dict[str, tuple[str, str, str | None]] = { +features = { + "webp_anim": ("PIL._webp", "HAVE_WEBPANIM", None), + "webp_mux": ("PIL._webp", "HAVE_WEBPMUX", None), + "transp_webp": ("PIL._webp", "HAVE_TRANSPARENCY", None), "raqm": ("PIL._imagingft", "HAVE_RAQM", "raqm_version"), "fribidi": ("PIL._imagingft", "HAVE_FRIBIDI", "fribidi_version"), "harfbuzz": ("PIL._imagingft", "HAVE_HARFBUZZ", "harfbuzz_version"), "libjpeg_turbo": ("PIL._imaging", "HAVE_LIBJPEGTURBO", "libjpeg_turbo_version"), - "mozjpeg": ("PIL._imaging", "HAVE_MOZJPEG", "libjpeg_turbo_version"), - "zlib_ng": ("PIL._imaging", "HAVE_ZLIBNG", "zlib_ng_version"), "libimagequant": ("PIL._imaging", "HAVE_LIBIMAGEQUANT", "imagequant_version"), "xcb": ("PIL._imaging", "HAVE_XCB", None), } @@ -271,7 +271,9 @@ def pilinfo(out: IO[str] | None = None, supported_formats: bool = True) -> None: ("freetype2", "FREETYPE2"), ("littlecms2", "LITTLECMS2"), ("webp", "WEBP"), - ("avif", "AVIF"), + ("transp_webp", "WEBP Transparency"), + ("webp_mux", "WEBPMUX"), + ("webp_anim", "WEBP Animation"), ("jpg", "JPEG"), ("jpg_2000", "OPENJPEG (JPEG2000)"), ("zlib", "ZLIB (PNG/ZIP)"), @@ -285,8 +287,7 @@ def pilinfo(out: IO[str] | None = None, supported_formats: bool = True) -> None: if name == "jpg": libjpeg_turbo_version = version_feature("libjpeg_turbo") if libjpeg_turbo_version is not None: - v = "mozjpeg" if check_feature("mozjpeg") else "libjpeg-turbo" - v += " " + libjpeg_turbo_version + v = "libjpeg-turbo " + libjpeg_turbo_version if v is None: v = version(name) if v is not None: @@ -295,11 +296,7 @@ def pilinfo(out: IO[str] | None = None, supported_formats: bool = True) -> None: # this check is also in src/_imagingcms.c:setup_module() version_static = tuple(int(x) for x in v.split(".")) < (2, 7) t = "compiled for" if version_static else "loaded" - if name == "zlib": - zlib_ng_version = version_feature("zlib_ng") - if zlib_ng_version is not None: - v += ", compiled for zlib-ng " + zlib_ng_version - elif name == "raqm": + if name == "raqm": for f in ("fribidi", "harfbuzz"): v2 = version_feature(f) if v2 is not None: diff --git a/venv/Lib/site-packages/Tea/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/Tea/__pycache__/__init__.cpython-312.pyc index 085a644..652054a 100644 Binary files a/venv/Lib/site-packages/Tea/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/Tea/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Tea/__pycache__/core.cpython-312.pyc b/venv/Lib/site-packages/Tea/__pycache__/core.cpython-312.pyc index 145c09f..a711795 100644 Binary files a/venv/Lib/site-packages/Tea/__pycache__/core.cpython-312.pyc and b/venv/Lib/site-packages/Tea/__pycache__/core.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Tea/__pycache__/decorators.cpython-312.pyc b/venv/Lib/site-packages/Tea/__pycache__/decorators.cpython-312.pyc index 87c6c80..e0b2a57 100644 Binary files a/venv/Lib/site-packages/Tea/__pycache__/decorators.cpython-312.pyc and b/venv/Lib/site-packages/Tea/__pycache__/decorators.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Tea/__pycache__/exceptions.cpython-312.pyc b/venv/Lib/site-packages/Tea/__pycache__/exceptions.cpython-312.pyc index b3b6e7e..23bb3bb 100644 Binary files a/venv/Lib/site-packages/Tea/__pycache__/exceptions.cpython-312.pyc and b/venv/Lib/site-packages/Tea/__pycache__/exceptions.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Tea/__pycache__/model.cpython-312.pyc b/venv/Lib/site-packages/Tea/__pycache__/model.cpython-312.pyc index 7e678ad..c471b68 100644 Binary files a/venv/Lib/site-packages/Tea/__pycache__/model.cpython-312.pyc and b/venv/Lib/site-packages/Tea/__pycache__/model.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Tea/__pycache__/request.cpython-312.pyc b/venv/Lib/site-packages/Tea/__pycache__/request.cpython-312.pyc index 813da8f..21c00ac 100644 Binary files a/venv/Lib/site-packages/Tea/__pycache__/request.cpython-312.pyc and b/venv/Lib/site-packages/Tea/__pycache__/request.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Tea/__pycache__/response.cpython-312.pyc b/venv/Lib/site-packages/Tea/__pycache__/response.cpython-312.pyc index 3c83ec9..4f5e9a5 100644 Binary files a/venv/Lib/site-packages/Tea/__pycache__/response.cpython-312.pyc and b/venv/Lib/site-packages/Tea/__pycache__/response.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/Tea/__pycache__/stream.cpython-312.pyc b/venv/Lib/site-packages/Tea/__pycache__/stream.cpython-312.pyc index 7bd478c..24274b9 100644 Binary files a/venv/Lib/site-packages/Tea/__pycache__/stream.cpython-312.pyc and b/venv/Lib/site-packages/Tea/__pycache__/stream.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/__pycache__/six.cpython-312.pyc b/venv/Lib/site-packages/__pycache__/six.cpython-312.pyc index 743b772..3670be1 100644 Binary files a/venv/Lib/site-packages/__pycache__/six.cpython-312.pyc and b/venv/Lib/site-packages/__pycache__/six.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/__pycache__/typing_extensions.cpython-312.pyc b/venv/Lib/site-packages/__pycache__/typing_extensions.cpython-312.pyc index da458c1..f08a2ce 100644 Binary files a/venv/Lib/site-packages/__pycache__/typing_extensions.cpython-312.pyc and b/venv/Lib/site-packages/__pycache__/typing_extensions.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/aiofiles-24.1.0.dist-info/RECORD b/venv/Lib/site-packages/aiofiles-24.1.0.dist-info/RECORD index 8467c87..7a9df6a 100644 --- a/venv/Lib/site-packages/aiofiles-24.1.0.dist-info/RECORD +++ b/venv/Lib/site-packages/aiofiles-24.1.0.dist-info/RECORD @@ -1,6 +1,7 @@ aiofiles-24.1.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 aiofiles-24.1.0.dist-info/METADATA,sha256=CvUJx21XclgI1Lp5Bt_4AyJesRYg0xCSx4exJZVmaSA,10708 aiofiles-24.1.0.dist-info/RECORD,, +aiofiles-24.1.0.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 aiofiles-24.1.0.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87 aiofiles-24.1.0.dist-info/licenses/LICENSE,sha256=y16Ofl9KOYjhBjwULGDcLfdWBfTEZRXnduOspt-XbhQ,11325 aiofiles-24.1.0.dist-info/licenses/NOTICE,sha256=EExY0dRQvWR0wJ2LZLwBgnM6YKw9jCU-M0zegpRSD_E,55 diff --git a/venv/Lib/site-packages/aiofiles-24.1.0.dist-info/REQUESTED b/venv/Lib/site-packages/aiofiles-24.1.0.dist-info/REQUESTED new file mode 100644 index 0000000..e69de29 diff --git a/venv/Lib/site-packages/aiofiles/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/aiofiles/__pycache__/__init__.cpython-312.pyc index 8c05f92..163e8b4 100644 Binary files a/venv/Lib/site-packages/aiofiles/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/aiofiles/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/aiofiles/__pycache__/base.cpython-312.pyc b/venv/Lib/site-packages/aiofiles/__pycache__/base.cpython-312.pyc index accdfc7..372eab0 100644 Binary files a/venv/Lib/site-packages/aiofiles/__pycache__/base.cpython-312.pyc and b/venv/Lib/site-packages/aiofiles/__pycache__/base.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/aiofiles/__pycache__/os.cpython-312.pyc b/venv/Lib/site-packages/aiofiles/__pycache__/os.cpython-312.pyc index f0fe011..f0a8d6e 100644 Binary files a/venv/Lib/site-packages/aiofiles/__pycache__/os.cpython-312.pyc and b/venv/Lib/site-packages/aiofiles/__pycache__/os.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/aiofiles/__pycache__/ospath.cpython-312.pyc b/venv/Lib/site-packages/aiofiles/__pycache__/ospath.cpython-312.pyc index 89fea6b..a51afdd 100644 Binary files a/venv/Lib/site-packages/aiofiles/__pycache__/ospath.cpython-312.pyc and b/venv/Lib/site-packages/aiofiles/__pycache__/ospath.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/aiofiles/tempfile/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/aiofiles/tempfile/__pycache__/__init__.cpython-312.pyc index 6881ff7..57c165a 100644 Binary files a/venv/Lib/site-packages/aiofiles/tempfile/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/aiofiles/tempfile/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/aiofiles/tempfile/__pycache__/temptypes.cpython-312.pyc b/venv/Lib/site-packages/aiofiles/tempfile/__pycache__/temptypes.cpython-312.pyc index 0565da6..4dfe80b 100644 Binary files a/venv/Lib/site-packages/aiofiles/tempfile/__pycache__/temptypes.cpython-312.pyc and b/venv/Lib/site-packages/aiofiles/tempfile/__pycache__/temptypes.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/aiofiles/threadpool/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/aiofiles/threadpool/__pycache__/__init__.cpython-312.pyc index f33b442..6ea661d 100644 Binary files a/venv/Lib/site-packages/aiofiles/threadpool/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/aiofiles/threadpool/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/aiofiles/threadpool/__pycache__/binary.cpython-312.pyc b/venv/Lib/site-packages/aiofiles/threadpool/__pycache__/binary.cpython-312.pyc index 8cce071..19d524d 100644 Binary files a/venv/Lib/site-packages/aiofiles/threadpool/__pycache__/binary.cpython-312.pyc and b/venv/Lib/site-packages/aiofiles/threadpool/__pycache__/binary.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/aiofiles/threadpool/__pycache__/text.cpython-312.pyc b/venv/Lib/site-packages/aiofiles/threadpool/__pycache__/text.cpython-312.pyc index ef31490..4d5e471 100644 Binary files a/venv/Lib/site-packages/aiofiles/threadpool/__pycache__/text.cpython-312.pyc and b/venv/Lib/site-packages/aiofiles/threadpool/__pycache__/text.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/aiofiles/threadpool/__pycache__/utils.cpython-312.pyc b/venv/Lib/site-packages/aiofiles/threadpool/__pycache__/utils.cpython-312.pyc index 3ea19a4..38e5d0b 100644 Binary files a/venv/Lib/site-packages/aiofiles/threadpool/__pycache__/utils.cpython-312.pyc and b/venv/Lib/site-packages/aiofiles/threadpool/__pycache__/utils.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/aiohappyeyeballs-2.6.1.dist-info/RECORD b/venv/Lib/site-packages/aiohappyeyeballs-2.6.1.dist-info/RECORD index 1b6cda7..615f098 100644 --- a/venv/Lib/site-packages/aiohappyeyeballs-2.6.1.dist-info/RECORD +++ b/venv/Lib/site-packages/aiohappyeyeballs-2.6.1.dist-info/RECORD @@ -2,6 +2,7 @@ aiohappyeyeballs-2.6.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQ aiohappyeyeballs-2.6.1.dist-info/LICENSE,sha256=Oy-B_iHRgcSZxZolbI4ZaEVdZonSaaqFNzv7avQdo78,13936 aiohappyeyeballs-2.6.1.dist-info/METADATA,sha256=NSXlhJwAfi380eEjAo7BQ4P_TVal9xi0qkyZWibMsVM,5915 aiohappyeyeballs-2.6.1.dist-info/RECORD,, +aiohappyeyeballs-2.6.1.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 aiohappyeyeballs-2.6.1.dist-info/WHEEL,sha256=XbeZDeTWKc1w7CSIyre5aMDU_-PohRwTQceYnisIYYY,88 aiohappyeyeballs/__init__.py,sha256=x7kktHEtaD9quBcWDJPuLeKyjuVAI-Jj14S9B_5hcTs,361 aiohappyeyeballs/__pycache__/__init__.cpython-312.pyc,, diff --git a/venv/Lib/site-packages/aiohappyeyeballs-2.6.1.dist-info/REQUESTED b/venv/Lib/site-packages/aiohappyeyeballs-2.6.1.dist-info/REQUESTED new file mode 100644 index 0000000..e69de29 diff --git a/venv/Lib/site-packages/aiohappyeyeballs/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/aiohappyeyeballs/__pycache__/__init__.cpython-312.pyc index fd49931..d6e88ff 100644 Binary files a/venv/Lib/site-packages/aiohappyeyeballs/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/aiohappyeyeballs/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/aiohappyeyeballs/__pycache__/_staggered.cpython-312.pyc b/venv/Lib/site-packages/aiohappyeyeballs/__pycache__/_staggered.cpython-312.pyc index a05d0bc..609c2fb 100644 Binary files a/venv/Lib/site-packages/aiohappyeyeballs/__pycache__/_staggered.cpython-312.pyc and b/venv/Lib/site-packages/aiohappyeyeballs/__pycache__/_staggered.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/aiohappyeyeballs/__pycache__/impl.cpython-312.pyc b/venv/Lib/site-packages/aiohappyeyeballs/__pycache__/impl.cpython-312.pyc index 468d7d0..3e4adc0 100644 Binary files a/venv/Lib/site-packages/aiohappyeyeballs/__pycache__/impl.cpython-312.pyc and b/venv/Lib/site-packages/aiohappyeyeballs/__pycache__/impl.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/aiohappyeyeballs/__pycache__/types.cpython-312.pyc b/venv/Lib/site-packages/aiohappyeyeballs/__pycache__/types.cpython-312.pyc index e418929..bcb017e 100644 Binary files a/venv/Lib/site-packages/aiohappyeyeballs/__pycache__/types.cpython-312.pyc and b/venv/Lib/site-packages/aiohappyeyeballs/__pycache__/types.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/aiohappyeyeballs/__pycache__/utils.cpython-312.pyc b/venv/Lib/site-packages/aiohappyeyeballs/__pycache__/utils.cpython-312.pyc index 4628135..160d500 100644 Binary files a/venv/Lib/site-packages/aiohappyeyeballs/__pycache__/utils.cpython-312.pyc and b/venv/Lib/site-packages/aiohappyeyeballs/__pycache__/utils.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/aiohttp-3.13.3.dist-info/RECORD b/venv/Lib/site-packages/aiohttp-3.13.3.dist-info/RECORD index 50f81fd..7fbdeaa 100644 --- a/venv/Lib/site-packages/aiohttp-3.13.3.dist-info/RECORD +++ b/venv/Lib/site-packages/aiohttp-3.13.3.dist-info/RECORD @@ -1,6 +1,7 @@ aiohttp-3.13.3.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 aiohttp-3.13.3.dist-info/METADATA,sha256=jkzui8KtHZ32gb8TfFZwIW4-zZ6Sr1eh1R6wYZW79Sg,8407 aiohttp-3.13.3.dist-info/RECORD,, +aiohttp-3.13.3.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 aiohttp-3.13.3.dist-info/WHEEL,sha256=8UP9x9puWI0P1V_d7K2oMTBqfeLNm21CTzZ_Ptr0NXU,101 aiohttp-3.13.3.dist-info/licenses/LICENSE.txt,sha256=wUk-nxDVnR-6n53ygAjhVX4zz5-6yM4SY6ozk5goA94,601 aiohttp-3.13.3.dist-info/licenses/vendor/llhttp/LICENSE,sha256=bd-mKNt20th7iWi6-61g9RxOyIEA3Xu5b5chbYivCAg,1127 diff --git a/venv/Lib/site-packages/aiohttp-3.13.3.dist-info/REQUESTED b/venv/Lib/site-packages/aiohttp-3.13.3.dist-info/REQUESTED new file mode 100644 index 0000000..e69de29 diff --git a/venv/Lib/site-packages/aiohttp/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/aiohttp/__pycache__/__init__.cpython-312.pyc index 0fa2798..0752493 100644 Binary files a/venv/Lib/site-packages/aiohttp/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/aiohttp/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/aiohttp/__pycache__/_cookie_helpers.cpython-312.pyc b/venv/Lib/site-packages/aiohttp/__pycache__/_cookie_helpers.cpython-312.pyc index 2ed1e45..2aab11b 100644 Binary files a/venv/Lib/site-packages/aiohttp/__pycache__/_cookie_helpers.cpython-312.pyc and b/venv/Lib/site-packages/aiohttp/__pycache__/_cookie_helpers.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/aiohttp/__pycache__/abc.cpython-312.pyc b/venv/Lib/site-packages/aiohttp/__pycache__/abc.cpython-312.pyc index 8e5384a..d249507 100644 Binary files a/venv/Lib/site-packages/aiohttp/__pycache__/abc.cpython-312.pyc and b/venv/Lib/site-packages/aiohttp/__pycache__/abc.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/aiohttp/__pycache__/base_protocol.cpython-312.pyc b/venv/Lib/site-packages/aiohttp/__pycache__/base_protocol.cpython-312.pyc index 76aa331..04914f9 100644 Binary files a/venv/Lib/site-packages/aiohttp/__pycache__/base_protocol.cpython-312.pyc and b/venv/Lib/site-packages/aiohttp/__pycache__/base_protocol.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/aiohttp/__pycache__/client.cpython-312.pyc b/venv/Lib/site-packages/aiohttp/__pycache__/client.cpython-312.pyc index 5c0993a..83447a0 100644 Binary files a/venv/Lib/site-packages/aiohttp/__pycache__/client.cpython-312.pyc and b/venv/Lib/site-packages/aiohttp/__pycache__/client.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/aiohttp/__pycache__/client_exceptions.cpython-312.pyc b/venv/Lib/site-packages/aiohttp/__pycache__/client_exceptions.cpython-312.pyc index 01ba545..d69527b 100644 Binary files a/venv/Lib/site-packages/aiohttp/__pycache__/client_exceptions.cpython-312.pyc and b/venv/Lib/site-packages/aiohttp/__pycache__/client_exceptions.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/aiohttp/__pycache__/client_middleware_digest_auth.cpython-312.pyc b/venv/Lib/site-packages/aiohttp/__pycache__/client_middleware_digest_auth.cpython-312.pyc index 473b293..65e8758 100644 Binary files a/venv/Lib/site-packages/aiohttp/__pycache__/client_middleware_digest_auth.cpython-312.pyc and b/venv/Lib/site-packages/aiohttp/__pycache__/client_middleware_digest_auth.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/aiohttp/__pycache__/client_middlewares.cpython-312.pyc b/venv/Lib/site-packages/aiohttp/__pycache__/client_middlewares.cpython-312.pyc index d72c414..6c04017 100644 Binary files a/venv/Lib/site-packages/aiohttp/__pycache__/client_middlewares.cpython-312.pyc and b/venv/Lib/site-packages/aiohttp/__pycache__/client_middlewares.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/aiohttp/__pycache__/client_proto.cpython-312.pyc b/venv/Lib/site-packages/aiohttp/__pycache__/client_proto.cpython-312.pyc index fb1d747..b4d3405 100644 Binary files a/venv/Lib/site-packages/aiohttp/__pycache__/client_proto.cpython-312.pyc and b/venv/Lib/site-packages/aiohttp/__pycache__/client_proto.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/aiohttp/__pycache__/client_reqrep.cpython-312.pyc b/venv/Lib/site-packages/aiohttp/__pycache__/client_reqrep.cpython-312.pyc index c0a691b..13ecfc5 100644 Binary files a/venv/Lib/site-packages/aiohttp/__pycache__/client_reqrep.cpython-312.pyc and b/venv/Lib/site-packages/aiohttp/__pycache__/client_reqrep.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/aiohttp/__pycache__/client_ws.cpython-312.pyc b/venv/Lib/site-packages/aiohttp/__pycache__/client_ws.cpython-312.pyc index c30ef27..b56864b 100644 Binary files a/venv/Lib/site-packages/aiohttp/__pycache__/client_ws.cpython-312.pyc and b/venv/Lib/site-packages/aiohttp/__pycache__/client_ws.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/aiohttp/__pycache__/compression_utils.cpython-312.pyc b/venv/Lib/site-packages/aiohttp/__pycache__/compression_utils.cpython-312.pyc index c5e7c51..195d08c 100644 Binary files a/venv/Lib/site-packages/aiohttp/__pycache__/compression_utils.cpython-312.pyc and b/venv/Lib/site-packages/aiohttp/__pycache__/compression_utils.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/aiohttp/__pycache__/connector.cpython-312.pyc b/venv/Lib/site-packages/aiohttp/__pycache__/connector.cpython-312.pyc index 6578d91..1d35f4d 100644 Binary files a/venv/Lib/site-packages/aiohttp/__pycache__/connector.cpython-312.pyc and b/venv/Lib/site-packages/aiohttp/__pycache__/connector.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/aiohttp/__pycache__/cookiejar.cpython-312.pyc b/venv/Lib/site-packages/aiohttp/__pycache__/cookiejar.cpython-312.pyc index cbc65f5..c5ae1ec 100644 Binary files a/venv/Lib/site-packages/aiohttp/__pycache__/cookiejar.cpython-312.pyc and b/venv/Lib/site-packages/aiohttp/__pycache__/cookiejar.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/aiohttp/__pycache__/formdata.cpython-312.pyc b/venv/Lib/site-packages/aiohttp/__pycache__/formdata.cpython-312.pyc index cf5304c..0ba37d1 100644 Binary files a/venv/Lib/site-packages/aiohttp/__pycache__/formdata.cpython-312.pyc and b/venv/Lib/site-packages/aiohttp/__pycache__/formdata.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/aiohttp/__pycache__/hdrs.cpython-312.pyc b/venv/Lib/site-packages/aiohttp/__pycache__/hdrs.cpython-312.pyc index 00b4690..5ad0bfc 100644 Binary files a/venv/Lib/site-packages/aiohttp/__pycache__/hdrs.cpython-312.pyc and b/venv/Lib/site-packages/aiohttp/__pycache__/hdrs.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/aiohttp/__pycache__/helpers.cpython-312.pyc b/venv/Lib/site-packages/aiohttp/__pycache__/helpers.cpython-312.pyc index 02ecb4f..0cb9234 100644 Binary files a/venv/Lib/site-packages/aiohttp/__pycache__/helpers.cpython-312.pyc and b/venv/Lib/site-packages/aiohttp/__pycache__/helpers.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/aiohttp/__pycache__/http.cpython-312.pyc b/venv/Lib/site-packages/aiohttp/__pycache__/http.cpython-312.pyc index 04ef807..23aee28 100644 Binary files a/venv/Lib/site-packages/aiohttp/__pycache__/http.cpython-312.pyc and b/venv/Lib/site-packages/aiohttp/__pycache__/http.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/aiohttp/__pycache__/http_exceptions.cpython-312.pyc b/venv/Lib/site-packages/aiohttp/__pycache__/http_exceptions.cpython-312.pyc index e273efe..9d8a3ad 100644 Binary files a/venv/Lib/site-packages/aiohttp/__pycache__/http_exceptions.cpython-312.pyc and b/venv/Lib/site-packages/aiohttp/__pycache__/http_exceptions.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/aiohttp/__pycache__/http_parser.cpython-312.pyc b/venv/Lib/site-packages/aiohttp/__pycache__/http_parser.cpython-312.pyc index 0a7fd95..27a89c8 100644 Binary files a/venv/Lib/site-packages/aiohttp/__pycache__/http_parser.cpython-312.pyc and b/venv/Lib/site-packages/aiohttp/__pycache__/http_parser.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/aiohttp/__pycache__/http_websocket.cpython-312.pyc b/venv/Lib/site-packages/aiohttp/__pycache__/http_websocket.cpython-312.pyc index e6af21a..e106648 100644 Binary files a/venv/Lib/site-packages/aiohttp/__pycache__/http_websocket.cpython-312.pyc and b/venv/Lib/site-packages/aiohttp/__pycache__/http_websocket.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/aiohttp/__pycache__/http_writer.cpython-312.pyc b/venv/Lib/site-packages/aiohttp/__pycache__/http_writer.cpython-312.pyc index 4364ed0..8b95a0d 100644 Binary files a/venv/Lib/site-packages/aiohttp/__pycache__/http_writer.cpython-312.pyc and b/venv/Lib/site-packages/aiohttp/__pycache__/http_writer.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/aiohttp/__pycache__/log.cpython-312.pyc b/venv/Lib/site-packages/aiohttp/__pycache__/log.cpython-312.pyc index 379c75e..2506bf7 100644 Binary files a/venv/Lib/site-packages/aiohttp/__pycache__/log.cpython-312.pyc and b/venv/Lib/site-packages/aiohttp/__pycache__/log.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/aiohttp/__pycache__/multipart.cpython-312.pyc b/venv/Lib/site-packages/aiohttp/__pycache__/multipart.cpython-312.pyc index d37f7a9..d0289d1 100644 Binary files a/venv/Lib/site-packages/aiohttp/__pycache__/multipart.cpython-312.pyc and b/venv/Lib/site-packages/aiohttp/__pycache__/multipart.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/aiohttp/__pycache__/payload.cpython-312.pyc b/venv/Lib/site-packages/aiohttp/__pycache__/payload.cpython-312.pyc index b975fee..31d8e78 100644 Binary files a/venv/Lib/site-packages/aiohttp/__pycache__/payload.cpython-312.pyc and b/venv/Lib/site-packages/aiohttp/__pycache__/payload.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/aiohttp/__pycache__/payload_streamer.cpython-312.pyc b/venv/Lib/site-packages/aiohttp/__pycache__/payload_streamer.cpython-312.pyc index 7e4b275..a2f04c9 100644 Binary files a/venv/Lib/site-packages/aiohttp/__pycache__/payload_streamer.cpython-312.pyc and b/venv/Lib/site-packages/aiohttp/__pycache__/payload_streamer.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/aiohttp/__pycache__/pytest_plugin.cpython-312.pyc b/venv/Lib/site-packages/aiohttp/__pycache__/pytest_plugin.cpython-312.pyc index 5373b4c..c4272da 100644 Binary files a/venv/Lib/site-packages/aiohttp/__pycache__/pytest_plugin.cpython-312.pyc and b/venv/Lib/site-packages/aiohttp/__pycache__/pytest_plugin.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/aiohttp/__pycache__/resolver.cpython-312.pyc b/venv/Lib/site-packages/aiohttp/__pycache__/resolver.cpython-312.pyc index c46d260..c671888 100644 Binary files a/venv/Lib/site-packages/aiohttp/__pycache__/resolver.cpython-312.pyc and b/venv/Lib/site-packages/aiohttp/__pycache__/resolver.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/aiohttp/__pycache__/streams.cpython-312.pyc b/venv/Lib/site-packages/aiohttp/__pycache__/streams.cpython-312.pyc index d474521..f472f69 100644 Binary files a/venv/Lib/site-packages/aiohttp/__pycache__/streams.cpython-312.pyc and b/venv/Lib/site-packages/aiohttp/__pycache__/streams.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/aiohttp/__pycache__/tcp_helpers.cpython-312.pyc b/venv/Lib/site-packages/aiohttp/__pycache__/tcp_helpers.cpython-312.pyc index 116b1a1..83b09d8 100644 Binary files a/venv/Lib/site-packages/aiohttp/__pycache__/tcp_helpers.cpython-312.pyc and b/venv/Lib/site-packages/aiohttp/__pycache__/tcp_helpers.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/aiohttp/__pycache__/test_utils.cpython-312.pyc b/venv/Lib/site-packages/aiohttp/__pycache__/test_utils.cpython-312.pyc index 1c7259e..9b3b521 100644 Binary files a/venv/Lib/site-packages/aiohttp/__pycache__/test_utils.cpython-312.pyc and b/venv/Lib/site-packages/aiohttp/__pycache__/test_utils.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/aiohttp/__pycache__/tracing.cpython-312.pyc b/venv/Lib/site-packages/aiohttp/__pycache__/tracing.cpython-312.pyc index 3a50da6..19c35cb 100644 Binary files a/venv/Lib/site-packages/aiohttp/__pycache__/tracing.cpython-312.pyc and b/venv/Lib/site-packages/aiohttp/__pycache__/tracing.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/aiohttp/__pycache__/typedefs.cpython-312.pyc b/venv/Lib/site-packages/aiohttp/__pycache__/typedefs.cpython-312.pyc index 85da732..351a19a 100644 Binary files a/venv/Lib/site-packages/aiohttp/__pycache__/typedefs.cpython-312.pyc and b/venv/Lib/site-packages/aiohttp/__pycache__/typedefs.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/aiohttp/__pycache__/web.cpython-312.pyc b/venv/Lib/site-packages/aiohttp/__pycache__/web.cpython-312.pyc index 8fc685e..b02bc2d 100644 Binary files a/venv/Lib/site-packages/aiohttp/__pycache__/web.cpython-312.pyc and b/venv/Lib/site-packages/aiohttp/__pycache__/web.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/aiohttp/__pycache__/web_app.cpython-312.pyc b/venv/Lib/site-packages/aiohttp/__pycache__/web_app.cpython-312.pyc index 7758b33..4d6c2cb 100644 Binary files a/venv/Lib/site-packages/aiohttp/__pycache__/web_app.cpython-312.pyc and b/venv/Lib/site-packages/aiohttp/__pycache__/web_app.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/aiohttp/__pycache__/web_exceptions.cpython-312.pyc b/venv/Lib/site-packages/aiohttp/__pycache__/web_exceptions.cpython-312.pyc index 37eeee6..9730898 100644 Binary files a/venv/Lib/site-packages/aiohttp/__pycache__/web_exceptions.cpython-312.pyc and b/venv/Lib/site-packages/aiohttp/__pycache__/web_exceptions.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/aiohttp/__pycache__/web_fileresponse.cpython-312.pyc b/venv/Lib/site-packages/aiohttp/__pycache__/web_fileresponse.cpython-312.pyc index 841badd..1cd57ca 100644 Binary files a/venv/Lib/site-packages/aiohttp/__pycache__/web_fileresponse.cpython-312.pyc and b/venv/Lib/site-packages/aiohttp/__pycache__/web_fileresponse.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/aiohttp/__pycache__/web_log.cpython-312.pyc b/venv/Lib/site-packages/aiohttp/__pycache__/web_log.cpython-312.pyc index b58102a..2fc91ca 100644 Binary files a/venv/Lib/site-packages/aiohttp/__pycache__/web_log.cpython-312.pyc and b/venv/Lib/site-packages/aiohttp/__pycache__/web_log.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/aiohttp/__pycache__/web_middlewares.cpython-312.pyc b/venv/Lib/site-packages/aiohttp/__pycache__/web_middlewares.cpython-312.pyc index e5ecfd0..0f17f7e 100644 Binary files a/venv/Lib/site-packages/aiohttp/__pycache__/web_middlewares.cpython-312.pyc and b/venv/Lib/site-packages/aiohttp/__pycache__/web_middlewares.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/aiohttp/__pycache__/web_protocol.cpython-312.pyc b/venv/Lib/site-packages/aiohttp/__pycache__/web_protocol.cpython-312.pyc index f149d8b..0e9dd6f 100644 Binary files a/venv/Lib/site-packages/aiohttp/__pycache__/web_protocol.cpython-312.pyc and b/venv/Lib/site-packages/aiohttp/__pycache__/web_protocol.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/aiohttp/__pycache__/web_request.cpython-312.pyc b/venv/Lib/site-packages/aiohttp/__pycache__/web_request.cpython-312.pyc index 1afa2fb..7da5ad9 100644 Binary files a/venv/Lib/site-packages/aiohttp/__pycache__/web_request.cpython-312.pyc and b/venv/Lib/site-packages/aiohttp/__pycache__/web_request.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/aiohttp/__pycache__/web_response.cpython-312.pyc b/venv/Lib/site-packages/aiohttp/__pycache__/web_response.cpython-312.pyc index fa8f73d..6476e95 100644 Binary files a/venv/Lib/site-packages/aiohttp/__pycache__/web_response.cpython-312.pyc and b/venv/Lib/site-packages/aiohttp/__pycache__/web_response.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/aiohttp/__pycache__/web_routedef.cpython-312.pyc b/venv/Lib/site-packages/aiohttp/__pycache__/web_routedef.cpython-312.pyc index aea1663..ee2425a 100644 Binary files a/venv/Lib/site-packages/aiohttp/__pycache__/web_routedef.cpython-312.pyc and b/venv/Lib/site-packages/aiohttp/__pycache__/web_routedef.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/aiohttp/__pycache__/web_runner.cpython-312.pyc b/venv/Lib/site-packages/aiohttp/__pycache__/web_runner.cpython-312.pyc index 2eed9bf..725579d 100644 Binary files a/venv/Lib/site-packages/aiohttp/__pycache__/web_runner.cpython-312.pyc and b/venv/Lib/site-packages/aiohttp/__pycache__/web_runner.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/aiohttp/__pycache__/web_server.cpython-312.pyc b/venv/Lib/site-packages/aiohttp/__pycache__/web_server.cpython-312.pyc index 88d883d..d2a1d79 100644 Binary files a/venv/Lib/site-packages/aiohttp/__pycache__/web_server.cpython-312.pyc and b/venv/Lib/site-packages/aiohttp/__pycache__/web_server.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/aiohttp/__pycache__/web_urldispatcher.cpython-312.pyc b/venv/Lib/site-packages/aiohttp/__pycache__/web_urldispatcher.cpython-312.pyc index bd27b25..219630e 100644 Binary files a/venv/Lib/site-packages/aiohttp/__pycache__/web_urldispatcher.cpython-312.pyc and b/venv/Lib/site-packages/aiohttp/__pycache__/web_urldispatcher.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/aiohttp/__pycache__/web_ws.cpython-312.pyc b/venv/Lib/site-packages/aiohttp/__pycache__/web_ws.cpython-312.pyc index 3895362..661e03f 100644 Binary files a/venv/Lib/site-packages/aiohttp/__pycache__/web_ws.cpython-312.pyc and b/venv/Lib/site-packages/aiohttp/__pycache__/web_ws.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/aiohttp/__pycache__/worker.cpython-312.pyc b/venv/Lib/site-packages/aiohttp/__pycache__/worker.cpython-312.pyc index fd7a4c5..646c07f 100644 Binary files a/venv/Lib/site-packages/aiohttp/__pycache__/worker.cpython-312.pyc and b/venv/Lib/site-packages/aiohttp/__pycache__/worker.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/aiohttp/_websocket/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/aiohttp/_websocket/__pycache__/__init__.cpython-312.pyc index ee7c27b..fdf5548 100644 Binary files a/venv/Lib/site-packages/aiohttp/_websocket/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/aiohttp/_websocket/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/aiohttp/_websocket/__pycache__/helpers.cpython-312.pyc b/venv/Lib/site-packages/aiohttp/_websocket/__pycache__/helpers.cpython-312.pyc index fa897cc..9e47f18 100644 Binary files a/venv/Lib/site-packages/aiohttp/_websocket/__pycache__/helpers.cpython-312.pyc and b/venv/Lib/site-packages/aiohttp/_websocket/__pycache__/helpers.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/aiohttp/_websocket/__pycache__/models.cpython-312.pyc b/venv/Lib/site-packages/aiohttp/_websocket/__pycache__/models.cpython-312.pyc index b7965d4..c152be1 100644 Binary files a/venv/Lib/site-packages/aiohttp/_websocket/__pycache__/models.cpython-312.pyc and b/venv/Lib/site-packages/aiohttp/_websocket/__pycache__/models.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/aiohttp/_websocket/__pycache__/reader.cpython-312.pyc b/venv/Lib/site-packages/aiohttp/_websocket/__pycache__/reader.cpython-312.pyc index a4165dc..69ca22c 100644 Binary files a/venv/Lib/site-packages/aiohttp/_websocket/__pycache__/reader.cpython-312.pyc and b/venv/Lib/site-packages/aiohttp/_websocket/__pycache__/reader.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/aiohttp/_websocket/__pycache__/reader_c.cpython-312.pyc b/venv/Lib/site-packages/aiohttp/_websocket/__pycache__/reader_c.cpython-312.pyc index 0a205ca..6d8f678 100644 Binary files a/venv/Lib/site-packages/aiohttp/_websocket/__pycache__/reader_c.cpython-312.pyc and b/venv/Lib/site-packages/aiohttp/_websocket/__pycache__/reader_c.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/aiohttp/_websocket/__pycache__/reader_py.cpython-312.pyc b/venv/Lib/site-packages/aiohttp/_websocket/__pycache__/reader_py.cpython-312.pyc index 4f2a9e1..602a52f 100644 Binary files a/venv/Lib/site-packages/aiohttp/_websocket/__pycache__/reader_py.cpython-312.pyc and b/venv/Lib/site-packages/aiohttp/_websocket/__pycache__/reader_py.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/aiohttp/_websocket/__pycache__/writer.cpython-312.pyc b/venv/Lib/site-packages/aiohttp/_websocket/__pycache__/writer.cpython-312.pyc index e531649..06c576c 100644 Binary files a/venv/Lib/site-packages/aiohttp/_websocket/__pycache__/writer.cpython-312.pyc and b/venv/Lib/site-packages/aiohttp/_websocket/__pycache__/writer.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/aiosignal-1.4.0.dist-info/RECORD b/venv/Lib/site-packages/aiosignal-1.4.0.dist-info/RECORD index 11bc848..30b91c3 100644 --- a/venv/Lib/site-packages/aiosignal-1.4.0.dist-info/RECORD +++ b/venv/Lib/site-packages/aiosignal-1.4.0.dist-info/RECORD @@ -1,6 +1,7 @@ aiosignal-1.4.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 aiosignal-1.4.0.dist-info/METADATA,sha256=CSR-8dqLxpZyjUcTDnAuQwf299EB1sSFv_nzpxznAI0,3662 aiosignal-1.4.0.dist-info/RECORD,, +aiosignal-1.4.0.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 aiosignal-1.4.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91 aiosignal-1.4.0.dist-info/licenses/LICENSE,sha256=b9UkPpLdf5jsacesN3co50kFcJ_1J6W_mNbQJjwE9bY,11332 aiosignal-1.4.0.dist-info/top_level.txt,sha256=z45aNOKGDdrI1roqZY3BGXQ22kJFPHBmVdwtLYLtXC0,10 diff --git a/venv/Lib/site-packages/aiosignal-1.4.0.dist-info/REQUESTED b/venv/Lib/site-packages/aiosignal-1.4.0.dist-info/REQUESTED new file mode 100644 index 0000000..e69de29 diff --git a/venv/Lib/site-packages/aiosignal/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/aiosignal/__pycache__/__init__.cpython-312.pyc index ac4f65c..bbaf146 100644 Binary files a/venv/Lib/site-packages/aiosignal/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/aiosignal/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/alibabacloud_credentials-1.0.4.dist-info/RECORD b/venv/Lib/site-packages/alibabacloud_credentials-1.0.4.dist-info/RECORD index 1f244c5..d3ddeb2 100644 --- a/venv/Lib/site-packages/alibabacloud_credentials-1.0.4.dist-info/RECORD +++ b/venv/Lib/site-packages/alibabacloud_credentials-1.0.4.dist-info/RECORD @@ -1,6 +1,7 @@ alibabacloud_credentials-1.0.4.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 alibabacloud_credentials-1.0.4.dist-info/METADATA,sha256=z9Cv9ARvWZ7frwNNoTdHs1VIQ-QEk5zSGgAAbcAX5Lg,29119 alibabacloud_credentials-1.0.4.dist-info/RECORD,, +alibabacloud_credentials-1.0.4.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 alibabacloud_credentials-1.0.4.dist-info/WHEEL,sha256=2wepM1nk4DS4eFpYrW1TTqPcoGNfHhhO_i5m4cOimbo,92 alibabacloud_credentials-1.0.4.dist-info/top_level.txt,sha256=qFzgPK-RjwJQIKjXEWcs5M8gtikqSgnJJB8uhoRMTfE,25 alibabacloud_credentials/__init__.py,sha256=kwEyWwKLIIqYSnkf5eXgPtRgw9Bz51riSupwtvDpJMA,23 diff --git a/venv/Lib/site-packages/alibabacloud_credentials-1.0.4.dist-info/REQUESTED b/venv/Lib/site-packages/alibabacloud_credentials-1.0.4.dist-info/REQUESTED new file mode 100644 index 0000000..e69de29 diff --git a/venv/Lib/site-packages/alibabacloud_credentials/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/alibabacloud_credentials/__pycache__/__init__.cpython-312.pyc index c7d7b6f..fc9bc24 100644 Binary files a/venv/Lib/site-packages/alibabacloud_credentials/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/alibabacloud_credentials/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/alibabacloud_credentials/__pycache__/client.cpython-312.pyc b/venv/Lib/site-packages/alibabacloud_credentials/__pycache__/client.cpython-312.pyc index c38745e..b3d5d69 100644 Binary files a/venv/Lib/site-packages/alibabacloud_credentials/__pycache__/client.cpython-312.pyc and b/venv/Lib/site-packages/alibabacloud_credentials/__pycache__/client.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/alibabacloud_credentials/__pycache__/credentials.cpython-312.pyc b/venv/Lib/site-packages/alibabacloud_credentials/__pycache__/credentials.cpython-312.pyc index 1c9b531..d2f776e 100644 Binary files a/venv/Lib/site-packages/alibabacloud_credentials/__pycache__/credentials.cpython-312.pyc and b/venv/Lib/site-packages/alibabacloud_credentials/__pycache__/credentials.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/alibabacloud_credentials/__pycache__/exceptions.cpython-312.pyc b/venv/Lib/site-packages/alibabacloud_credentials/__pycache__/exceptions.cpython-312.pyc index fb02ddb..9b29912 100644 Binary files a/venv/Lib/site-packages/alibabacloud_credentials/__pycache__/exceptions.cpython-312.pyc and b/venv/Lib/site-packages/alibabacloud_credentials/__pycache__/exceptions.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/alibabacloud_credentials/__pycache__/models.cpython-312.pyc b/venv/Lib/site-packages/alibabacloud_credentials/__pycache__/models.cpython-312.pyc index a65759e..b10a8cb 100644 Binary files a/venv/Lib/site-packages/alibabacloud_credentials/__pycache__/models.cpython-312.pyc and b/venv/Lib/site-packages/alibabacloud_credentials/__pycache__/models.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/alibabacloud_credentials/__pycache__/providers.cpython-312.pyc b/venv/Lib/site-packages/alibabacloud_credentials/__pycache__/providers.cpython-312.pyc index de2c30e..851ca4b 100644 Binary files a/venv/Lib/site-packages/alibabacloud_credentials/__pycache__/providers.cpython-312.pyc and b/venv/Lib/site-packages/alibabacloud_credentials/__pycache__/providers.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/alibabacloud_credentials/http/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/alibabacloud_credentials/http/__pycache__/__init__.cpython-312.pyc index 6a4ee09..fcf9156 100644 Binary files a/venv/Lib/site-packages/alibabacloud_credentials/http/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/alibabacloud_credentials/http/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/alibabacloud_credentials/http/__pycache__/_options.cpython-312.pyc b/venv/Lib/site-packages/alibabacloud_credentials/http/__pycache__/_options.cpython-312.pyc index 5724c0a..d0d9c26 100644 Binary files a/venv/Lib/site-packages/alibabacloud_credentials/http/__pycache__/_options.cpython-312.pyc and b/venv/Lib/site-packages/alibabacloud_credentials/http/__pycache__/_options.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/alibabacloud_credentials/provider/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/alibabacloud_credentials/provider/__pycache__/__init__.cpython-312.pyc index 5036cdd..c17eaa9 100644 Binary files a/venv/Lib/site-packages/alibabacloud_credentials/provider/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/alibabacloud_credentials/provider/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/alibabacloud_credentials/provider/__pycache__/cli_profile.cpython-312.pyc b/venv/Lib/site-packages/alibabacloud_credentials/provider/__pycache__/cli_profile.cpython-312.pyc index 7cf1e01..b516d87 100644 Binary files a/venv/Lib/site-packages/alibabacloud_credentials/provider/__pycache__/cli_profile.cpython-312.pyc and b/venv/Lib/site-packages/alibabacloud_credentials/provider/__pycache__/cli_profile.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/alibabacloud_credentials/provider/__pycache__/cloud_sso.cpython-312.pyc b/venv/Lib/site-packages/alibabacloud_credentials/provider/__pycache__/cloud_sso.cpython-312.pyc index 78ac6a0..3b7b56a 100644 Binary files a/venv/Lib/site-packages/alibabacloud_credentials/provider/__pycache__/cloud_sso.cpython-312.pyc and b/venv/Lib/site-packages/alibabacloud_credentials/provider/__pycache__/cloud_sso.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/alibabacloud_credentials/provider/__pycache__/default.cpython-312.pyc b/venv/Lib/site-packages/alibabacloud_credentials/provider/__pycache__/default.cpython-312.pyc index 1f7da87..0f5bd9a 100644 Binary files a/venv/Lib/site-packages/alibabacloud_credentials/provider/__pycache__/default.cpython-312.pyc and b/venv/Lib/site-packages/alibabacloud_credentials/provider/__pycache__/default.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/alibabacloud_credentials/provider/__pycache__/ecs_ram_role.cpython-312.pyc b/venv/Lib/site-packages/alibabacloud_credentials/provider/__pycache__/ecs_ram_role.cpython-312.pyc index 4a72602..280b612 100644 Binary files a/venv/Lib/site-packages/alibabacloud_credentials/provider/__pycache__/ecs_ram_role.cpython-312.pyc and b/venv/Lib/site-packages/alibabacloud_credentials/provider/__pycache__/ecs_ram_role.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/alibabacloud_credentials/provider/__pycache__/env.cpython-312.pyc b/venv/Lib/site-packages/alibabacloud_credentials/provider/__pycache__/env.cpython-312.pyc index d2489d0..c968be0 100644 Binary files a/venv/Lib/site-packages/alibabacloud_credentials/provider/__pycache__/env.cpython-312.pyc and b/venv/Lib/site-packages/alibabacloud_credentials/provider/__pycache__/env.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/alibabacloud_credentials/provider/__pycache__/oauth.cpython-312.pyc b/venv/Lib/site-packages/alibabacloud_credentials/provider/__pycache__/oauth.cpython-312.pyc index e725e06..08bd32b 100644 Binary files a/venv/Lib/site-packages/alibabacloud_credentials/provider/__pycache__/oauth.cpython-312.pyc and b/venv/Lib/site-packages/alibabacloud_credentials/provider/__pycache__/oauth.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/alibabacloud_credentials/provider/__pycache__/oidc.cpython-312.pyc b/venv/Lib/site-packages/alibabacloud_credentials/provider/__pycache__/oidc.cpython-312.pyc index 7de2826..47239f9 100644 Binary files a/venv/Lib/site-packages/alibabacloud_credentials/provider/__pycache__/oidc.cpython-312.pyc and b/venv/Lib/site-packages/alibabacloud_credentials/provider/__pycache__/oidc.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/alibabacloud_credentials/provider/__pycache__/profile.cpython-312.pyc b/venv/Lib/site-packages/alibabacloud_credentials/provider/__pycache__/profile.cpython-312.pyc index c83a496..b26fb08 100644 Binary files a/venv/Lib/site-packages/alibabacloud_credentials/provider/__pycache__/profile.cpython-312.pyc and b/venv/Lib/site-packages/alibabacloud_credentials/provider/__pycache__/profile.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/alibabacloud_credentials/provider/__pycache__/ram_role_arn.cpython-312.pyc b/venv/Lib/site-packages/alibabacloud_credentials/provider/__pycache__/ram_role_arn.cpython-312.pyc index 2943734..d1b19f7 100644 Binary files a/venv/Lib/site-packages/alibabacloud_credentials/provider/__pycache__/ram_role_arn.cpython-312.pyc and b/venv/Lib/site-packages/alibabacloud_credentials/provider/__pycache__/ram_role_arn.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/alibabacloud_credentials/provider/__pycache__/refreshable.cpython-312.pyc b/venv/Lib/site-packages/alibabacloud_credentials/provider/__pycache__/refreshable.cpython-312.pyc index 98f9a39..3a31dc3 100644 Binary files a/venv/Lib/site-packages/alibabacloud_credentials/provider/__pycache__/refreshable.cpython-312.pyc and b/venv/Lib/site-packages/alibabacloud_credentials/provider/__pycache__/refreshable.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/alibabacloud_credentials/provider/__pycache__/rsa_key_pair.cpython-312.pyc b/venv/Lib/site-packages/alibabacloud_credentials/provider/__pycache__/rsa_key_pair.cpython-312.pyc index ac08e40..214748e 100644 Binary files a/venv/Lib/site-packages/alibabacloud_credentials/provider/__pycache__/rsa_key_pair.cpython-312.pyc and b/venv/Lib/site-packages/alibabacloud_credentials/provider/__pycache__/rsa_key_pair.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/alibabacloud_credentials/provider/__pycache__/static_ak.cpython-312.pyc b/venv/Lib/site-packages/alibabacloud_credentials/provider/__pycache__/static_ak.cpython-312.pyc index 381160c..548936c 100644 Binary files a/venv/Lib/site-packages/alibabacloud_credentials/provider/__pycache__/static_ak.cpython-312.pyc and b/venv/Lib/site-packages/alibabacloud_credentials/provider/__pycache__/static_ak.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/alibabacloud_credentials/provider/__pycache__/static_sts.cpython-312.pyc b/venv/Lib/site-packages/alibabacloud_credentials/provider/__pycache__/static_sts.cpython-312.pyc index bbd7f51..2e6c07a 100644 Binary files a/venv/Lib/site-packages/alibabacloud_credentials/provider/__pycache__/static_sts.cpython-312.pyc and b/venv/Lib/site-packages/alibabacloud_credentials/provider/__pycache__/static_sts.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/alibabacloud_credentials/provider/__pycache__/uri.cpython-312.pyc b/venv/Lib/site-packages/alibabacloud_credentials/provider/__pycache__/uri.cpython-312.pyc index 6f24640..ce3d842 100644 Binary files a/venv/Lib/site-packages/alibabacloud_credentials/provider/__pycache__/uri.cpython-312.pyc and b/venv/Lib/site-packages/alibabacloud_credentials/provider/__pycache__/uri.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/alibabacloud_credentials/utils/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/alibabacloud_credentials/utils/__pycache__/__init__.cpython-312.pyc index 17c8eba..33dfdcc 100644 Binary files a/venv/Lib/site-packages/alibabacloud_credentials/utils/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/alibabacloud_credentials/utils/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/alibabacloud_credentials/utils/__pycache__/auth_constant.cpython-312.pyc b/venv/Lib/site-packages/alibabacloud_credentials/utils/__pycache__/auth_constant.cpython-312.pyc index 99ec463..d830efd 100644 Binary files a/venv/Lib/site-packages/alibabacloud_credentials/utils/__pycache__/auth_constant.cpython-312.pyc and b/venv/Lib/site-packages/alibabacloud_credentials/utils/__pycache__/auth_constant.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/alibabacloud_credentials/utils/__pycache__/auth_util.cpython-312.pyc b/venv/Lib/site-packages/alibabacloud_credentials/utils/__pycache__/auth_util.cpython-312.pyc index 2b7bce0..29b1282 100644 Binary files a/venv/Lib/site-packages/alibabacloud_credentials/utils/__pycache__/auth_util.cpython-312.pyc and b/venv/Lib/site-packages/alibabacloud_credentials/utils/__pycache__/auth_util.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/alibabacloud_credentials/utils/__pycache__/parameter_helper.cpython-312.pyc b/venv/Lib/site-packages/alibabacloud_credentials/utils/__pycache__/parameter_helper.cpython-312.pyc index ed425e8..9b15bf9 100644 Binary files a/venv/Lib/site-packages/alibabacloud_credentials/utils/__pycache__/parameter_helper.cpython-312.pyc and b/venv/Lib/site-packages/alibabacloud_credentials/utils/__pycache__/parameter_helper.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/alibabacloud_credentials_api-1.0.0.dist-info/RECORD b/venv/Lib/site-packages/alibabacloud_credentials_api-1.0.0.dist-info/RECORD index 60b3b2b..f0efdc3 100644 --- a/venv/Lib/site-packages/alibabacloud_credentials_api-1.0.0.dist-info/RECORD +++ b/venv/Lib/site-packages/alibabacloud_credentials_api-1.0.0.dist-info/RECORD @@ -1,6 +1,7 @@ alibabacloud_credentials_api-1.0.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 alibabacloud_credentials_api-1.0.0.dist-info/METADATA,sha256=aSfvACGsABp4euDCwTHARD8tSRzJqF2zs76TVwv2g34,1224 alibabacloud_credentials_api-1.0.0.dist-info/RECORD,, +alibabacloud_credentials_api-1.0.0.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 alibabacloud_credentials_api-1.0.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91 alibabacloud_credentials_api-1.0.0.dist-info/top_level.txt,sha256=dIv-StdUW0heWk7dXongOwOf0pfJobK5uFhkNl5D9AQ,29 alibabacloud_credentials_api/__init__.py,sha256=lB4fbOMNpXj08gB_nt5NLijbjYlWmGRTFsk1OKPVF5M,140 diff --git a/venv/Lib/site-packages/alibabacloud_credentials_api-1.0.0.dist-info/REQUESTED b/venv/Lib/site-packages/alibabacloud_credentials_api-1.0.0.dist-info/REQUESTED new file mode 100644 index 0000000..e69de29 diff --git a/venv/Lib/site-packages/alibabacloud_credentials_api/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/alibabacloud_credentials_api/__pycache__/__init__.cpython-312.pyc index 705cca8..56b9155 100644 Binary files a/venv/Lib/site-packages/alibabacloud_credentials_api/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/alibabacloud_credentials_api/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/alibabacloud_credentials_api/__pycache__/models.cpython-312.pyc b/venv/Lib/site-packages/alibabacloud_credentials_api/__pycache__/models.cpython-312.pyc index 3c026be..355287e 100644 Binary files a/venv/Lib/site-packages/alibabacloud_credentials_api/__pycache__/models.cpython-312.pyc and b/venv/Lib/site-packages/alibabacloud_credentials_api/__pycache__/models.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/alibabacloud_dypnsapi20170525/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/alibabacloud_dypnsapi20170525/__pycache__/__init__.cpython-312.pyc index 057be75..e9169dc 100644 Binary files a/venv/Lib/site-packages/alibabacloud_dypnsapi20170525/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/alibabacloud_dypnsapi20170525/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/alibabacloud_dypnsapi20170525/__pycache__/client.cpython-312.pyc b/venv/Lib/site-packages/alibabacloud_dypnsapi20170525/__pycache__/client.cpython-312.pyc index 23fed78..e2601ab 100644 Binary files a/venv/Lib/site-packages/alibabacloud_dypnsapi20170525/__pycache__/client.cpython-312.pyc and b/venv/Lib/site-packages/alibabacloud_dypnsapi20170525/__pycache__/client.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/alibabacloud_dypnsapi20170525/__pycache__/models.cpython-312.pyc b/venv/Lib/site-packages/alibabacloud_dypnsapi20170525/__pycache__/models.cpython-312.pyc index 3681895..91b0f7c 100644 Binary files a/venv/Lib/site-packages/alibabacloud_dypnsapi20170525/__pycache__/models.cpython-312.pyc and b/venv/Lib/site-packages/alibabacloud_dypnsapi20170525/__pycache__/models.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/alibabacloud_endpoint_util-0.0.4.dist-info/RECORD b/venv/Lib/site-packages/alibabacloud_endpoint_util-0.0.4.dist-info/RECORD index f3a9299..11f989d 100644 --- a/venv/Lib/site-packages/alibabacloud_endpoint_util-0.0.4.dist-info/RECORD +++ b/venv/Lib/site-packages/alibabacloud_endpoint_util-0.0.4.dist-info/RECORD @@ -1,6 +1,7 @@ alibabacloud_endpoint_util-0.0.4.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 alibabacloud_endpoint_util-0.0.4.dist-info/METADATA,sha256=bqrkoK0l3kgkI7vfjV15CubNj5n08S65KGC0stF0kxw,2069 alibabacloud_endpoint_util-0.0.4.dist-info/RECORD,, +alibabacloud_endpoint_util-0.0.4.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 alibabacloud_endpoint_util-0.0.4.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91 alibabacloud_endpoint_util-0.0.4.dist-info/top_level.txt,sha256=SxgZWIi9gxV6ujIETxJc180437X1tKT1-mkqnUPqMQs,27 alibabacloud_endpoint_util/__init__.py,sha256=b8Tfyn46wV92NWm_uziWVxCW3zTxPV8EyFKcI9HhXcA,23 diff --git a/venv/Lib/site-packages/alibabacloud_endpoint_util-0.0.4.dist-info/REQUESTED b/venv/Lib/site-packages/alibabacloud_endpoint_util-0.0.4.dist-info/REQUESTED new file mode 100644 index 0000000..e69de29 diff --git a/venv/Lib/site-packages/alibabacloud_endpoint_util/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/alibabacloud_endpoint_util/__pycache__/__init__.cpython-312.pyc index 9c89117..c7d4b22 100644 Binary files a/venv/Lib/site-packages/alibabacloud_endpoint_util/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/alibabacloud_endpoint_util/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/alibabacloud_endpoint_util/__pycache__/client.cpython-312.pyc b/venv/Lib/site-packages/alibabacloud_endpoint_util/__pycache__/client.cpython-312.pyc index cd28a33..50d458e 100644 Binary files a/venv/Lib/site-packages/alibabacloud_endpoint_util/__pycache__/client.cpython-312.pyc and b/venv/Lib/site-packages/alibabacloud_endpoint_util/__pycache__/client.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/alibabacloud_gateway_spi-0.0.3.dist-info/RECORD b/venv/Lib/site-packages/alibabacloud_gateway_spi-0.0.3.dist-info/RECORD index 9f9cf1f..6f916e2 100644 --- a/venv/Lib/site-packages/alibabacloud_gateway_spi-0.0.3.dist-info/RECORD +++ b/venv/Lib/site-packages/alibabacloud_gateway_spi-0.0.3.dist-info/RECORD @@ -1,6 +1,7 @@ alibabacloud_gateway_spi-0.0.3.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 alibabacloud_gateway_spi-0.0.3.dist-info/METADATA,sha256=WEphVSwbGrBkLkcz9WAAnOrk-7Ycs0MimPyoZND4_QY,1183 alibabacloud_gateway_spi-0.0.3.dist-info/RECORD,, +alibabacloud_gateway_spi-0.0.3.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 alibabacloud_gateway_spi-0.0.3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91 alibabacloud_gateway_spi-0.0.3.dist-info/top_level.txt,sha256=511ROoT0u4oP62ojq0HVNV0pPDXQQuCtjypzurQn_lg,25 alibabacloud_gateway_spi/__init__.py,sha256=4GZKi13lDTD25YBkGakhZyEQZWTER_OWQMNPoH_UM2c,22 diff --git a/venv/Lib/site-packages/alibabacloud_gateway_spi-0.0.3.dist-info/REQUESTED b/venv/Lib/site-packages/alibabacloud_gateway_spi-0.0.3.dist-info/REQUESTED new file mode 100644 index 0000000..e69de29 diff --git a/venv/Lib/site-packages/alibabacloud_gateway_spi/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/alibabacloud_gateway_spi/__pycache__/__init__.cpython-312.pyc index 00a73b7..f772ce8 100644 Binary files a/venv/Lib/site-packages/alibabacloud_gateway_spi/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/alibabacloud_gateway_spi/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/alibabacloud_gateway_spi/__pycache__/client.cpython-312.pyc b/venv/Lib/site-packages/alibabacloud_gateway_spi/__pycache__/client.cpython-312.pyc index 87322d6..556f73a 100644 Binary files a/venv/Lib/site-packages/alibabacloud_gateway_spi/__pycache__/client.cpython-312.pyc and b/venv/Lib/site-packages/alibabacloud_gateway_spi/__pycache__/client.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/alibabacloud_gateway_spi/__pycache__/models.cpython-312.pyc b/venv/Lib/site-packages/alibabacloud_gateway_spi/__pycache__/models.cpython-312.pyc index 700df28..cf2f516 100644 Binary files a/venv/Lib/site-packages/alibabacloud_gateway_spi/__pycache__/models.cpython-312.pyc and b/venv/Lib/site-packages/alibabacloud_gateway_spi/__pycache__/models.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/alibabacloud_openapi_util-0.2.2.dist-info/RECORD b/venv/Lib/site-packages/alibabacloud_openapi_util-0.2.2.dist-info/RECORD index e070ec6..d2975d2 100644 --- a/venv/Lib/site-packages/alibabacloud_openapi_util-0.2.2.dist-info/RECORD +++ b/venv/Lib/site-packages/alibabacloud_openapi_util-0.2.2.dist-info/RECORD @@ -1,6 +1,7 @@ alibabacloud_openapi_util-0.2.2.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 alibabacloud_openapi_util-0.2.2.dist-info/METADATA,sha256=BxeKkAhw9hQu2XsgGOzFIGUJc_pYOz6ONqSKpWnf_nw,2052 alibabacloud_openapi_util-0.2.2.dist-info/RECORD,, +alibabacloud_openapi_util-0.2.2.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 alibabacloud_openapi_util-0.2.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91 alibabacloud_openapi_util-0.2.2.dist-info/top_level.txt,sha256=Jk2YmRHG2WRAq2vkmIbshlKi2Du-ol5QFs7S_gqy62M,26 alibabacloud_openapi_util/__init__.py,sha256=Mgz08fr8tY-8mhsBCgrKWOz7pu_-v4kgS4rNrtcwGxM,23 diff --git a/venv/Lib/site-packages/alibabacloud_openapi_util-0.2.2.dist-info/REQUESTED b/venv/Lib/site-packages/alibabacloud_openapi_util-0.2.2.dist-info/REQUESTED new file mode 100644 index 0000000..e69de29 diff --git a/venv/Lib/site-packages/alibabacloud_openapi_util/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/alibabacloud_openapi_util/__pycache__/__init__.cpython-312.pyc index 7cce8d4..2a2523d 100644 Binary files a/venv/Lib/site-packages/alibabacloud_openapi_util/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/alibabacloud_openapi_util/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/alibabacloud_openapi_util/__pycache__/client.cpython-312.pyc b/venv/Lib/site-packages/alibabacloud_openapi_util/__pycache__/client.cpython-312.pyc index 1dc8e33..9a9aaba 100644 Binary files a/venv/Lib/site-packages/alibabacloud_openapi_util/__pycache__/client.cpython-312.pyc and b/venv/Lib/site-packages/alibabacloud_openapi_util/__pycache__/client.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/alibabacloud_openapi_util/__pycache__/sm3.cpython-312.pyc b/venv/Lib/site-packages/alibabacloud_openapi_util/__pycache__/sm3.cpython-312.pyc index f20a700..b03ece3 100644 Binary files a/venv/Lib/site-packages/alibabacloud_openapi_util/__pycache__/sm3.cpython-312.pyc and b/venv/Lib/site-packages/alibabacloud_openapi_util/__pycache__/sm3.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/alibabacloud_tea-0.4.3.dist-info/RECORD b/venv/Lib/site-packages/alibabacloud_tea-0.4.3.dist-info/RECORD index ecc788f..983af12 100644 --- a/venv/Lib/site-packages/alibabacloud_tea-0.4.3.dist-info/RECORD +++ b/venv/Lib/site-packages/alibabacloud_tea-0.4.3.dist-info/RECORD @@ -17,5 +17,6 @@ Tea/stream.py,sha256=foR2zGN_nrFSKQai1zw0gttcqaQOEQvTue0S61yah88,892 alibabacloud_tea-0.4.3.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 alibabacloud_tea-0.4.3.dist-info/METADATA,sha256=ijuxSsvaLyiNP7Pk9AtlDwmsSz4tfNM67dekmhH4IkI,2843 alibabacloud_tea-0.4.3.dist-info/RECORD,, +alibabacloud_tea-0.4.3.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 alibabacloud_tea-0.4.3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91 alibabacloud_tea-0.4.3.dist-info/top_level.txt,sha256=9pdmruRzz-SPlHMB25KgIsDzIoBrlS2Gz_m9HmBoV5I,4 diff --git a/venv/Lib/site-packages/alibabacloud_tea-0.4.3.dist-info/REQUESTED b/venv/Lib/site-packages/alibabacloud_tea-0.4.3.dist-info/REQUESTED new file mode 100644 index 0000000..e69de29 diff --git a/venv/Lib/site-packages/alibabacloud_tea_openapi/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/alibabacloud_tea_openapi/__pycache__/__init__.cpython-312.pyc index bdea0b1..6c347cb 100644 Binary files a/venv/Lib/site-packages/alibabacloud_tea_openapi/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/alibabacloud_tea_openapi/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/alibabacloud_tea_openapi/__pycache__/client.cpython-312.pyc b/venv/Lib/site-packages/alibabacloud_tea_openapi/__pycache__/client.cpython-312.pyc index 7ea47ee..27becf2 100644 Binary files a/venv/Lib/site-packages/alibabacloud_tea_openapi/__pycache__/client.cpython-312.pyc and b/venv/Lib/site-packages/alibabacloud_tea_openapi/__pycache__/client.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/alibabacloud_tea_openapi/__pycache__/sm3.cpython-312.pyc b/venv/Lib/site-packages/alibabacloud_tea_openapi/__pycache__/sm3.cpython-312.pyc index 4347d26..a137cb0 100644 Binary files a/venv/Lib/site-packages/alibabacloud_tea_openapi/__pycache__/sm3.cpython-312.pyc and b/venv/Lib/site-packages/alibabacloud_tea_openapi/__pycache__/sm3.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/alibabacloud_tea_openapi/__pycache__/utils.cpython-312.pyc b/venv/Lib/site-packages/alibabacloud_tea_openapi/__pycache__/utils.cpython-312.pyc index 918a96f..b533aae 100644 Binary files a/venv/Lib/site-packages/alibabacloud_tea_openapi/__pycache__/utils.cpython-312.pyc and b/venv/Lib/site-packages/alibabacloud_tea_openapi/__pycache__/utils.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/alibabacloud_tea_openapi/exceptions/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/alibabacloud_tea_openapi/exceptions/__pycache__/__init__.cpython-312.pyc index cc89766..c9c2092 100644 Binary files a/venv/Lib/site-packages/alibabacloud_tea_openapi/exceptions/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/alibabacloud_tea_openapi/exceptions/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/alibabacloud_tea_openapi/exceptions/__pycache__/_alibaba_cloud.cpython-312.pyc b/venv/Lib/site-packages/alibabacloud_tea_openapi/exceptions/__pycache__/_alibaba_cloud.cpython-312.pyc index c92ce4f..0dd45fe 100644 Binary files a/venv/Lib/site-packages/alibabacloud_tea_openapi/exceptions/__pycache__/_alibaba_cloud.cpython-312.pyc and b/venv/Lib/site-packages/alibabacloud_tea_openapi/exceptions/__pycache__/_alibaba_cloud.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/alibabacloud_tea_openapi/exceptions/__pycache__/_client.cpython-312.pyc b/venv/Lib/site-packages/alibabacloud_tea_openapi/exceptions/__pycache__/_client.cpython-312.pyc index ba45448..36240db 100644 Binary files a/venv/Lib/site-packages/alibabacloud_tea_openapi/exceptions/__pycache__/_client.cpython-312.pyc and b/venv/Lib/site-packages/alibabacloud_tea_openapi/exceptions/__pycache__/_client.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/alibabacloud_tea_openapi/exceptions/__pycache__/_server.cpython-312.pyc b/venv/Lib/site-packages/alibabacloud_tea_openapi/exceptions/__pycache__/_server.cpython-312.pyc index 7dceb39..401768b 100644 Binary files a/venv/Lib/site-packages/alibabacloud_tea_openapi/exceptions/__pycache__/_server.cpython-312.pyc and b/venv/Lib/site-packages/alibabacloud_tea_openapi/exceptions/__pycache__/_server.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/alibabacloud_tea_openapi/exceptions/__pycache__/_throttling.cpython-312.pyc b/venv/Lib/site-packages/alibabacloud_tea_openapi/exceptions/__pycache__/_throttling.cpython-312.pyc index 149315e..cf44ab2 100644 Binary files a/venv/Lib/site-packages/alibabacloud_tea_openapi/exceptions/__pycache__/_throttling.cpython-312.pyc and b/venv/Lib/site-packages/alibabacloud_tea_openapi/exceptions/__pycache__/_throttling.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/alibabacloud_tea_openapi/models/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/alibabacloud_tea_openapi/models/__pycache__/__init__.cpython-312.pyc index fe98c22..2e4544a 100644 Binary files a/venv/Lib/site-packages/alibabacloud_tea_openapi/models/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/alibabacloud_tea_openapi/models/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/alibabacloud_tea_openapi/models/__pycache__/_sseresponse.cpython-312.pyc b/venv/Lib/site-packages/alibabacloud_tea_openapi/models/__pycache__/_sseresponse.cpython-312.pyc index e9c6469..3b068f6 100644 Binary files a/venv/Lib/site-packages/alibabacloud_tea_openapi/models/__pycache__/_sseresponse.cpython-312.pyc and b/venv/Lib/site-packages/alibabacloud_tea_openapi/models/__pycache__/_sseresponse.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/alibabacloud_tea_openapi/utils_models/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/alibabacloud_tea_openapi/utils_models/__pycache__/__init__.cpython-312.pyc index aae4d3c..eae7df4 100644 Binary files a/venv/Lib/site-packages/alibabacloud_tea_openapi/utils_models/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/alibabacloud_tea_openapi/utils_models/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/alibabacloud_tea_openapi/utils_models/__pycache__/_config.cpython-312.pyc b/venv/Lib/site-packages/alibabacloud_tea_openapi/utils_models/__pycache__/_config.cpython-312.pyc index 7add9f8..0f7df48 100644 Binary files a/venv/Lib/site-packages/alibabacloud_tea_openapi/utils_models/__pycache__/_config.cpython-312.pyc and b/venv/Lib/site-packages/alibabacloud_tea_openapi/utils_models/__pycache__/_config.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/alibabacloud_tea_openapi/utils_models/__pycache__/_global_parameters.cpython-312.pyc b/venv/Lib/site-packages/alibabacloud_tea_openapi/utils_models/__pycache__/_global_parameters.cpython-312.pyc index a134a38..21f6035 100644 Binary files a/venv/Lib/site-packages/alibabacloud_tea_openapi/utils_models/__pycache__/_global_parameters.cpython-312.pyc and b/venv/Lib/site-packages/alibabacloud_tea_openapi/utils_models/__pycache__/_global_parameters.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/alibabacloud_tea_openapi/utils_models/__pycache__/_open_api_request.cpython-312.pyc b/venv/Lib/site-packages/alibabacloud_tea_openapi/utils_models/__pycache__/_open_api_request.cpython-312.pyc index 6f6f16c..30b27dd 100644 Binary files a/venv/Lib/site-packages/alibabacloud_tea_openapi/utils_models/__pycache__/_open_api_request.cpython-312.pyc and b/venv/Lib/site-packages/alibabacloud_tea_openapi/utils_models/__pycache__/_open_api_request.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/alibabacloud_tea_openapi/utils_models/__pycache__/_params.cpython-312.pyc b/venv/Lib/site-packages/alibabacloud_tea_openapi/utils_models/__pycache__/_params.cpython-312.pyc index 57c9fcf..1077609 100644 Binary files a/venv/Lib/site-packages/alibabacloud_tea_openapi/utils_models/__pycache__/_params.cpython-312.pyc and b/venv/Lib/site-packages/alibabacloud_tea_openapi/utils_models/__pycache__/_params.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/alibabacloud_tea_util/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/alibabacloud_tea_util/__pycache__/__init__.cpython-312.pyc index 47689a1..6942b74 100644 Binary files a/venv/Lib/site-packages/alibabacloud_tea_util/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/alibabacloud_tea_util/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/alibabacloud_tea_util/__pycache__/client.cpython-312.pyc b/venv/Lib/site-packages/alibabacloud_tea_util/__pycache__/client.cpython-312.pyc index 2afaef4..b313296 100644 Binary files a/venv/Lib/site-packages/alibabacloud_tea_util/__pycache__/client.cpython-312.pyc and b/venv/Lib/site-packages/alibabacloud_tea_util/__pycache__/client.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/alibabacloud_tea_util/__pycache__/models.cpython-312.pyc b/venv/Lib/site-packages/alibabacloud_tea_util/__pycache__/models.cpython-312.pyc index b5a190a..92ba1a0 100644 Binary files a/venv/Lib/site-packages/alibabacloud_tea_util/__pycache__/models.cpython-312.pyc and b/venv/Lib/site-packages/alibabacloud_tea_util/__pycache__/models.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/alipay/__init__.py b/venv/Lib/site-packages/alipay/__init__.py new file mode 100644 index 0000000..adf75d1 --- /dev/null +++ b/venv/Lib/site-packages/alipay/__init__.py @@ -0,0 +1,890 @@ +#!/usr/bin/env python +# coding: utf-8 +""" + __init__.py + ~~~~~~~~~~ +""" +import json +from datetime import datetime +from functools import partial + +import hashlib +import OpenSSL +from Cryptodome.Hash import SHA, SHA256 +from Cryptodome.PublicKey import RSA +from Cryptodome.Signature import PKCS1_v1_5 + +from .compat import decodebytes, encodebytes, quote_plus, urlopen +from .exceptions import AliPayException, AliPayValidationError +from .utils import AliPayConfig +from .loggers import logger + + +# 常见加密算法 +CryptoAlgSet = ( + b'rsaEncryption', + b'md2WithRSAEncryption', + b'md5WithRSAEncryption', + b'sha1WithRSAEncryption', + b'sha256WithRSAEncryption', + b'sha384WithRSAEncryption', + b'sha512WithRSAEncryption' +) + + +class BaseAliPay: + @property + def appid(self): + return self._appid + + @property + def sign_type(self): + return self._sign_type + + @property + def app_private_key(self): + """签名用""" + return self._app_private_key + + @property + def alipay_public_key(self): + """验证签名用""" + return self._alipay_public_key + + def __init__( + self, + appid, + app_notify_url=None, + app_private_key_string=None, + alipay_public_key_string=None, + sign_type="RSA2", + debug=False, + verbose=False, + config=None + ): + """ + 初始化: + alipay = AliPay( + appid="", + app_notify_url="http://example.com", + sign_type="RSA2" + ) + """ + self._appid = str(appid) + self._app_notify_url = app_notify_url + self._app_private_key_string = app_private_key_string + self._alipay_public_key_string = alipay_public_key_string + self._verbose = verbose + self._config = config or AliPayConfig() + + self._app_private_key = None + self._alipay_public_key = None + if sign_type not in ("RSA", "RSA2"): + message = "Unsupported sign type {}".format(sign_type) + raise AliPayException(None, message) + self._sign_type = sign_type + + if debug: + # self._gateway = "https://openapi.alipaydev.com/gateway.do" + self._gateway = "https://openapi-sandbox.dl.alipaydev.com/gateway.do" + else: + self._gateway = "https://openapi.alipay.com/gateway.do" + + # load key file immediately + self._load_key() + + def _load_key(self): + # load private key + content = self._app_private_key_string + self._app_private_key = RSA.importKey(content) + + # load public key + content = self._alipay_public_key_string + self._alipay_public_key = RSA.importKey(content) + + def _sign(self, unsigned_string): + """ + 通过如下方法调试签名 + 方法1 + key = rsa.PrivateKey.load_pkcs1(open(self._app_private_key_string).read()) + sign = rsa.sign(unsigned_string.encode(), key, "SHA-1") + # base64 编码,转换为 unicode 表示并移除回车 + sign = base64.encodebytes(sign).decode().replace("\n", "") + 方法2 + key = RSA.importKey(open(self._app_private_key_string).read()) + signer = PKCS1_v1_5.new(key) + signature = signer.sign(SHA.new(unsigned_string.encode())) + # base64 编码,转换为 unicode 表示并移除回车 + sign = base64.encodebytes(signature).decode().replace("\n", "") + 方法3 + echo "abc" | openssl sha1 -sign alipay.key | openssl base64 + """ + # 开始计算签名 + key = self.app_private_key + signer = PKCS1_v1_5.new(key) + if self._sign_type == "RSA": + signature = signer.sign(SHA.new(unsigned_string.encode())) + else: + signature = signer.sign(SHA256.new(unsigned_string.encode())) + # base64 编码,转换为 unicode 表示并移除回车 + sign = encodebytes(signature).decode().replace("\n", "") + return sign + + def _ordered_data(self, data): + for k, v in data.items(): + if isinstance(v, dict): + # 将字典类型的数据dump出来 + data[k] = json.dumps(v, separators=(',', ':')) + return sorted(data.items()) + + def build_body(self, method, biz_content=None, **kwargs): + if not biz_content: + biz_content = {} + + data = { + "app_id": self._appid, + "method": method, + "charset": "utf-8", + "sign_type": self._sign_type, + "timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S"), + "version": "1.0", + "biz_content": biz_content + } + data.update(kwargs) + + if method in ( + "alipay.trade.app.pay", "alipay.trade.wap.pay", + "alipay.trade.page.pay", "alipay.trade.pay", + "alipay.trade.precreate", "alipay.trade.create" + ) and not data.get("notify_url") and self._app_notify_url: + data["notify_url"] = self._app_notify_url + + # the following keys are optional, and should be removed if it's empty + keys = ("notify_url", "return_url") + for key in keys: + if key in data and not data.get(key, None): + data.pop(key, None) + + if self._verbose: + logger.debug("data to be signed") + logger.debug(data) + return data + + def sign_data(self, data): + # 排序后的字符串 + ordered_items = self._ordered_data(data) + raw_string = "&".join("{}={}".format(k, v) for k, v in ordered_items) + sign = self._sign(raw_string) + unquoted_items = ordered_items + [('sign', sign)] + + # 获得最终的订单信息字符串 + signed_string = "&".join("{}={}".format(k, quote_plus(v)) for k, v in unquoted_items) + if self._verbose: + logger.debug("signed srtring") + logger.debug(signed_string) + return signed_string + + def _verify(self, raw_content, signature): + # 开始计算签名 + key = self.alipay_public_key + signer = PKCS1_v1_5.new(key) + if self._sign_type == "RSA": + digest = SHA.new() + else: + digest = SHA256.new() + digest.update(raw_content.encode()) + return bool(signer.verify(digest, decodebytes(signature.encode()))) + + def verify(self, data, signature): + if "sign_type" in data: + sign_type = data.pop("sign_type") + if sign_type != self._sign_type: + raise AliPayException(None, "Unknown sign type: {}".format(sign_type)) + # 排序后的字符串 + unsigned_items = self._ordered_data(data) + message = "&".join(u"{}={}".format(k, v) for k, v in unsigned_items) + return self._verify(message, signature) + + def client_api(self, api_name, biz_content=None, **kwargs): + """ + alipay api without http request + """ + if not biz_content: + biz_content = {} + + data = self.build_body(api_name, biz_content, **kwargs) + return self.sign_data(data) + + def server_api(self, api_name, biz_content=None, **kwargs): + """ + alipay api with http request + """ + if not biz_content: + biz_content = {} + + data = self.build_body(api_name, biz_content, **kwargs) + # alipay.trade.query => alipay_trade_query_response + response_type = api_name.replace(".", "_") + "_response" + # print(data) + return self.verified_sync_response(data, response_type) + + def api_alipay_trade_wap_pay( + self, subject, out_trade_no, total_amount, + return_url=None, notify_url=None, **kwargs + ): + biz_content = { + "subject": subject, + "out_trade_no": out_trade_no, + "total_amount": total_amount, + "product_code": "QUICK_WAP_PAY" + } + biz_content.update(kwargs) + data = self.build_body( + "alipay.trade.wap.pay", + biz_content, + return_url=return_url, + notify_url=notify_url + ) + return self.sign_data(data) + + def api_alipay_trade_app_pay( + self, subject, out_trade_no, total_amount, notify_url=None, **kwargs + ): + biz_content = { + "subject": subject, + "out_trade_no": out_trade_no, + "total_amount": total_amount, + "product_code": "QUICK_MSECURITY_PAY" + } + biz_content.update(kwargs) + data = self.build_body("alipay.trade.app.pay", biz_content, notify_url=notify_url) + return self.sign_data(data) + + def api_alipay_trade_page_pay(self, subject, out_trade_no, total_amount, + return_url=None, notify_url=None, **kwargs): + biz_content = { + "subject": subject, + "out_trade_no": out_trade_no, + "total_amount": total_amount, + "product_code": "FAST_INSTANT_TRADE_PAY" + } + + biz_content.update(kwargs) + data = self.build_body( + "alipay.trade.page.pay", + biz_content, + return_url=return_url, + notify_url=notify_url + ) + return self.sign_data(data) + + def api_alipay_trade_query(self, out_trade_no=None, trade_no=None): + """ + response = { + "alipay_trade_query_response": { + "trade_no": "2017032121001004070200176844", + "code": "10000", + "invoice_amount": "20.00", + "open_id": "20880072506750308812798160715407", + "fund_bill_list": [ + { + "amount": "20.00", + "fund_channel": "ALIPAYACCOUNT" + } + ], + "buyer_logon_id": "csq***@sandbox.com", + "send_pay_date": "2017-03-21 13:29:17", + "receipt_amount": "20.00", + "out_trade_no": "out_trade_no15", + "buyer_pay_amount": "20.00", + "buyer_user_id": "2088102169481075", + "msg": "Success", + "point_amount": "0.00", + "trade_status": "TRADE_SUCCESS", + "total_amount": "20.00" + }, + "sign": "" + } + """ + assert (out_trade_no is not None) or (trade_no is not None),\ + "Both trade_no and out_trade_no are None" + + biz_content = {} + if out_trade_no: + biz_content["out_trade_no"] = out_trade_no + if trade_no: + biz_content["trade_no"] = trade_no + data = self.build_body("alipay.trade.query", biz_content) + response_type = "alipay_trade_query_response" + return self.verified_sync_response(data, response_type) + + def api_alipay_trade_pay( + self, out_trade_no, scene, auth_code, subject, notify_url=None, **kwargs + ): + """ + eg: + self.api_alipay_trade_pay( + out_trade_no, + "bar_code/wave_code", + auth_code, + subject, + total_amount=12, + discountable_amount=10 + ) + + failed response = { + "alipay_trade_pay_response": { + "code": "40004", + "msg": "Business Failed", + "sub_code": "ACQ.INVALID_PARAMETER", + "sub_msg": "", + "buyer_pay_amount": "0.00", + "invoice_amount": "0.00", + "point_amount": "0.00", + "receipt_amount": "0.00" + }, + "sign": "" + } + succeeded response = { + "alipay_trade_pay_response": { + "trade_no": "2017032121001004070200176846", + "code": "10000", + "invoice_amount": "20.00", + "open_id": "20880072506750308812798160715407", + "fund_bill_list": [ + { + "amount": "20.00", + "fund_channel": "ALIPAYACCOUNT" + } + ], + "buyer_logon_id": "csq***@sandbox.com", + "receipt_amount": "20.00", + "out_trade_no": "out_trade_no18", + "buyer_pay_amount": "20.00", + "buyer_user_id": "2088102169481075", + "msg": "Success", + "point_amount": "0.00", + "gmt_payment": "2017-03-21 15:07:29", + "total_amount": "20.00" + }, + "sign": "" + } + """ + assert scene in ("bar_code", "wave_code"), 'scene not in ("bar_code", "wave_code")' + + biz_content = { + "out_trade_no": out_trade_no, + "scene": scene, + "auth_code": auth_code, + "subject": subject + } + biz_content.update(**kwargs) + data = self.build_body("alipay.trade.pay", biz_content, notify_url=notify_url) + response_type = "alipay_trade_pay_response" + return self.verified_sync_response(data, response_type) + + def api_alipay_trade_refund(self, refund_amount, out_trade_no=None, trade_no=None, **kwargs): + biz_content = { + "refund_amount": refund_amount + } + biz_content.update(**kwargs) + if out_trade_no: + biz_content["out_trade_no"] = out_trade_no + if trade_no: + biz_content["trade_no"] = trade_no + + data = self.build_body("alipay.trade.refund", biz_content) + response_type = "alipay_trade_refund_response" + return self.verified_sync_response(data, response_type) + + def api_alipay_trade_cancel(self, out_trade_no=None, trade_no=None): + """ + response = { + "alipay_trade_cancel_response": { + "msg": "Success", + "out_trade_no": "out_trade_no15", + "code": "10000", + "retry_flag": "N" + } + } + """ + + assert (out_trade_no is not None) or (trade_no is not None),\ + "Both trade_no and out_trade_no are None" + + biz_content = {} + if out_trade_no: + biz_content["out_trade_no"] = out_trade_no + if trade_no: + biz_content["trade_no"] = trade_no + + data = self.build_body("alipay.trade.cancel", biz_content) + response_type = "alipay_trade_cancel_response" + return self.verified_sync_response(data, response_type) + + def api_alipay_trade_close(self, out_trade_no=None, trade_no=None, operator_id=None): + """ + response = { + "alipay_trade_close_response": { + "code": "10000", + "msg": "Success", + "trade_no": "2013112111001004500000675971", + "out_trade_no": "YX_001"a + } + } + """ + + assert (out_trade_no is not None) or (trade_no is not None),\ + "Both trade_no and out_trade_no are None" + + biz_content = {} + if out_trade_no: + biz_content["out_trade_no"] = out_trade_no + if trade_no: + biz_content["trade_no"] = trade_no + if operator_id: + biz_content["operator_id"] = operator_id + + data = self.build_body("alipay.trade.close", biz_content) + response_type = "alipay_trade_close_response" + return self.verified_sync_response(data, response_type) + + def api_alipay_trade_create( + self, subject, out_trade_no, total_amount, notify_url=None, **kwargs + ): + biz_content = { + "subject": subject, + "out_trade_no": out_trade_no, + "total_amount": total_amount + } + biz_content.update(kwargs) + data = self.build_body("alipay.trade.create", biz_content, notify_url=notify_url) + response_type = "alipay_trade_create" + return self.verified_sync_response(data, response_type) + + def api_alipay_trade_precreate( + self, subject, out_trade_no, total_amount, notify_url=None, **kwargs + ): + """ + success response = { + "alipay_trade_precreate_response": { + "msg": "Success", + "out_trade_no": "out_trade_no17", + "code": "10000", + "qr_code": "https://qr.alipay.com/bax03431ljhokirwl38f00a7" + }, + "sign": "" + } + + + failed response = { + "alipay_trade_precreate_response": { + "msg": "Business Failed", + "sub_code": "ACQ.TOTAL_FEE_EXCEED", + "code": "40004", + "sub_msg": "订单金额超过限额" + }, + "sign": "" + } + """ + biz_content = { + "out_trade_no": out_trade_no, + "total_amount": total_amount, + "subject": subject + } + biz_content.update(**kwargs) + data = self.build_body("alipay.trade.precreate", biz_content, notify_url=notify_url) + response_type = "alipay_trade_precreate_response" + return self.verified_sync_response(data, response_type) + + def api_alipay_trade_fastpay_refund_query( + self, out_request_no, trade_no=None, out_trade_no=None + ): + assert (out_trade_no is not None) or (trade_no is not None),\ + "Both trade_no and out_trade_no are None" + + biz_content = {"out_request_no": out_request_no} + if trade_no: + biz_content["trade_no"] = trade_no + else: + biz_content["out_trade_no"] = out_trade_no + + data = self.build_body("alipay.trade.fastpay.refund.query", biz_content) + response_type = "alipay_trade_fastpay_refund_query_response" + return self.verified_sync_response(data, response_type) + + def api_alipay_fund_trans_toaccount_transfer( + self, out_biz_no, payee_type, payee_account, amount, **kwargs + ): + assert payee_type in ("ALIPAY_USERID", "ALIPAY_LOGONID"), "unknown payee type" + biz_content = { + "out_biz_no": out_biz_no, + "payee_type": payee_type, + "payee_account": payee_account, + "amount": amount + } + biz_content.update(kwargs) + data = self.build_body("alipay.fund.trans.toaccount.transfer", biz_content) + response_type = "alipay_fund_trans_toaccount_transfer_response" + return self.verified_sync_response(data, response_type) + + def api_alipay_fund_trans_order_query(self, out_biz_no=None, order_id=None): + if out_biz_no is None and order_id is None: + raise Exception("Both out_biz_no and order_id are None!") + + biz_content = {} + if out_biz_no: + biz_content["out_biz_no"] = out_biz_no + if order_id: + biz_content["order_id"] = order_id + + data = self.build_body("alipay.fund.trans.order.query", biz_content) + response_type = "alipay_fund_trans_order_query_response" + return self.verified_sync_response(data, response_type) + + def api_alipay_trade_order_settle( + self, + out_request_no, + trade_no, + royalty_parameters, + **kwargs + ): + biz_content = { + "out_request_no": out_request_no, + "trade_no": trade_no, + "royalty_parameters": royalty_parameters, + } + biz_content.update(kwargs) + data = self.build_body("alipay.trade.order.settle", biz_content) + response_type = "alipay_trade_order_settle_response" + return self.verified_sync_response(data, response_type) + + def api_alipay_ebpp_invoice_token_batchquery(self, invoice_token=None, scene=None): + if scene is None: + scene = "INVOICE_EXPENSE" + if invoice_token is None: + raise Exception("invoice_token is None!") + + biz_content = { + "invoice_token": invoice_token, + "scene": scene + } + data = self.build_body("alipay.ebpp.invoice.token.batchquery", biz_content) + response_type = "alipay_ebpp_invoice_token_batchquery_response" + return self.verified_sync_response(data, response_type) + + def _verify_and_return_sync_response(self, raw_string, response_type): + """ + return response if verification succeeded, raise exception if not + + As to issue #69, json.loads(raw_string)[response_type] should not be returned directly, + use json.loads(plain_content) instead + + failed response is like this + { + "alipay_trade_query_response": { + "sub_code": "isv.invalid-app-id", + "code": "40002", + "sub_msg": "无效的AppID参数", + "msg": "Invalid Arguments" + } + } + or + { + "error_response": { + "msg": "Invalid Arguments", + "code": "40002", + "sub_msg": "授权码code无效", + "sub_code": "isv.code-invalid" + }, + "alipay_cert_sn": "a5b59edf65dcda9ca26e071ab6f5a0a7", + "sign": "" + } + + """ + response = json.loads(raw_string) + if "sign" not in response.keys() or "error_response" in response.keys(): + result = response.get(response_type, None) or response.get("error_response") + raise AliPayException( + code=result.get("code", "0"), + message=raw_string + ) + + sign = response["sign"] + + # locate string to be signed + plain_content = self._get_string_to_be_signed(raw_string, response_type) + + if not self._verify(plain_content, sign): + raise AliPayValidationError + return json.loads(plain_content) + + def verified_sync_response(self, data, response_type): + url = self._gateway + "?" + self.sign_data(data) + raw_string = urlopen(url, timeout=self._config.timeout).read().decode() + return self._verify_and_return_sync_response(raw_string, response_type) + + def _get_string_to_be_signed(self, raw_string, response_type): + """ + https://docs.open.alipay.com/200/106120 + 从同步返回的接口里面找到待签名的字符串 + """ + balance = 0 + start = end = raw_string.find("{", raw_string.find(response_type)) + # 从response_type之后的第一个{的下一位开始匹配, + # 如果是{则balance加1; 如果是}而且balance=0,就是待验签字符串的终点 + for i, c in enumerate(raw_string[start + 1:], start + 1): + if c == "{": + balance += 1 + elif c == "}": + if balance == 0: + end = i + 1 + break + balance -= 1 + return raw_string[start:end] + + +class AliPay(BaseAliPay): + pass + + +class DCAliPay(BaseAliPay): + """ + 数字证书 (digital certificate) 版本 + """ + + def __init__( + self, + appid, + app_private_key_string, + app_public_key_cert_string, + alipay_public_key_cert_string, + alipay_root_cert_string, + app_notify_url=None, + sign_type="RSA2", + debug=False, + verbose=False + ): + """ + 初始化 + DCAlipay( + appid='', + app_notify_url='http://example.com', + app_private_key_string='', + app_public_key_cert_string='', + alipay_public_key_cert_sring='', + aplipay_root_cert_string='', + ) + """ + self._app_public_key_cert_string = app_public_key_cert_string + self._alipay_public_key_cert_string = alipay_public_key_cert_string + self._alipay_root_cert_string = alipay_root_cert_string + alipay_public_key_string = self.load_alipay_public_key_string() + super().__init__( + appid=appid, + app_notify_url=app_notify_url, + app_private_key_string=app_private_key_string, + alipay_public_key_string=alipay_public_key_string, + sign_type=sign_type, + debug=debug, + verbose=verbose + ) + + def api_alipay_open_app_alipaycert_download(self, alipay_cert_sn): + """ + 下载支付宝证书 + 验签使用,支付宝公钥证书无感知升级机制 + """ + biz_content = { + "alipay_cert_sn": alipay_cert_sn + } + data = self.build_body("alipay.open.app.alipaycert.download", biz_content) + return self.sign_data(data) + + def build_body(self, *args, **kwargs): + data = super().build_body(*args, **kwargs) + data["app_cert_sn"] = self.app_cert_sn + data["alipay_root_cert_sn"] = self.alipay_root_cert_sn + if self._verbose: + logger.debug("data to be signed") + logger.debug(data) + return data + + def load_alipay_public_key_string(self): + cert = OpenSSL.crypto.load_certificate( + OpenSSL.crypto.FILETYPE_PEM, self._alipay_public_key_cert_string + ) + return OpenSSL.crypto.dump_publickey( + OpenSSL.crypto.FILETYPE_PEM, cert.get_pubkey() + ).decode("utf-8") + + @staticmethod + def get_cert_sn(cert): + """ + 获取证书 SN 算法 + """ + cert = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM, cert) + certIssue = cert.get_issuer() + name = 'CN={},OU={},O={},C={}'.format(certIssue.CN, certIssue.OU, certIssue.O, certIssue.C) + string = name + str(cert.get_serial_number()) + return hashlib.md5(string.encode()).hexdigest() + + @staticmethod + def read_pem_cert_chain(certContent): + """解析根证书""" + # 根证书中,每个 cert 中间有两个回车间隔 + items = [i for i in certContent.split('\n\n') if i] + load_cert = partial(OpenSSL.crypto.load_certificate, OpenSSL.crypto.FILETYPE_PEM) + return [load_cert(c) for c in items] + + @staticmethod + def get_root_cert_sn(rootCert): + """ 根证书 SN 算法""" + certs = DCAliPay.read_pem_cert_chain(rootCert) + rootCertSN = None + for cert in certs: + try: + sigAlg = cert.get_signature_algorithm() + except ValueError: + continue + if sigAlg in CryptoAlgSet: + certIssue = cert.get_issuer() + name = 'CN={},OU={},O={},C={}'.format( + certIssue.CN, certIssue.OU, certIssue.O, certIssue.C + ) + string = name + str(cert.get_serial_number()) + certSN = hashlib.md5(string.encode()).hexdigest() + if not rootCertSN: + rootCertSN = certSN + else: + rootCertSN = rootCertSN + '_' + certSN + return rootCertSN + + @property + def app_cert_sn(self): + if not hasattr(self, "_app_cert_sn"): + self._app_cert_sn = self.get_cert_sn(self._app_public_key_cert_string) + return getattr(self, "_app_cert_sn") + + @property + def alipay_root_cert_sn(self): + if not hasattr(self, "_alipay_root_cert_sn"): + self._alipay_root_cert_sn = self.get_root_cert_sn(self._alipay_root_cert_string) + return getattr(self, "_alipay_root_cert_sn") + + def api_alipay_fund_trans_uni_transfer( + self, out_biz_no, identity_type, identity, trans_amount, name=None, **kwargs + ): + """ + 单笔转账接口, 只支持公钥证书模式 + 文档地址: https://opendocs.alipay.com/apis/api_28/alipay.fund.trans.uni.transfer + """ + assert identity_type in ("ALIPAY_USER_ID", "ALIPAY_LOGON_ID"), "unknown identity type" + + biz_content = { + "payee_info": { + "identity": identity, + "identity_type": identity_type, + }, + "out_biz_no": out_biz_no, + "trans_amount": trans_amount, + "product_code": "TRANS_ACCOUNT_NO_PWD", + "biz_scene": "DIRECT_TRANSFER", + } + biz_content["payee_info"]["name"] = name if name else None + biz_content.update(kwargs) + + response_type = "alipay_fund_trans_uni_transfer_response" + data = self.build_body("alipay.fund.trans.uni.transfer", biz_content) + return self.verified_sync_response(data, response_type) + + +class ISVAliPay(BaseAliPay): + + def __init__( + self, + appid, + app_notify_url=None, + app_private_key_string=None, + alipay_public_key_string=None, + sign_type="RSA2", + debug=False, + verbose=False, + app_auth_token=None, + app_auth_code=None + ): + if not app_auth_token and not app_auth_code: + raise Exception("Both app_auth_code and app_auth_token are None !!!") + + self._app_auth_token = app_auth_token + self._app_auth_code = app_auth_code + super().__init__( + appid, + app_notify_url, + app_private_key_string=app_private_key_string, + alipay_public_key_string=alipay_public_key_string, + sign_type=sign_type, + debug=debug, + verbose=verbose + ) + + @property + def app_auth_token(self): + # 没有则换取token + if not self._app_auth_token: + result = self.api_alipay_open_auth_token_app(self._app_auth_code) + self._app_auth_token = result.get("app_auth_token") + if not self._app_auth_token: + msg = "Get auth token by auth code failed: {}" + raise Exception(msg.format(self._app_auth_code)) + return self._app_auth_token + + def build_body(self, *args, **kwargs): + data = super().build_body(*args, **kwargs) + if self._app_auth_token: + data["app_auth_token"] = self._app_auth_token + if self._verbose: + logger.debug("data to be signed") + logger.debug(data) + + return data + + def api_alipay_open_auth_token_app(self, refresh_token=None): + """ + response = { + "code": "10000", + "msg": "Success", + "app_auth_token": "201708BB28623ce3d10f4f62875e9ef5cbeebX07", + "app_refresh_token": "201708BB108a270d8bb6409890d16175a04a7X07", + "auth_app_id": "appid", + "expires_in": 31536000, + "re_expires_in": 32140800, + "user_id": "2088xxxxx + } + """ + + if refresh_token: + biz_content = { + "grant_type": "refresh_token", + "refresh_token": refresh_token + } + else: + biz_content = { + "grant_type": "authorization_code", + "code": self._app_auth_code + } + data = self.build_body( + "alipay.open.auth.token.app", + biz_content, + ) + response_type = "alipay_open_auth_token_app_response" + return self.verified_sync_response(data, response_type) + + def api_alipay_open_auth_token_app_query(self): + biz_content = {"app_auth_token": self.app_auth_token} + data = self.build_body( + "alipay.open.auth.token.app.query", + biz_content, + ) + response_type = "alipay_open_auth_token_app_query_response" + return self.verified_sync_response(data, response_type) diff --git a/venv/Lib/site-packages/alipay/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/alipay/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000..7422f87 Binary files /dev/null and b/venv/Lib/site-packages/alipay/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/alipay/__pycache__/compat.cpython-312.pyc b/venv/Lib/site-packages/alipay/__pycache__/compat.cpython-312.pyc new file mode 100644 index 0000000..5f84302 Binary files /dev/null and b/venv/Lib/site-packages/alipay/__pycache__/compat.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/alipay/__pycache__/exceptions.cpython-312.pyc b/venv/Lib/site-packages/alipay/__pycache__/exceptions.cpython-312.pyc new file mode 100644 index 0000000..51ce22f Binary files /dev/null and b/venv/Lib/site-packages/alipay/__pycache__/exceptions.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/alipay/__pycache__/loggers.cpython-312.pyc b/venv/Lib/site-packages/alipay/__pycache__/loggers.cpython-312.pyc new file mode 100644 index 0000000..6017065 Binary files /dev/null and b/venv/Lib/site-packages/alipay/__pycache__/loggers.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/alipay/__pycache__/utils.cpython-312.pyc b/venv/Lib/site-packages/alipay/__pycache__/utils.cpython-312.pyc new file mode 100644 index 0000000..37efefa Binary files /dev/null and b/venv/Lib/site-packages/alipay/__pycache__/utils.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/alipay/compat.py b/venv/Lib/site-packages/alipay/compat.py new file mode 100644 index 0000000..914fb44 --- /dev/null +++ b/venv/Lib/site-packages/alipay/compat.py @@ -0,0 +1,9 @@ +#!/usr/bin/env python +# coding: utf-8 +""" + compat.py + ~~~~~~~~~~ +""" +from urllib.parse import quote_plus +from urllib.request import urlopen +from base64 import decodebytes, encodebytes diff --git a/venv/Lib/site-packages/alipay/exceptions.py b/venv/Lib/site-packages/alipay/exceptions.py new file mode 100644 index 0000000..2e59f44 --- /dev/null +++ b/venv/Lib/site-packages/alipay/exceptions.py @@ -0,0 +1,25 @@ +#!/usr/bin/env python +# coding: utf-8 +""" + exceptions.py + ~~~~~~~~~~ +""" + + +class AliPayException(Exception): + def __init__(self, code, message): + self.__code = code + self.__message = message + + def to_unicode(self): + return "AliPayException: code:{}, message:{}".format(self.__code, self.__message) + + def __str__(self): + return self.to_unicode() + + def __repr__(self): + return self.to_unicode() + + +class AliPayValidationError(Exception): + pass diff --git a/venv/Lib/site-packages/alipay/loggers.py b/venv/Lib/site-packages/alipay/loggers.py new file mode 100644 index 0000000..4a564ac --- /dev/null +++ b/venv/Lib/site-packages/alipay/loggers.py @@ -0,0 +1,26 @@ +import logging +import logging.config + +logging.config.dictConfig({ + "version": 1, + "disable_existing_loggers": False, + "formatters": { + "standard": { + "format": "%(asctime)s [%(levelname)s] %(name)s: %(message)s" + }, + }, + "handlers": { + "console": { + "level": "DEBUG", + "formatter": "standard", + "class": "logging.StreamHandler", + }, + }, + "loggers": { + "python-alipay-sdk": { + "handlers": ["console"], + "level": "DEBUG", + } + } +}) +logger = logging.getLogger("python-alipay-sdk") diff --git a/venv/Lib/site-packages/alipay/utils.py b/venv/Lib/site-packages/alipay/utils.py new file mode 100644 index 0000000..19871d8 --- /dev/null +++ b/venv/Lib/site-packages/alipay/utils.py @@ -0,0 +1,9 @@ +""" + alipay/utils.py + ~~~~~~~~~~ +""" + + +class AliPayConfig: + def __init__(self, timeout=15): + self.timeout = timeout diff --git a/venv/Lib/site-packages/apscheduler-3.11.2.dist-info/RECORD b/venv/Lib/site-packages/apscheduler-3.11.2.dist-info/RECORD index 70602cd..81e345d 100644 --- a/venv/Lib/site-packages/apscheduler-3.11.2.dist-info/RECORD +++ b/venv/Lib/site-packages/apscheduler-3.11.2.dist-info/RECORD @@ -1,6 +1,7 @@ apscheduler-3.11.2.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 apscheduler-3.11.2.dist-info/METADATA,sha256=isrjIgfQXa2C9Ky7hBjOtp21BjnfMw4nIUkd6JeXbgA,6443 apscheduler-3.11.2.dist-info/RECORD,, +apscheduler-3.11.2.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 apscheduler-3.11.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91 apscheduler-3.11.2.dist-info/entry_points.txt,sha256=HSDTxgulLTgymfXK2UNCPP1ib5rlQSFgZJEg72vto3s,1181 apscheduler-3.11.2.dist-info/licenses/LICENSE.txt,sha256=YWP3mH37ONa8MgzitwsvArhivEESZRbVUu8c1DJH51g,1130 diff --git a/venv/Lib/site-packages/apscheduler-3.11.2.dist-info/REQUESTED b/venv/Lib/site-packages/apscheduler-3.11.2.dist-info/REQUESTED new file mode 100644 index 0000000..e69de29 diff --git a/venv/Lib/site-packages/apscheduler/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/apscheduler/__pycache__/__init__.cpython-312.pyc index ebf7ad5..d6479ae 100644 Binary files a/venv/Lib/site-packages/apscheduler/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/apscheduler/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/apscheduler/__pycache__/events.cpython-312.pyc b/venv/Lib/site-packages/apscheduler/__pycache__/events.cpython-312.pyc index bd58f45..646a9c2 100644 Binary files a/venv/Lib/site-packages/apscheduler/__pycache__/events.cpython-312.pyc and b/venv/Lib/site-packages/apscheduler/__pycache__/events.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/apscheduler/__pycache__/job.cpython-312.pyc b/venv/Lib/site-packages/apscheduler/__pycache__/job.cpython-312.pyc index e55ce68..559191d 100644 Binary files a/venv/Lib/site-packages/apscheduler/__pycache__/job.cpython-312.pyc and b/venv/Lib/site-packages/apscheduler/__pycache__/job.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/apscheduler/__pycache__/util.cpython-312.pyc b/venv/Lib/site-packages/apscheduler/__pycache__/util.cpython-312.pyc index 5af9a03..82c416f 100644 Binary files a/venv/Lib/site-packages/apscheduler/__pycache__/util.cpython-312.pyc and b/venv/Lib/site-packages/apscheduler/__pycache__/util.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/apscheduler/executors/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/apscheduler/executors/__pycache__/__init__.cpython-312.pyc index 53a34d1..8a9d198 100644 Binary files a/venv/Lib/site-packages/apscheduler/executors/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/apscheduler/executors/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/apscheduler/executors/__pycache__/asyncio.cpython-312.pyc b/venv/Lib/site-packages/apscheduler/executors/__pycache__/asyncio.cpython-312.pyc index df5f3e6..5f07578 100644 Binary files a/venv/Lib/site-packages/apscheduler/executors/__pycache__/asyncio.cpython-312.pyc and b/venv/Lib/site-packages/apscheduler/executors/__pycache__/asyncio.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/apscheduler/executors/__pycache__/base.cpython-312.pyc b/venv/Lib/site-packages/apscheduler/executors/__pycache__/base.cpython-312.pyc index 12d3045..f6c1d3f 100644 Binary files a/venv/Lib/site-packages/apscheduler/executors/__pycache__/base.cpython-312.pyc and b/venv/Lib/site-packages/apscheduler/executors/__pycache__/base.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/apscheduler/executors/__pycache__/debug.cpython-312.pyc b/venv/Lib/site-packages/apscheduler/executors/__pycache__/debug.cpython-312.pyc index 0e047d2..9d6ec0f 100644 Binary files a/venv/Lib/site-packages/apscheduler/executors/__pycache__/debug.cpython-312.pyc and b/venv/Lib/site-packages/apscheduler/executors/__pycache__/debug.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/apscheduler/executors/__pycache__/gevent.cpython-312.pyc b/venv/Lib/site-packages/apscheduler/executors/__pycache__/gevent.cpython-312.pyc index fb89c9d..c742c56 100644 Binary files a/venv/Lib/site-packages/apscheduler/executors/__pycache__/gevent.cpython-312.pyc and b/venv/Lib/site-packages/apscheduler/executors/__pycache__/gevent.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/apscheduler/executors/__pycache__/pool.cpython-312.pyc b/venv/Lib/site-packages/apscheduler/executors/__pycache__/pool.cpython-312.pyc index 51934ef..05f9534 100644 Binary files a/venv/Lib/site-packages/apscheduler/executors/__pycache__/pool.cpython-312.pyc and b/venv/Lib/site-packages/apscheduler/executors/__pycache__/pool.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/apscheduler/executors/__pycache__/tornado.cpython-312.pyc b/venv/Lib/site-packages/apscheduler/executors/__pycache__/tornado.cpython-312.pyc index d4454cf..371c2e8 100644 Binary files a/venv/Lib/site-packages/apscheduler/executors/__pycache__/tornado.cpython-312.pyc and b/venv/Lib/site-packages/apscheduler/executors/__pycache__/tornado.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/apscheduler/executors/__pycache__/twisted.cpython-312.pyc b/venv/Lib/site-packages/apscheduler/executors/__pycache__/twisted.cpython-312.pyc index a4c5a16..4358a7a 100644 Binary files a/venv/Lib/site-packages/apscheduler/executors/__pycache__/twisted.cpython-312.pyc and b/venv/Lib/site-packages/apscheduler/executors/__pycache__/twisted.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/apscheduler/jobstores/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/apscheduler/jobstores/__pycache__/__init__.cpython-312.pyc index 31ffff5..4be2293 100644 Binary files a/venv/Lib/site-packages/apscheduler/jobstores/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/apscheduler/jobstores/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/apscheduler/jobstores/__pycache__/base.cpython-312.pyc b/venv/Lib/site-packages/apscheduler/jobstores/__pycache__/base.cpython-312.pyc index 87cb291..2a2f6c2 100644 Binary files a/venv/Lib/site-packages/apscheduler/jobstores/__pycache__/base.cpython-312.pyc and b/venv/Lib/site-packages/apscheduler/jobstores/__pycache__/base.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/apscheduler/jobstores/__pycache__/etcd.cpython-312.pyc b/venv/Lib/site-packages/apscheduler/jobstores/__pycache__/etcd.cpython-312.pyc index 270bd55..36af4cd 100644 Binary files a/venv/Lib/site-packages/apscheduler/jobstores/__pycache__/etcd.cpython-312.pyc and b/venv/Lib/site-packages/apscheduler/jobstores/__pycache__/etcd.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/apscheduler/jobstores/__pycache__/memory.cpython-312.pyc b/venv/Lib/site-packages/apscheduler/jobstores/__pycache__/memory.cpython-312.pyc index f681741..7273941 100644 Binary files a/venv/Lib/site-packages/apscheduler/jobstores/__pycache__/memory.cpython-312.pyc and b/venv/Lib/site-packages/apscheduler/jobstores/__pycache__/memory.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/apscheduler/jobstores/__pycache__/mongodb.cpython-312.pyc b/venv/Lib/site-packages/apscheduler/jobstores/__pycache__/mongodb.cpython-312.pyc index 6d6f90f..175111b 100644 Binary files a/venv/Lib/site-packages/apscheduler/jobstores/__pycache__/mongodb.cpython-312.pyc and b/venv/Lib/site-packages/apscheduler/jobstores/__pycache__/mongodb.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/apscheduler/jobstores/__pycache__/redis.cpython-312.pyc b/venv/Lib/site-packages/apscheduler/jobstores/__pycache__/redis.cpython-312.pyc index 439cac1..5fd2865 100644 Binary files a/venv/Lib/site-packages/apscheduler/jobstores/__pycache__/redis.cpython-312.pyc and b/venv/Lib/site-packages/apscheduler/jobstores/__pycache__/redis.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/apscheduler/jobstores/__pycache__/rethinkdb.cpython-312.pyc b/venv/Lib/site-packages/apscheduler/jobstores/__pycache__/rethinkdb.cpython-312.pyc index 070c1f9..9622a71 100644 Binary files a/venv/Lib/site-packages/apscheduler/jobstores/__pycache__/rethinkdb.cpython-312.pyc and b/venv/Lib/site-packages/apscheduler/jobstores/__pycache__/rethinkdb.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/apscheduler/jobstores/__pycache__/sqlalchemy.cpython-312.pyc b/venv/Lib/site-packages/apscheduler/jobstores/__pycache__/sqlalchemy.cpython-312.pyc index 22c560f..b4a8e3e 100644 Binary files a/venv/Lib/site-packages/apscheduler/jobstores/__pycache__/sqlalchemy.cpython-312.pyc and b/venv/Lib/site-packages/apscheduler/jobstores/__pycache__/sqlalchemy.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/apscheduler/jobstores/__pycache__/zookeeper.cpython-312.pyc b/venv/Lib/site-packages/apscheduler/jobstores/__pycache__/zookeeper.cpython-312.pyc index 7c921bd..06b5475 100644 Binary files a/venv/Lib/site-packages/apscheduler/jobstores/__pycache__/zookeeper.cpython-312.pyc and b/venv/Lib/site-packages/apscheduler/jobstores/__pycache__/zookeeper.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/apscheduler/schedulers/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/apscheduler/schedulers/__pycache__/__init__.cpython-312.pyc index 7207cd8..0e36379 100644 Binary files a/venv/Lib/site-packages/apscheduler/schedulers/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/apscheduler/schedulers/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/apscheduler/schedulers/__pycache__/asyncio.cpython-312.pyc b/venv/Lib/site-packages/apscheduler/schedulers/__pycache__/asyncio.cpython-312.pyc index 1ad69a6..ad836c0 100644 Binary files a/venv/Lib/site-packages/apscheduler/schedulers/__pycache__/asyncio.cpython-312.pyc and b/venv/Lib/site-packages/apscheduler/schedulers/__pycache__/asyncio.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/apscheduler/schedulers/__pycache__/background.cpython-312.pyc b/venv/Lib/site-packages/apscheduler/schedulers/__pycache__/background.cpython-312.pyc index 30cab8f..323ebe0 100644 Binary files a/venv/Lib/site-packages/apscheduler/schedulers/__pycache__/background.cpython-312.pyc and b/venv/Lib/site-packages/apscheduler/schedulers/__pycache__/background.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/apscheduler/schedulers/__pycache__/base.cpython-312.pyc b/venv/Lib/site-packages/apscheduler/schedulers/__pycache__/base.cpython-312.pyc index 8043893..d9febdc 100644 Binary files a/venv/Lib/site-packages/apscheduler/schedulers/__pycache__/base.cpython-312.pyc and b/venv/Lib/site-packages/apscheduler/schedulers/__pycache__/base.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/apscheduler/schedulers/__pycache__/blocking.cpython-312.pyc b/venv/Lib/site-packages/apscheduler/schedulers/__pycache__/blocking.cpython-312.pyc index 7ea614a..12bb5a8 100644 Binary files a/venv/Lib/site-packages/apscheduler/schedulers/__pycache__/blocking.cpython-312.pyc and b/venv/Lib/site-packages/apscheduler/schedulers/__pycache__/blocking.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/apscheduler/schedulers/__pycache__/gevent.cpython-312.pyc b/venv/Lib/site-packages/apscheduler/schedulers/__pycache__/gevent.cpython-312.pyc index 6896433..45588bf 100644 Binary files a/venv/Lib/site-packages/apscheduler/schedulers/__pycache__/gevent.cpython-312.pyc and b/venv/Lib/site-packages/apscheduler/schedulers/__pycache__/gevent.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/apscheduler/schedulers/__pycache__/qt.cpython-312.pyc b/venv/Lib/site-packages/apscheduler/schedulers/__pycache__/qt.cpython-312.pyc index 1634142..e1ec910 100644 Binary files a/venv/Lib/site-packages/apscheduler/schedulers/__pycache__/qt.cpython-312.pyc and b/venv/Lib/site-packages/apscheduler/schedulers/__pycache__/qt.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/apscheduler/schedulers/__pycache__/tornado.cpython-312.pyc b/venv/Lib/site-packages/apscheduler/schedulers/__pycache__/tornado.cpython-312.pyc index 0ae7eae..1b9dad5 100644 Binary files a/venv/Lib/site-packages/apscheduler/schedulers/__pycache__/tornado.cpython-312.pyc and b/venv/Lib/site-packages/apscheduler/schedulers/__pycache__/tornado.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/apscheduler/schedulers/__pycache__/twisted.cpython-312.pyc b/venv/Lib/site-packages/apscheduler/schedulers/__pycache__/twisted.cpython-312.pyc index 0bea940..d1f54c5 100644 Binary files a/venv/Lib/site-packages/apscheduler/schedulers/__pycache__/twisted.cpython-312.pyc and b/venv/Lib/site-packages/apscheduler/schedulers/__pycache__/twisted.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/apscheduler/triggers/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/apscheduler/triggers/__pycache__/__init__.cpython-312.pyc index 7348e8d..ec65b87 100644 Binary files a/venv/Lib/site-packages/apscheduler/triggers/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/apscheduler/triggers/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/apscheduler/triggers/__pycache__/base.cpython-312.pyc b/venv/Lib/site-packages/apscheduler/triggers/__pycache__/base.cpython-312.pyc index 2bd9608..e0ea74c 100644 Binary files a/venv/Lib/site-packages/apscheduler/triggers/__pycache__/base.cpython-312.pyc and b/venv/Lib/site-packages/apscheduler/triggers/__pycache__/base.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/apscheduler/triggers/__pycache__/calendarinterval.cpython-312.pyc b/venv/Lib/site-packages/apscheduler/triggers/__pycache__/calendarinterval.cpython-312.pyc index 627287f..0025fd1 100644 Binary files a/venv/Lib/site-packages/apscheduler/triggers/__pycache__/calendarinterval.cpython-312.pyc and b/venv/Lib/site-packages/apscheduler/triggers/__pycache__/calendarinterval.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/apscheduler/triggers/__pycache__/combining.cpython-312.pyc b/venv/Lib/site-packages/apscheduler/triggers/__pycache__/combining.cpython-312.pyc index fa0823d..d7db2a2 100644 Binary files a/venv/Lib/site-packages/apscheduler/triggers/__pycache__/combining.cpython-312.pyc and b/venv/Lib/site-packages/apscheduler/triggers/__pycache__/combining.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/apscheduler/triggers/__pycache__/date.cpython-312.pyc b/venv/Lib/site-packages/apscheduler/triggers/__pycache__/date.cpython-312.pyc index 189e7e5..b6aabb1 100644 Binary files a/venv/Lib/site-packages/apscheduler/triggers/__pycache__/date.cpython-312.pyc and b/venv/Lib/site-packages/apscheduler/triggers/__pycache__/date.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/apscheduler/triggers/__pycache__/interval.cpython-312.pyc b/venv/Lib/site-packages/apscheduler/triggers/__pycache__/interval.cpython-312.pyc index a44dde9..d439e4f 100644 Binary files a/venv/Lib/site-packages/apscheduler/triggers/__pycache__/interval.cpython-312.pyc and b/venv/Lib/site-packages/apscheduler/triggers/__pycache__/interval.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/apscheduler/triggers/cron/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/apscheduler/triggers/cron/__pycache__/__init__.cpython-312.pyc index 4e0f2d2..4854362 100644 Binary files a/venv/Lib/site-packages/apscheduler/triggers/cron/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/apscheduler/triggers/cron/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/apscheduler/triggers/cron/__pycache__/expressions.cpython-312.pyc b/venv/Lib/site-packages/apscheduler/triggers/cron/__pycache__/expressions.cpython-312.pyc index bc9bff8..ff63b8a 100644 Binary files a/venv/Lib/site-packages/apscheduler/triggers/cron/__pycache__/expressions.cpython-312.pyc and b/venv/Lib/site-packages/apscheduler/triggers/cron/__pycache__/expressions.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/apscheduler/triggers/cron/__pycache__/fields.cpython-312.pyc b/venv/Lib/site-packages/apscheduler/triggers/cron/__pycache__/fields.cpython-312.pyc index fd5e470..f07f4cd 100644 Binary files a/venv/Lib/site-packages/apscheduler/triggers/cron/__pycache__/fields.cpython-312.pyc and b/venv/Lib/site-packages/apscheduler/triggers/cron/__pycache__/fields.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/attr/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/attr/__pycache__/__init__.cpython-312.pyc index d05bd49..ab29b73 100644 Binary files a/venv/Lib/site-packages/attr/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/attr/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/attr/__pycache__/_cmp.cpython-312.pyc b/venv/Lib/site-packages/attr/__pycache__/_cmp.cpython-312.pyc index 69cc3c8..6a9440b 100644 Binary files a/venv/Lib/site-packages/attr/__pycache__/_cmp.cpython-312.pyc and b/venv/Lib/site-packages/attr/__pycache__/_cmp.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/attr/__pycache__/_compat.cpython-312.pyc b/venv/Lib/site-packages/attr/__pycache__/_compat.cpython-312.pyc index 551c4ea..dc48665 100644 Binary files a/venv/Lib/site-packages/attr/__pycache__/_compat.cpython-312.pyc and b/venv/Lib/site-packages/attr/__pycache__/_compat.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/attr/__pycache__/_config.cpython-312.pyc b/venv/Lib/site-packages/attr/__pycache__/_config.cpython-312.pyc index 31876b0..5bef360 100644 Binary files a/venv/Lib/site-packages/attr/__pycache__/_config.cpython-312.pyc and b/venv/Lib/site-packages/attr/__pycache__/_config.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/attr/__pycache__/_funcs.cpython-312.pyc b/venv/Lib/site-packages/attr/__pycache__/_funcs.cpython-312.pyc index 320ab7a..dc3c27b 100644 Binary files a/venv/Lib/site-packages/attr/__pycache__/_funcs.cpython-312.pyc and b/venv/Lib/site-packages/attr/__pycache__/_funcs.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/attr/__pycache__/_make.cpython-312.pyc b/venv/Lib/site-packages/attr/__pycache__/_make.cpython-312.pyc index d580df4..35f9f15 100644 Binary files a/venv/Lib/site-packages/attr/__pycache__/_make.cpython-312.pyc and b/venv/Lib/site-packages/attr/__pycache__/_make.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/attr/__pycache__/_next_gen.cpython-312.pyc b/venv/Lib/site-packages/attr/__pycache__/_next_gen.cpython-312.pyc index f1e5df4..e43f0ed 100644 Binary files a/venv/Lib/site-packages/attr/__pycache__/_next_gen.cpython-312.pyc and b/venv/Lib/site-packages/attr/__pycache__/_next_gen.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/attr/__pycache__/_version_info.cpython-312.pyc b/venv/Lib/site-packages/attr/__pycache__/_version_info.cpython-312.pyc index 1f735f0..a8bcdb0 100644 Binary files a/venv/Lib/site-packages/attr/__pycache__/_version_info.cpython-312.pyc and b/venv/Lib/site-packages/attr/__pycache__/_version_info.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/attr/__pycache__/converters.cpython-312.pyc b/venv/Lib/site-packages/attr/__pycache__/converters.cpython-312.pyc index 9931a28..fc457c7 100644 Binary files a/venv/Lib/site-packages/attr/__pycache__/converters.cpython-312.pyc and b/venv/Lib/site-packages/attr/__pycache__/converters.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/attr/__pycache__/exceptions.cpython-312.pyc b/venv/Lib/site-packages/attr/__pycache__/exceptions.cpython-312.pyc index 9c85024..9919f5f 100644 Binary files a/venv/Lib/site-packages/attr/__pycache__/exceptions.cpython-312.pyc and b/venv/Lib/site-packages/attr/__pycache__/exceptions.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/attr/__pycache__/filters.cpython-312.pyc b/venv/Lib/site-packages/attr/__pycache__/filters.cpython-312.pyc index fec82e7..adbe806 100644 Binary files a/venv/Lib/site-packages/attr/__pycache__/filters.cpython-312.pyc and b/venv/Lib/site-packages/attr/__pycache__/filters.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/attr/__pycache__/setters.cpython-312.pyc b/venv/Lib/site-packages/attr/__pycache__/setters.cpython-312.pyc index 7cc1e0b..d3ef551 100644 Binary files a/venv/Lib/site-packages/attr/__pycache__/setters.cpython-312.pyc and b/venv/Lib/site-packages/attr/__pycache__/setters.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/attr/__pycache__/validators.cpython-312.pyc b/venv/Lib/site-packages/attr/__pycache__/validators.cpython-312.pyc index 4fb48de..c98e0ba 100644 Binary files a/venv/Lib/site-packages/attr/__pycache__/validators.cpython-312.pyc and b/venv/Lib/site-packages/attr/__pycache__/validators.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/attrs-25.4.0.dist-info/RECORD b/venv/Lib/site-packages/attrs-25.4.0.dist-info/RECORD index 70e06bf..e77f608 100644 --- a/venv/Lib/site-packages/attrs-25.4.0.dist-info/RECORD +++ b/venv/Lib/site-packages/attrs-25.4.0.dist-info/RECORD @@ -37,6 +37,7 @@ attr/validators.pyi,sha256=ftmW3m4KJ3pQcIXAj-BejT7BY4ZfqrC1G-5W7XvoPds,4082 attrs-25.4.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 attrs-25.4.0.dist-info/METADATA,sha256=2Rerxj7agcMRxiwdkt6lC2guqHAmkGKCH13nWWK7ZoQ,10473 attrs-25.4.0.dist-info/RECORD,, +attrs-25.4.0.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 attrs-25.4.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87 attrs-25.4.0.dist-info/licenses/LICENSE,sha256=iCEVyV38KvHutnFPjsbVy8q_Znyv-HKfQkINpj9xTp8,1109 attrs/__init__.py,sha256=RxaAZNwYiEh-fcvHLZNpQ_DWKni73M_jxEPEftiq1Zc,1183 diff --git a/venv/Lib/site-packages/attrs-25.4.0.dist-info/REQUESTED b/venv/Lib/site-packages/attrs-25.4.0.dist-info/REQUESTED new file mode 100644 index 0000000..e69de29 diff --git a/venv/Lib/site-packages/attrs/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/attrs/__pycache__/__init__.cpython-312.pyc index 32d6be9..d535453 100644 Binary files a/venv/Lib/site-packages/attrs/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/attrs/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/attrs/__pycache__/converters.cpython-312.pyc b/venv/Lib/site-packages/attrs/__pycache__/converters.cpython-312.pyc index 98b4bf7..7a73eec 100644 Binary files a/venv/Lib/site-packages/attrs/__pycache__/converters.cpython-312.pyc and b/venv/Lib/site-packages/attrs/__pycache__/converters.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/attrs/__pycache__/exceptions.cpython-312.pyc b/venv/Lib/site-packages/attrs/__pycache__/exceptions.cpython-312.pyc index 91a82fe..5eebcad 100644 Binary files a/venv/Lib/site-packages/attrs/__pycache__/exceptions.cpython-312.pyc and b/venv/Lib/site-packages/attrs/__pycache__/exceptions.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/attrs/__pycache__/filters.cpython-312.pyc b/venv/Lib/site-packages/attrs/__pycache__/filters.cpython-312.pyc index b14223c..b82fda9 100644 Binary files a/venv/Lib/site-packages/attrs/__pycache__/filters.cpython-312.pyc and b/venv/Lib/site-packages/attrs/__pycache__/filters.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/attrs/__pycache__/setters.cpython-312.pyc b/venv/Lib/site-packages/attrs/__pycache__/setters.cpython-312.pyc index a90d482..66afe8e 100644 Binary files a/venv/Lib/site-packages/attrs/__pycache__/setters.cpython-312.pyc and b/venv/Lib/site-packages/attrs/__pycache__/setters.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/attrs/__pycache__/validators.cpython-312.pyc b/venv/Lib/site-packages/attrs/__pycache__/validators.cpython-312.pyc index 272ec73..cce6f1b 100644 Binary files a/venv/Lib/site-packages/attrs/__pycache__/validators.cpython-312.pyc and b/venv/Lib/site-packages/attrs/__pycache__/validators.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/blinker-1.9.0.dist-info/RECORD b/venv/Lib/site-packages/blinker-1.9.0.dist-info/RECORD index d4f985b..2eba51c 100644 --- a/venv/Lib/site-packages/blinker-1.9.0.dist-info/RECORD +++ b/venv/Lib/site-packages/blinker-1.9.0.dist-info/RECORD @@ -2,6 +2,7 @@ blinker-1.9.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuw blinker-1.9.0.dist-info/LICENSE.txt,sha256=nrc6HzhZekqhcCXSrhvjg5Ykx5XphdTw6Xac4p-spGc,1054 blinker-1.9.0.dist-info/METADATA,sha256=uIRiM8wjjbHkCtbCyTvctU37IAZk0kEe5kxAld1dvzA,1633 blinker-1.9.0.dist-info/RECORD,, +blinker-1.9.0.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 blinker-1.9.0.dist-info/WHEEL,sha256=CpUCUxeHQbRN5UGRQHYRJorO5Af-Qy_fHMctcQ8DSGI,82 blinker/__init__.py,sha256=I2EdZqpy4LyjX17Hn1yzJGWCjeLaVaPzsMgHkLfj_cQ,317 blinker/__pycache__/__init__.cpython-312.pyc,, diff --git a/venv/Lib/site-packages/blinker-1.9.0.dist-info/REQUESTED b/venv/Lib/site-packages/blinker-1.9.0.dist-info/REQUESTED new file mode 100644 index 0000000..e69de29 diff --git a/venv/Lib/site-packages/blinker/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/blinker/__pycache__/__init__.cpython-312.pyc index 9fb4318..92ac1d3 100644 Binary files a/venv/Lib/site-packages/blinker/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/blinker/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/blinker/__pycache__/_utilities.cpython-312.pyc b/venv/Lib/site-packages/blinker/__pycache__/_utilities.cpython-312.pyc index 30401b7..9bb6514 100644 Binary files a/venv/Lib/site-packages/blinker/__pycache__/_utilities.cpython-312.pyc and b/venv/Lib/site-packages/blinker/__pycache__/_utilities.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/blinker/__pycache__/base.cpython-312.pyc b/venv/Lib/site-packages/blinker/__pycache__/base.cpython-312.pyc index 29739f1..c596458 100644 Binary files a/venv/Lib/site-packages/blinker/__pycache__/base.cpython-312.pyc and b/venv/Lib/site-packages/blinker/__pycache__/base.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/boto3/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/boto3/__pycache__/__init__.cpython-312.pyc index 243dd2f..2b3bd45 100644 Binary files a/venv/Lib/site-packages/boto3/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/boto3/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/boto3/__pycache__/compat.cpython-312.pyc b/venv/Lib/site-packages/boto3/__pycache__/compat.cpython-312.pyc index 197c8cb..8660550 100644 Binary files a/venv/Lib/site-packages/boto3/__pycache__/compat.cpython-312.pyc and b/venv/Lib/site-packages/boto3/__pycache__/compat.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/boto3/__pycache__/crt.cpython-312.pyc b/venv/Lib/site-packages/boto3/__pycache__/crt.cpython-312.pyc index cdad656..b5626e9 100644 Binary files a/venv/Lib/site-packages/boto3/__pycache__/crt.cpython-312.pyc and b/venv/Lib/site-packages/boto3/__pycache__/crt.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/boto3/__pycache__/exceptions.cpython-312.pyc b/venv/Lib/site-packages/boto3/__pycache__/exceptions.cpython-312.pyc index 43f1e79..e1440f5 100644 Binary files a/venv/Lib/site-packages/boto3/__pycache__/exceptions.cpython-312.pyc and b/venv/Lib/site-packages/boto3/__pycache__/exceptions.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/boto3/__pycache__/session.cpython-312.pyc b/venv/Lib/site-packages/boto3/__pycache__/session.cpython-312.pyc index a1198da..55517f0 100644 Binary files a/venv/Lib/site-packages/boto3/__pycache__/session.cpython-312.pyc and b/venv/Lib/site-packages/boto3/__pycache__/session.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/boto3/__pycache__/utils.cpython-312.pyc b/venv/Lib/site-packages/boto3/__pycache__/utils.cpython-312.pyc index 4ddba80..f5b50bf 100644 Binary files a/venv/Lib/site-packages/boto3/__pycache__/utils.cpython-312.pyc and b/venv/Lib/site-packages/boto3/__pycache__/utils.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/boto3/docs/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/boto3/docs/__pycache__/__init__.cpython-312.pyc index 0acdcbe..7d2b321 100644 Binary files a/venv/Lib/site-packages/boto3/docs/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/boto3/docs/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/boto3/docs/__pycache__/action.cpython-312.pyc b/venv/Lib/site-packages/boto3/docs/__pycache__/action.cpython-312.pyc index 0d6d0b0..1660527 100644 Binary files a/venv/Lib/site-packages/boto3/docs/__pycache__/action.cpython-312.pyc and b/venv/Lib/site-packages/boto3/docs/__pycache__/action.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/boto3/docs/__pycache__/attr.cpython-312.pyc b/venv/Lib/site-packages/boto3/docs/__pycache__/attr.cpython-312.pyc index 88da966..e98e6e6 100644 Binary files a/venv/Lib/site-packages/boto3/docs/__pycache__/attr.cpython-312.pyc and b/venv/Lib/site-packages/boto3/docs/__pycache__/attr.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/boto3/docs/__pycache__/base.cpython-312.pyc b/venv/Lib/site-packages/boto3/docs/__pycache__/base.cpython-312.pyc index 11d520c..2c0ff0d 100644 Binary files a/venv/Lib/site-packages/boto3/docs/__pycache__/base.cpython-312.pyc and b/venv/Lib/site-packages/boto3/docs/__pycache__/base.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/boto3/docs/__pycache__/client.cpython-312.pyc b/venv/Lib/site-packages/boto3/docs/__pycache__/client.cpython-312.pyc index 1c00542..5cf4e55 100644 Binary files a/venv/Lib/site-packages/boto3/docs/__pycache__/client.cpython-312.pyc and b/venv/Lib/site-packages/boto3/docs/__pycache__/client.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/boto3/docs/__pycache__/collection.cpython-312.pyc b/venv/Lib/site-packages/boto3/docs/__pycache__/collection.cpython-312.pyc index 37d3e62..10e3a0d 100644 Binary files a/venv/Lib/site-packages/boto3/docs/__pycache__/collection.cpython-312.pyc and b/venv/Lib/site-packages/boto3/docs/__pycache__/collection.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/boto3/docs/__pycache__/docstring.cpython-312.pyc b/venv/Lib/site-packages/boto3/docs/__pycache__/docstring.cpython-312.pyc index 82a5bac..9ba0306 100644 Binary files a/venv/Lib/site-packages/boto3/docs/__pycache__/docstring.cpython-312.pyc and b/venv/Lib/site-packages/boto3/docs/__pycache__/docstring.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/boto3/docs/__pycache__/method.cpython-312.pyc b/venv/Lib/site-packages/boto3/docs/__pycache__/method.cpython-312.pyc index 1a360bb..309f781 100644 Binary files a/venv/Lib/site-packages/boto3/docs/__pycache__/method.cpython-312.pyc and b/venv/Lib/site-packages/boto3/docs/__pycache__/method.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/boto3/docs/__pycache__/resource.cpython-312.pyc b/venv/Lib/site-packages/boto3/docs/__pycache__/resource.cpython-312.pyc index eea108d..7668212 100644 Binary files a/venv/Lib/site-packages/boto3/docs/__pycache__/resource.cpython-312.pyc and b/venv/Lib/site-packages/boto3/docs/__pycache__/resource.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/boto3/docs/__pycache__/service.cpython-312.pyc b/venv/Lib/site-packages/boto3/docs/__pycache__/service.cpython-312.pyc index 9463c51..2b05d26 100644 Binary files a/venv/Lib/site-packages/boto3/docs/__pycache__/service.cpython-312.pyc and b/venv/Lib/site-packages/boto3/docs/__pycache__/service.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/boto3/docs/__pycache__/subresource.cpython-312.pyc b/venv/Lib/site-packages/boto3/docs/__pycache__/subresource.cpython-312.pyc index db0db24..6840bce 100644 Binary files a/venv/Lib/site-packages/boto3/docs/__pycache__/subresource.cpython-312.pyc and b/venv/Lib/site-packages/boto3/docs/__pycache__/subresource.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/boto3/docs/__pycache__/utils.cpython-312.pyc b/venv/Lib/site-packages/boto3/docs/__pycache__/utils.cpython-312.pyc index 6a3a5a7..f07119e 100644 Binary files a/venv/Lib/site-packages/boto3/docs/__pycache__/utils.cpython-312.pyc and b/venv/Lib/site-packages/boto3/docs/__pycache__/utils.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/boto3/docs/__pycache__/waiter.cpython-312.pyc b/venv/Lib/site-packages/boto3/docs/__pycache__/waiter.cpython-312.pyc index 32087d3..3c5a110 100644 Binary files a/venv/Lib/site-packages/boto3/docs/__pycache__/waiter.cpython-312.pyc and b/venv/Lib/site-packages/boto3/docs/__pycache__/waiter.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/boto3/dynamodb/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/boto3/dynamodb/__pycache__/__init__.cpython-312.pyc index 8f5e7cd..f67059a 100644 Binary files a/venv/Lib/site-packages/boto3/dynamodb/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/boto3/dynamodb/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/boto3/dynamodb/__pycache__/conditions.cpython-312.pyc b/venv/Lib/site-packages/boto3/dynamodb/__pycache__/conditions.cpython-312.pyc index 641426b..967d480 100644 Binary files a/venv/Lib/site-packages/boto3/dynamodb/__pycache__/conditions.cpython-312.pyc and b/venv/Lib/site-packages/boto3/dynamodb/__pycache__/conditions.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/boto3/dynamodb/__pycache__/table.cpython-312.pyc b/venv/Lib/site-packages/boto3/dynamodb/__pycache__/table.cpython-312.pyc index 4941241..106a0a6 100644 Binary files a/venv/Lib/site-packages/boto3/dynamodb/__pycache__/table.cpython-312.pyc and b/venv/Lib/site-packages/boto3/dynamodb/__pycache__/table.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/boto3/dynamodb/__pycache__/transform.cpython-312.pyc b/venv/Lib/site-packages/boto3/dynamodb/__pycache__/transform.cpython-312.pyc index 913b2db..d05b230 100644 Binary files a/venv/Lib/site-packages/boto3/dynamodb/__pycache__/transform.cpython-312.pyc and b/venv/Lib/site-packages/boto3/dynamodb/__pycache__/transform.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/boto3/dynamodb/__pycache__/types.cpython-312.pyc b/venv/Lib/site-packages/boto3/dynamodb/__pycache__/types.cpython-312.pyc index 7e7de8e..182f27d 100644 Binary files a/venv/Lib/site-packages/boto3/dynamodb/__pycache__/types.cpython-312.pyc and b/venv/Lib/site-packages/boto3/dynamodb/__pycache__/types.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/boto3/ec2/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/boto3/ec2/__pycache__/__init__.cpython-312.pyc index e82ca82..ce79355 100644 Binary files a/venv/Lib/site-packages/boto3/ec2/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/boto3/ec2/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/boto3/ec2/__pycache__/createtags.cpython-312.pyc b/venv/Lib/site-packages/boto3/ec2/__pycache__/createtags.cpython-312.pyc index 4245527..c4f83a3 100644 Binary files a/venv/Lib/site-packages/boto3/ec2/__pycache__/createtags.cpython-312.pyc and b/venv/Lib/site-packages/boto3/ec2/__pycache__/createtags.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/boto3/ec2/__pycache__/deletetags.cpython-312.pyc b/venv/Lib/site-packages/boto3/ec2/__pycache__/deletetags.cpython-312.pyc index 8bcf7c5..8e07aa0 100644 Binary files a/venv/Lib/site-packages/boto3/ec2/__pycache__/deletetags.cpython-312.pyc and b/venv/Lib/site-packages/boto3/ec2/__pycache__/deletetags.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/boto3/resources/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/boto3/resources/__pycache__/__init__.cpython-312.pyc index 4e9336d..ab80d62 100644 Binary files a/venv/Lib/site-packages/boto3/resources/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/boto3/resources/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/boto3/resources/__pycache__/action.cpython-312.pyc b/venv/Lib/site-packages/boto3/resources/__pycache__/action.cpython-312.pyc index 364be35..6c7b7bb 100644 Binary files a/venv/Lib/site-packages/boto3/resources/__pycache__/action.cpython-312.pyc and b/venv/Lib/site-packages/boto3/resources/__pycache__/action.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/boto3/resources/__pycache__/base.cpython-312.pyc b/venv/Lib/site-packages/boto3/resources/__pycache__/base.cpython-312.pyc index 32e34f5..db8b0c6 100644 Binary files a/venv/Lib/site-packages/boto3/resources/__pycache__/base.cpython-312.pyc and b/venv/Lib/site-packages/boto3/resources/__pycache__/base.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/boto3/resources/__pycache__/collection.cpython-312.pyc b/venv/Lib/site-packages/boto3/resources/__pycache__/collection.cpython-312.pyc index 34583b7..badb454 100644 Binary files a/venv/Lib/site-packages/boto3/resources/__pycache__/collection.cpython-312.pyc and b/venv/Lib/site-packages/boto3/resources/__pycache__/collection.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/boto3/resources/__pycache__/factory.cpython-312.pyc b/venv/Lib/site-packages/boto3/resources/__pycache__/factory.cpython-312.pyc index 7caa204..50b02b8 100644 Binary files a/venv/Lib/site-packages/boto3/resources/__pycache__/factory.cpython-312.pyc and b/venv/Lib/site-packages/boto3/resources/__pycache__/factory.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/boto3/resources/__pycache__/model.cpython-312.pyc b/venv/Lib/site-packages/boto3/resources/__pycache__/model.cpython-312.pyc index 1e80482..cc3eb03 100644 Binary files a/venv/Lib/site-packages/boto3/resources/__pycache__/model.cpython-312.pyc and b/venv/Lib/site-packages/boto3/resources/__pycache__/model.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/boto3/resources/__pycache__/params.cpython-312.pyc b/venv/Lib/site-packages/boto3/resources/__pycache__/params.cpython-312.pyc index e87d69b..ac47a4d 100644 Binary files a/venv/Lib/site-packages/boto3/resources/__pycache__/params.cpython-312.pyc and b/venv/Lib/site-packages/boto3/resources/__pycache__/params.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/boto3/resources/__pycache__/response.cpython-312.pyc b/venv/Lib/site-packages/boto3/resources/__pycache__/response.cpython-312.pyc index c31375b..5222964 100644 Binary files a/venv/Lib/site-packages/boto3/resources/__pycache__/response.cpython-312.pyc and b/venv/Lib/site-packages/boto3/resources/__pycache__/response.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/boto3/s3/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/boto3/s3/__pycache__/__init__.cpython-312.pyc index 97b9a02..b973924 100644 Binary files a/venv/Lib/site-packages/boto3/s3/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/boto3/s3/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/boto3/s3/__pycache__/constants.cpython-312.pyc b/venv/Lib/site-packages/boto3/s3/__pycache__/constants.cpython-312.pyc index 107502c..4c7381b 100644 Binary files a/venv/Lib/site-packages/boto3/s3/__pycache__/constants.cpython-312.pyc and b/venv/Lib/site-packages/boto3/s3/__pycache__/constants.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/boto3/s3/__pycache__/inject.cpython-312.pyc b/venv/Lib/site-packages/boto3/s3/__pycache__/inject.cpython-312.pyc index cc44119..4390387 100644 Binary files a/venv/Lib/site-packages/boto3/s3/__pycache__/inject.cpython-312.pyc and b/venv/Lib/site-packages/boto3/s3/__pycache__/inject.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/boto3/s3/__pycache__/transfer.cpython-312.pyc b/venv/Lib/site-packages/boto3/s3/__pycache__/transfer.cpython-312.pyc index 454a26e..ca4d3a9 100644 Binary files a/venv/Lib/site-packages/boto3/s3/__pycache__/transfer.cpython-312.pyc and b/venv/Lib/site-packages/boto3/s3/__pycache__/transfer.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/botocore-1.42.25.dist-info/RECORD b/venv/Lib/site-packages/botocore-1.42.25.dist-info/RECORD index 8827c59..08ca47b 100644 --- a/venv/Lib/site-packages/botocore-1.42.25.dist-info/RECORD +++ b/venv/Lib/site-packages/botocore-1.42.25.dist-info/RECORD @@ -3,6 +3,7 @@ botocore-1.42.25.dist-info/LICENSE.txt,sha256=DVQuDIgE45qn836wDaWnYhSdxoLXgpRRKH botocore-1.42.25.dist-info/METADATA,sha256=5hIj29mEvijqqTL0qAddyWYEshDsxDglUP_w6N6VLmI,5869 botocore-1.42.25.dist-info/NOTICE,sha256=HRxabz1oyxH0-tGvqGp0UNAobxXBdu8OoEjyVbRtlbA,2467 botocore-1.42.25.dist-info/RECORD,, +botocore-1.42.25.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 botocore-1.42.25.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91 botocore-1.42.25.dist-info/top_level.txt,sha256=IdlNr9dnwi3lQt66dKnShE5HBUhIqBFqJmVhm11aijk,9 botocore/__init__.py,sha256=HeEf7LTXDjdbeGBDRQv3E9fbnG-jhil54SmUFle7z3s,8019 diff --git a/venv/Lib/site-packages/botocore-1.42.25.dist-info/REQUESTED b/venv/Lib/site-packages/botocore-1.42.25.dist-info/REQUESTED new file mode 100644 index 0000000..e69de29 diff --git a/venv/Lib/site-packages/botocore/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/botocore/__pycache__/__init__.cpython-312.pyc index 3d0fb1c..c050745 100644 Binary files a/venv/Lib/site-packages/botocore/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/botocore/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/botocore/__pycache__/args.cpython-312.pyc b/venv/Lib/site-packages/botocore/__pycache__/args.cpython-312.pyc index a58f61d..afab661 100644 Binary files a/venv/Lib/site-packages/botocore/__pycache__/args.cpython-312.pyc and b/venv/Lib/site-packages/botocore/__pycache__/args.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/botocore/__pycache__/auth.cpython-312.pyc b/venv/Lib/site-packages/botocore/__pycache__/auth.cpython-312.pyc index b64fe54..f03f709 100644 Binary files a/venv/Lib/site-packages/botocore/__pycache__/auth.cpython-312.pyc and b/venv/Lib/site-packages/botocore/__pycache__/auth.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/botocore/__pycache__/awsrequest.cpython-312.pyc b/venv/Lib/site-packages/botocore/__pycache__/awsrequest.cpython-312.pyc index e2ef39b..8634ff3 100644 Binary files a/venv/Lib/site-packages/botocore/__pycache__/awsrequest.cpython-312.pyc and b/venv/Lib/site-packages/botocore/__pycache__/awsrequest.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/botocore/__pycache__/client.cpython-312.pyc b/venv/Lib/site-packages/botocore/__pycache__/client.cpython-312.pyc index 04bcc32..d0993ff 100644 Binary files a/venv/Lib/site-packages/botocore/__pycache__/client.cpython-312.pyc and b/venv/Lib/site-packages/botocore/__pycache__/client.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/botocore/__pycache__/compat.cpython-312.pyc b/venv/Lib/site-packages/botocore/__pycache__/compat.cpython-312.pyc index 94024c4..fe34031 100644 Binary files a/venv/Lib/site-packages/botocore/__pycache__/compat.cpython-312.pyc and b/venv/Lib/site-packages/botocore/__pycache__/compat.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/botocore/__pycache__/compress.cpython-312.pyc b/venv/Lib/site-packages/botocore/__pycache__/compress.cpython-312.pyc index 7416a69..f1c4a48 100644 Binary files a/venv/Lib/site-packages/botocore/__pycache__/compress.cpython-312.pyc and b/venv/Lib/site-packages/botocore/__pycache__/compress.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/botocore/__pycache__/config.cpython-312.pyc b/venv/Lib/site-packages/botocore/__pycache__/config.cpython-312.pyc index 7374b46..aa48cb8 100644 Binary files a/venv/Lib/site-packages/botocore/__pycache__/config.cpython-312.pyc and b/venv/Lib/site-packages/botocore/__pycache__/config.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/botocore/__pycache__/configloader.cpython-312.pyc b/venv/Lib/site-packages/botocore/__pycache__/configloader.cpython-312.pyc index 3c4c76b..680d3d8 100644 Binary files a/venv/Lib/site-packages/botocore/__pycache__/configloader.cpython-312.pyc and b/venv/Lib/site-packages/botocore/__pycache__/configloader.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/botocore/__pycache__/configprovider.cpython-312.pyc b/venv/Lib/site-packages/botocore/__pycache__/configprovider.cpython-312.pyc index f009a09..15e5674 100644 Binary files a/venv/Lib/site-packages/botocore/__pycache__/configprovider.cpython-312.pyc and b/venv/Lib/site-packages/botocore/__pycache__/configprovider.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/botocore/__pycache__/context.cpython-312.pyc b/venv/Lib/site-packages/botocore/__pycache__/context.cpython-312.pyc index 5d19fe6..fc34b7f 100644 Binary files a/venv/Lib/site-packages/botocore/__pycache__/context.cpython-312.pyc and b/venv/Lib/site-packages/botocore/__pycache__/context.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/botocore/__pycache__/credentials.cpython-312.pyc b/venv/Lib/site-packages/botocore/__pycache__/credentials.cpython-312.pyc index ec7d413..a8a5369 100644 Binary files a/venv/Lib/site-packages/botocore/__pycache__/credentials.cpython-312.pyc and b/venv/Lib/site-packages/botocore/__pycache__/credentials.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/botocore/__pycache__/discovery.cpython-312.pyc b/venv/Lib/site-packages/botocore/__pycache__/discovery.cpython-312.pyc index 00721ee..4597af2 100644 Binary files a/venv/Lib/site-packages/botocore/__pycache__/discovery.cpython-312.pyc and b/venv/Lib/site-packages/botocore/__pycache__/discovery.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/botocore/__pycache__/endpoint.cpython-312.pyc b/venv/Lib/site-packages/botocore/__pycache__/endpoint.cpython-312.pyc index 7d12906..8667f29 100644 Binary files a/venv/Lib/site-packages/botocore/__pycache__/endpoint.cpython-312.pyc and b/venv/Lib/site-packages/botocore/__pycache__/endpoint.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/botocore/__pycache__/endpoint_provider.cpython-312.pyc b/venv/Lib/site-packages/botocore/__pycache__/endpoint_provider.cpython-312.pyc index c32d517..f59b644 100644 Binary files a/venv/Lib/site-packages/botocore/__pycache__/endpoint_provider.cpython-312.pyc and b/venv/Lib/site-packages/botocore/__pycache__/endpoint_provider.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/botocore/__pycache__/errorfactory.cpython-312.pyc b/venv/Lib/site-packages/botocore/__pycache__/errorfactory.cpython-312.pyc index b10254d..6baf3b1 100644 Binary files a/venv/Lib/site-packages/botocore/__pycache__/errorfactory.cpython-312.pyc and b/venv/Lib/site-packages/botocore/__pycache__/errorfactory.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/botocore/__pycache__/eventstream.cpython-312.pyc b/venv/Lib/site-packages/botocore/__pycache__/eventstream.cpython-312.pyc index a6005ee..8022885 100644 Binary files a/venv/Lib/site-packages/botocore/__pycache__/eventstream.cpython-312.pyc and b/venv/Lib/site-packages/botocore/__pycache__/eventstream.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/botocore/__pycache__/exceptions.cpython-312.pyc b/venv/Lib/site-packages/botocore/__pycache__/exceptions.cpython-312.pyc index 83b1058..b8a768f 100644 Binary files a/venv/Lib/site-packages/botocore/__pycache__/exceptions.cpython-312.pyc and b/venv/Lib/site-packages/botocore/__pycache__/exceptions.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/botocore/__pycache__/handlers.cpython-312.pyc b/venv/Lib/site-packages/botocore/__pycache__/handlers.cpython-312.pyc index 69cfce6..8cccb87 100644 Binary files a/venv/Lib/site-packages/botocore/__pycache__/handlers.cpython-312.pyc and b/venv/Lib/site-packages/botocore/__pycache__/handlers.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/botocore/__pycache__/history.cpython-312.pyc b/venv/Lib/site-packages/botocore/__pycache__/history.cpython-312.pyc index 1afd00b..a47b20c 100644 Binary files a/venv/Lib/site-packages/botocore/__pycache__/history.cpython-312.pyc and b/venv/Lib/site-packages/botocore/__pycache__/history.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/botocore/__pycache__/hooks.cpython-312.pyc b/venv/Lib/site-packages/botocore/__pycache__/hooks.cpython-312.pyc index f3c065e..a7cdfd3 100644 Binary files a/venv/Lib/site-packages/botocore/__pycache__/hooks.cpython-312.pyc and b/venv/Lib/site-packages/botocore/__pycache__/hooks.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/botocore/__pycache__/httpchecksum.cpython-312.pyc b/venv/Lib/site-packages/botocore/__pycache__/httpchecksum.cpython-312.pyc index bdd1653..104ede4 100644 Binary files a/venv/Lib/site-packages/botocore/__pycache__/httpchecksum.cpython-312.pyc and b/venv/Lib/site-packages/botocore/__pycache__/httpchecksum.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/botocore/__pycache__/httpsession.cpython-312.pyc b/venv/Lib/site-packages/botocore/__pycache__/httpsession.cpython-312.pyc index 6ae0f9a..50071d1 100644 Binary files a/venv/Lib/site-packages/botocore/__pycache__/httpsession.cpython-312.pyc and b/venv/Lib/site-packages/botocore/__pycache__/httpsession.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/botocore/__pycache__/loaders.cpython-312.pyc b/venv/Lib/site-packages/botocore/__pycache__/loaders.cpython-312.pyc index 9d4e939..393c855 100644 Binary files a/venv/Lib/site-packages/botocore/__pycache__/loaders.cpython-312.pyc and b/venv/Lib/site-packages/botocore/__pycache__/loaders.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/botocore/__pycache__/model.cpython-312.pyc b/venv/Lib/site-packages/botocore/__pycache__/model.cpython-312.pyc index 411dcd8..d8d7856 100644 Binary files a/venv/Lib/site-packages/botocore/__pycache__/model.cpython-312.pyc and b/venv/Lib/site-packages/botocore/__pycache__/model.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/botocore/__pycache__/monitoring.cpython-312.pyc b/venv/Lib/site-packages/botocore/__pycache__/monitoring.cpython-312.pyc index 4985fb1..e069317 100644 Binary files a/venv/Lib/site-packages/botocore/__pycache__/monitoring.cpython-312.pyc and b/venv/Lib/site-packages/botocore/__pycache__/monitoring.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/botocore/__pycache__/paginate.cpython-312.pyc b/venv/Lib/site-packages/botocore/__pycache__/paginate.cpython-312.pyc index 03dab69..73e930d 100644 Binary files a/venv/Lib/site-packages/botocore/__pycache__/paginate.cpython-312.pyc and b/venv/Lib/site-packages/botocore/__pycache__/paginate.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/botocore/__pycache__/parsers.cpython-312.pyc b/venv/Lib/site-packages/botocore/__pycache__/parsers.cpython-312.pyc index c1257a8..53bb032 100644 Binary files a/venv/Lib/site-packages/botocore/__pycache__/parsers.cpython-312.pyc and b/venv/Lib/site-packages/botocore/__pycache__/parsers.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/botocore/__pycache__/plugin.cpython-312.pyc b/venv/Lib/site-packages/botocore/__pycache__/plugin.cpython-312.pyc index ca29cf5..1905113 100644 Binary files a/venv/Lib/site-packages/botocore/__pycache__/plugin.cpython-312.pyc and b/venv/Lib/site-packages/botocore/__pycache__/plugin.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/botocore/__pycache__/regions.cpython-312.pyc b/venv/Lib/site-packages/botocore/__pycache__/regions.cpython-312.pyc index 1b51ec8..c97661d 100644 Binary files a/venv/Lib/site-packages/botocore/__pycache__/regions.cpython-312.pyc and b/venv/Lib/site-packages/botocore/__pycache__/regions.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/botocore/__pycache__/response.cpython-312.pyc b/venv/Lib/site-packages/botocore/__pycache__/response.cpython-312.pyc index 4b9ff61..8ad64ae 100644 Binary files a/venv/Lib/site-packages/botocore/__pycache__/response.cpython-312.pyc and b/venv/Lib/site-packages/botocore/__pycache__/response.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/botocore/__pycache__/retryhandler.cpython-312.pyc b/venv/Lib/site-packages/botocore/__pycache__/retryhandler.cpython-312.pyc index 30cf464..3db63e6 100644 Binary files a/venv/Lib/site-packages/botocore/__pycache__/retryhandler.cpython-312.pyc and b/venv/Lib/site-packages/botocore/__pycache__/retryhandler.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/botocore/__pycache__/serialize.cpython-312.pyc b/venv/Lib/site-packages/botocore/__pycache__/serialize.cpython-312.pyc index b53e716..3be0de5 100644 Binary files a/venv/Lib/site-packages/botocore/__pycache__/serialize.cpython-312.pyc and b/venv/Lib/site-packages/botocore/__pycache__/serialize.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/botocore/__pycache__/session.cpython-312.pyc b/venv/Lib/site-packages/botocore/__pycache__/session.cpython-312.pyc index 2a10596..e6e18dc 100644 Binary files a/venv/Lib/site-packages/botocore/__pycache__/session.cpython-312.pyc and b/venv/Lib/site-packages/botocore/__pycache__/session.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/botocore/__pycache__/signers.cpython-312.pyc b/venv/Lib/site-packages/botocore/__pycache__/signers.cpython-312.pyc index 61f5201..64eafd7 100644 Binary files a/venv/Lib/site-packages/botocore/__pycache__/signers.cpython-312.pyc and b/venv/Lib/site-packages/botocore/__pycache__/signers.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/botocore/__pycache__/stub.cpython-312.pyc b/venv/Lib/site-packages/botocore/__pycache__/stub.cpython-312.pyc index 695f7d0..f63e91c 100644 Binary files a/venv/Lib/site-packages/botocore/__pycache__/stub.cpython-312.pyc and b/venv/Lib/site-packages/botocore/__pycache__/stub.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/botocore/__pycache__/tokens.cpython-312.pyc b/venv/Lib/site-packages/botocore/__pycache__/tokens.cpython-312.pyc index edf2f1b..1ad4cae 100644 Binary files a/venv/Lib/site-packages/botocore/__pycache__/tokens.cpython-312.pyc and b/venv/Lib/site-packages/botocore/__pycache__/tokens.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/botocore/__pycache__/translate.cpython-312.pyc b/venv/Lib/site-packages/botocore/__pycache__/translate.cpython-312.pyc index 8537361..164f861 100644 Binary files a/venv/Lib/site-packages/botocore/__pycache__/translate.cpython-312.pyc and b/venv/Lib/site-packages/botocore/__pycache__/translate.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/botocore/__pycache__/useragent.cpython-312.pyc b/venv/Lib/site-packages/botocore/__pycache__/useragent.cpython-312.pyc index 6d42af4..d3cf767 100644 Binary files a/venv/Lib/site-packages/botocore/__pycache__/useragent.cpython-312.pyc and b/venv/Lib/site-packages/botocore/__pycache__/useragent.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/botocore/__pycache__/utils.cpython-312.pyc b/venv/Lib/site-packages/botocore/__pycache__/utils.cpython-312.pyc index d66bc14..adeaeb9 100644 Binary files a/venv/Lib/site-packages/botocore/__pycache__/utils.cpython-312.pyc and b/venv/Lib/site-packages/botocore/__pycache__/utils.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/botocore/__pycache__/validate.cpython-312.pyc b/venv/Lib/site-packages/botocore/__pycache__/validate.cpython-312.pyc index 4c4e43c..d5d48ff 100644 Binary files a/venv/Lib/site-packages/botocore/__pycache__/validate.cpython-312.pyc and b/venv/Lib/site-packages/botocore/__pycache__/validate.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/botocore/__pycache__/waiter.cpython-312.pyc b/venv/Lib/site-packages/botocore/__pycache__/waiter.cpython-312.pyc index 0fba6d3..0c7099f 100644 Binary files a/venv/Lib/site-packages/botocore/__pycache__/waiter.cpython-312.pyc and b/venv/Lib/site-packages/botocore/__pycache__/waiter.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/botocore/crt/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/botocore/crt/__pycache__/__init__.cpython-312.pyc index bb86509..51711ac 100644 Binary files a/venv/Lib/site-packages/botocore/crt/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/botocore/crt/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/botocore/crt/__pycache__/auth.cpython-312.pyc b/venv/Lib/site-packages/botocore/crt/__pycache__/auth.cpython-312.pyc index 171ff90..9ef4039 100644 Binary files a/venv/Lib/site-packages/botocore/crt/__pycache__/auth.cpython-312.pyc and b/venv/Lib/site-packages/botocore/crt/__pycache__/auth.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/botocore/docs/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/botocore/docs/__pycache__/__init__.cpython-312.pyc index 1377e50..71ca571 100644 Binary files a/venv/Lib/site-packages/botocore/docs/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/botocore/docs/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/botocore/docs/__pycache__/client.cpython-312.pyc b/venv/Lib/site-packages/botocore/docs/__pycache__/client.cpython-312.pyc index 5ff9e84..854d76c 100644 Binary files a/venv/Lib/site-packages/botocore/docs/__pycache__/client.cpython-312.pyc and b/venv/Lib/site-packages/botocore/docs/__pycache__/client.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/botocore/docs/__pycache__/docstring.cpython-312.pyc b/venv/Lib/site-packages/botocore/docs/__pycache__/docstring.cpython-312.pyc index e56af1e..363473c 100644 Binary files a/venv/Lib/site-packages/botocore/docs/__pycache__/docstring.cpython-312.pyc and b/venv/Lib/site-packages/botocore/docs/__pycache__/docstring.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/botocore/docs/__pycache__/example.cpython-312.pyc b/venv/Lib/site-packages/botocore/docs/__pycache__/example.cpython-312.pyc index ca0f160..c59e61a 100644 Binary files a/venv/Lib/site-packages/botocore/docs/__pycache__/example.cpython-312.pyc and b/venv/Lib/site-packages/botocore/docs/__pycache__/example.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/botocore/docs/__pycache__/method.cpython-312.pyc b/venv/Lib/site-packages/botocore/docs/__pycache__/method.cpython-312.pyc index 0ddc30d..a9e2e23 100644 Binary files a/venv/Lib/site-packages/botocore/docs/__pycache__/method.cpython-312.pyc and b/venv/Lib/site-packages/botocore/docs/__pycache__/method.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/botocore/docs/__pycache__/paginator.cpython-312.pyc b/venv/Lib/site-packages/botocore/docs/__pycache__/paginator.cpython-312.pyc index b7fb5e2..f7fa97a 100644 Binary files a/venv/Lib/site-packages/botocore/docs/__pycache__/paginator.cpython-312.pyc and b/venv/Lib/site-packages/botocore/docs/__pycache__/paginator.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/botocore/docs/__pycache__/params.cpython-312.pyc b/venv/Lib/site-packages/botocore/docs/__pycache__/params.cpython-312.pyc index 3c62b38..9ded756 100644 Binary files a/venv/Lib/site-packages/botocore/docs/__pycache__/params.cpython-312.pyc and b/venv/Lib/site-packages/botocore/docs/__pycache__/params.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/botocore/docs/__pycache__/service.cpython-312.pyc b/venv/Lib/site-packages/botocore/docs/__pycache__/service.cpython-312.pyc index 672518f..18fcd86 100644 Binary files a/venv/Lib/site-packages/botocore/docs/__pycache__/service.cpython-312.pyc and b/venv/Lib/site-packages/botocore/docs/__pycache__/service.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/botocore/docs/__pycache__/shape.cpython-312.pyc b/venv/Lib/site-packages/botocore/docs/__pycache__/shape.cpython-312.pyc index 8906f7b..051f3ac 100644 Binary files a/venv/Lib/site-packages/botocore/docs/__pycache__/shape.cpython-312.pyc and b/venv/Lib/site-packages/botocore/docs/__pycache__/shape.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/botocore/docs/__pycache__/sharedexample.cpython-312.pyc b/venv/Lib/site-packages/botocore/docs/__pycache__/sharedexample.cpython-312.pyc index 4208ee1..926907f 100644 Binary files a/venv/Lib/site-packages/botocore/docs/__pycache__/sharedexample.cpython-312.pyc and b/venv/Lib/site-packages/botocore/docs/__pycache__/sharedexample.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/botocore/docs/__pycache__/translator.cpython-312.pyc b/venv/Lib/site-packages/botocore/docs/__pycache__/translator.cpython-312.pyc index a833af1..4ee5ceb 100644 Binary files a/venv/Lib/site-packages/botocore/docs/__pycache__/translator.cpython-312.pyc and b/venv/Lib/site-packages/botocore/docs/__pycache__/translator.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/botocore/docs/__pycache__/utils.cpython-312.pyc b/venv/Lib/site-packages/botocore/docs/__pycache__/utils.cpython-312.pyc index d5abcc2..9fa4793 100644 Binary files a/venv/Lib/site-packages/botocore/docs/__pycache__/utils.cpython-312.pyc and b/venv/Lib/site-packages/botocore/docs/__pycache__/utils.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/botocore/docs/__pycache__/waiter.cpython-312.pyc b/venv/Lib/site-packages/botocore/docs/__pycache__/waiter.cpython-312.pyc index 31c25d4..9da93ab 100644 Binary files a/venv/Lib/site-packages/botocore/docs/__pycache__/waiter.cpython-312.pyc and b/venv/Lib/site-packages/botocore/docs/__pycache__/waiter.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/botocore/docs/bcdoc/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/botocore/docs/bcdoc/__pycache__/__init__.cpython-312.pyc index 168a1a2..69b31e4 100644 Binary files a/venv/Lib/site-packages/botocore/docs/bcdoc/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/botocore/docs/bcdoc/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/botocore/docs/bcdoc/__pycache__/docstringparser.cpython-312.pyc b/venv/Lib/site-packages/botocore/docs/bcdoc/__pycache__/docstringparser.cpython-312.pyc index d3b6ab7..82648cb 100644 Binary files a/venv/Lib/site-packages/botocore/docs/bcdoc/__pycache__/docstringparser.cpython-312.pyc and b/venv/Lib/site-packages/botocore/docs/bcdoc/__pycache__/docstringparser.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/botocore/docs/bcdoc/__pycache__/restdoc.cpython-312.pyc b/venv/Lib/site-packages/botocore/docs/bcdoc/__pycache__/restdoc.cpython-312.pyc index d5931da..6f1560e 100644 Binary files a/venv/Lib/site-packages/botocore/docs/bcdoc/__pycache__/restdoc.cpython-312.pyc and b/venv/Lib/site-packages/botocore/docs/bcdoc/__pycache__/restdoc.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/botocore/docs/bcdoc/__pycache__/style.cpython-312.pyc b/venv/Lib/site-packages/botocore/docs/bcdoc/__pycache__/style.cpython-312.pyc index be254cc..a5df2bb 100644 Binary files a/venv/Lib/site-packages/botocore/docs/bcdoc/__pycache__/style.cpython-312.pyc and b/venv/Lib/site-packages/botocore/docs/bcdoc/__pycache__/style.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/botocore/retries/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/botocore/retries/__pycache__/__init__.cpython-312.pyc index f3a4292..49d9df4 100644 Binary files a/venv/Lib/site-packages/botocore/retries/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/botocore/retries/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/botocore/retries/__pycache__/adaptive.cpython-312.pyc b/venv/Lib/site-packages/botocore/retries/__pycache__/adaptive.cpython-312.pyc index ed0526e..2bb88a9 100644 Binary files a/venv/Lib/site-packages/botocore/retries/__pycache__/adaptive.cpython-312.pyc and b/venv/Lib/site-packages/botocore/retries/__pycache__/adaptive.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/botocore/retries/__pycache__/base.cpython-312.pyc b/venv/Lib/site-packages/botocore/retries/__pycache__/base.cpython-312.pyc index b7cca0a..735d569 100644 Binary files a/venv/Lib/site-packages/botocore/retries/__pycache__/base.cpython-312.pyc and b/venv/Lib/site-packages/botocore/retries/__pycache__/base.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/botocore/retries/__pycache__/bucket.cpython-312.pyc b/venv/Lib/site-packages/botocore/retries/__pycache__/bucket.cpython-312.pyc index 27344f6..f0233fb 100644 Binary files a/venv/Lib/site-packages/botocore/retries/__pycache__/bucket.cpython-312.pyc and b/venv/Lib/site-packages/botocore/retries/__pycache__/bucket.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/botocore/retries/__pycache__/quota.cpython-312.pyc b/venv/Lib/site-packages/botocore/retries/__pycache__/quota.cpython-312.pyc index d7cd88c..4afc539 100644 Binary files a/venv/Lib/site-packages/botocore/retries/__pycache__/quota.cpython-312.pyc and b/venv/Lib/site-packages/botocore/retries/__pycache__/quota.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/botocore/retries/__pycache__/special.cpython-312.pyc b/venv/Lib/site-packages/botocore/retries/__pycache__/special.cpython-312.pyc index bd76210..40825c0 100644 Binary files a/venv/Lib/site-packages/botocore/retries/__pycache__/special.cpython-312.pyc and b/venv/Lib/site-packages/botocore/retries/__pycache__/special.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/botocore/retries/__pycache__/standard.cpython-312.pyc b/venv/Lib/site-packages/botocore/retries/__pycache__/standard.cpython-312.pyc index 02b2874..61cd30d 100644 Binary files a/venv/Lib/site-packages/botocore/retries/__pycache__/standard.cpython-312.pyc and b/venv/Lib/site-packages/botocore/retries/__pycache__/standard.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/botocore/retries/__pycache__/throttling.cpython-312.pyc b/venv/Lib/site-packages/botocore/retries/__pycache__/throttling.cpython-312.pyc index 71bd4de..13c9744 100644 Binary files a/venv/Lib/site-packages/botocore/retries/__pycache__/throttling.cpython-312.pyc and b/venv/Lib/site-packages/botocore/retries/__pycache__/throttling.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/botocore/vendored/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/botocore/vendored/__pycache__/__init__.cpython-312.pyc index 9c51ab4..3ee2a24 100644 Binary files a/venv/Lib/site-packages/botocore/vendored/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/botocore/vendored/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/botocore/vendored/__pycache__/six.cpython-312.pyc b/venv/Lib/site-packages/botocore/vendored/__pycache__/six.cpython-312.pyc index a3dbc03..297a1e1 100644 Binary files a/venv/Lib/site-packages/botocore/vendored/__pycache__/six.cpython-312.pyc and b/venv/Lib/site-packages/botocore/vendored/__pycache__/six.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/botocore/vendored/requests/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/botocore/vendored/requests/__pycache__/__init__.cpython-312.pyc index f338ac6..143517b 100644 Binary files a/venv/Lib/site-packages/botocore/vendored/requests/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/botocore/vendored/requests/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/botocore/vendored/requests/__pycache__/exceptions.cpython-312.pyc b/venv/Lib/site-packages/botocore/vendored/requests/__pycache__/exceptions.cpython-312.pyc index 103ead2..fb8d22c 100644 Binary files a/venv/Lib/site-packages/botocore/vendored/requests/__pycache__/exceptions.cpython-312.pyc and b/venv/Lib/site-packages/botocore/vendored/requests/__pycache__/exceptions.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/botocore/vendored/requests/packages/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/botocore/vendored/requests/packages/__pycache__/__init__.cpython-312.pyc index c7a54ff..91a5865 100644 Binary files a/venv/Lib/site-packages/botocore/vendored/requests/packages/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/botocore/vendored/requests/packages/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/botocore/vendored/requests/packages/urllib3/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/botocore/vendored/requests/packages/urllib3/__pycache__/__init__.cpython-312.pyc index cb2f05c..def83e4 100644 Binary files a/venv/Lib/site-packages/botocore/vendored/requests/packages/urllib3/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/botocore/vendored/requests/packages/urllib3/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/botocore/vendored/requests/packages/urllib3/__pycache__/exceptions.cpython-312.pyc b/venv/Lib/site-packages/botocore/vendored/requests/packages/urllib3/__pycache__/exceptions.cpython-312.pyc index 6937bb3..effd9fc 100644 Binary files a/venv/Lib/site-packages/botocore/vendored/requests/packages/urllib3/__pycache__/exceptions.cpython-312.pyc and b/venv/Lib/site-packages/botocore/vendored/requests/packages/urllib3/__pycache__/exceptions.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/certifi-2026.1.4.dist-info/RECORD b/venv/Lib/site-packages/certifi-2026.1.4.dist-info/RECORD index d591898..87a9de0 100644 --- a/venv/Lib/site-packages/certifi-2026.1.4.dist-info/RECORD +++ b/venv/Lib/site-packages/certifi-2026.1.4.dist-info/RECORD @@ -1,6 +1,7 @@ certifi-2026.1.4.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 certifi-2026.1.4.dist-info/METADATA,sha256=FSfJEfKuMo6bJlofUrtRpn4PFTYtbYyXpHN_A3ZFpIY,2473 certifi-2026.1.4.dist-info/RECORD,, +certifi-2026.1.4.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 certifi-2026.1.4.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91 certifi-2026.1.4.dist-info/licenses/LICENSE,sha256=6TcW2mucDVpKHfYP5pWzcPBpVgPSH2-D8FPkLPwQyvc,989 certifi-2026.1.4.dist-info/top_level.txt,sha256=KMu4vUCfsjLrkPbSNdgdekS-pVJzBAJFO__nI8NF6-U,8 diff --git a/venv/Lib/site-packages/certifi-2026.1.4.dist-info/REQUESTED b/venv/Lib/site-packages/certifi-2026.1.4.dist-info/REQUESTED new file mode 100644 index 0000000..e69de29 diff --git a/venv/Lib/site-packages/certifi/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/certifi/__pycache__/__init__.cpython-312.pyc index fcad540..9027f50 100644 Binary files a/venv/Lib/site-packages/certifi/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/certifi/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/certifi/__pycache__/__main__.cpython-312.pyc b/venv/Lib/site-packages/certifi/__pycache__/__main__.cpython-312.pyc index 4e73e77..bd7962a 100644 Binary files a/venv/Lib/site-packages/certifi/__pycache__/__main__.cpython-312.pyc and b/venv/Lib/site-packages/certifi/__pycache__/__main__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/certifi/__pycache__/core.cpython-312.pyc b/venv/Lib/site-packages/certifi/__pycache__/core.cpython-312.pyc index 6ce3cb6..e794e25 100644 Binary files a/venv/Lib/site-packages/certifi/__pycache__/core.cpython-312.pyc and b/venv/Lib/site-packages/certifi/__pycache__/core.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/cffi-2.0.0.dist-info/RECORD b/venv/Lib/site-packages/cffi-2.0.0.dist-info/RECORD index b44794d..6e04ab3 100644 --- a/venv/Lib/site-packages/cffi-2.0.0.dist-info/RECORD +++ b/venv/Lib/site-packages/cffi-2.0.0.dist-info/RECORD @@ -2,6 +2,7 @@ _cffi_backend.cp312-win_amd64.pyd,sha256=U940r8OTnYG_JJi3dCXFLiw_MWT4z-JUPTrMjyQ cffi-2.0.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 cffi-2.0.0.dist-info/METADATA,sha256=ZET6EC-RAp729tW1o4YJl61x9srq0O0A_tZ4N3Mi3uc,2627 cffi-2.0.0.dist-info/RECORD,, +cffi-2.0.0.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 cffi-2.0.0.dist-info/WHEEL,sha256=8UP9x9puWI0P1V_d7K2oMTBqfeLNm21CTzZ_Ptr0NXU,101 cffi-2.0.0.dist-info/entry_points.txt,sha256=y6jTxnyeuLnL-XJcDv8uML3n6wyYiGRg8MTp_QGJ9Ho,75 cffi-2.0.0.dist-info/licenses/AUTHORS,sha256=KmemC7-zN1nWfWRf8TG45ta8TK_CMtdR_Kw-2k0xTMg,208 diff --git a/venv/Lib/site-packages/cffi-2.0.0.dist-info/REQUESTED b/venv/Lib/site-packages/cffi-2.0.0.dist-info/REQUESTED new file mode 100644 index 0000000..e69de29 diff --git a/venv/Lib/site-packages/cffi/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/cffi/__pycache__/__init__.cpython-312.pyc index eb2689b..abd928b 100644 Binary files a/venv/Lib/site-packages/cffi/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/cffi/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/cffi/__pycache__/_imp_emulation.cpython-312.pyc b/venv/Lib/site-packages/cffi/__pycache__/_imp_emulation.cpython-312.pyc index 47b52ce..d4b7065 100644 Binary files a/venv/Lib/site-packages/cffi/__pycache__/_imp_emulation.cpython-312.pyc and b/venv/Lib/site-packages/cffi/__pycache__/_imp_emulation.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/cffi/__pycache__/_shimmed_dist_utils.cpython-312.pyc b/venv/Lib/site-packages/cffi/__pycache__/_shimmed_dist_utils.cpython-312.pyc index ed4b936..1d7d360 100644 Binary files a/venv/Lib/site-packages/cffi/__pycache__/_shimmed_dist_utils.cpython-312.pyc and b/venv/Lib/site-packages/cffi/__pycache__/_shimmed_dist_utils.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/cffi/__pycache__/api.cpython-312.pyc b/venv/Lib/site-packages/cffi/__pycache__/api.cpython-312.pyc index 2954ed0..89b88b2 100644 Binary files a/venv/Lib/site-packages/cffi/__pycache__/api.cpython-312.pyc and b/venv/Lib/site-packages/cffi/__pycache__/api.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/cffi/__pycache__/backend_ctypes.cpython-312.pyc b/venv/Lib/site-packages/cffi/__pycache__/backend_ctypes.cpython-312.pyc index 7286707..d510a74 100644 Binary files a/venv/Lib/site-packages/cffi/__pycache__/backend_ctypes.cpython-312.pyc and b/venv/Lib/site-packages/cffi/__pycache__/backend_ctypes.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/cffi/__pycache__/cffi_opcode.cpython-312.pyc b/venv/Lib/site-packages/cffi/__pycache__/cffi_opcode.cpython-312.pyc index da10d68..7382d70 100644 Binary files a/venv/Lib/site-packages/cffi/__pycache__/cffi_opcode.cpython-312.pyc and b/venv/Lib/site-packages/cffi/__pycache__/cffi_opcode.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/cffi/__pycache__/commontypes.cpython-312.pyc b/venv/Lib/site-packages/cffi/__pycache__/commontypes.cpython-312.pyc index 8754da1..bda7aa5 100644 Binary files a/venv/Lib/site-packages/cffi/__pycache__/commontypes.cpython-312.pyc and b/venv/Lib/site-packages/cffi/__pycache__/commontypes.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/cffi/__pycache__/cparser.cpython-312.pyc b/venv/Lib/site-packages/cffi/__pycache__/cparser.cpython-312.pyc index 6bdec1b..8f32eed 100644 Binary files a/venv/Lib/site-packages/cffi/__pycache__/cparser.cpython-312.pyc and b/venv/Lib/site-packages/cffi/__pycache__/cparser.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/cffi/__pycache__/error.cpython-312.pyc b/venv/Lib/site-packages/cffi/__pycache__/error.cpython-312.pyc index a8da130..fc9bae1 100644 Binary files a/venv/Lib/site-packages/cffi/__pycache__/error.cpython-312.pyc and b/venv/Lib/site-packages/cffi/__pycache__/error.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/cffi/__pycache__/ffiplatform.cpython-312.pyc b/venv/Lib/site-packages/cffi/__pycache__/ffiplatform.cpython-312.pyc index 526b276..db94674 100644 Binary files a/venv/Lib/site-packages/cffi/__pycache__/ffiplatform.cpython-312.pyc and b/venv/Lib/site-packages/cffi/__pycache__/ffiplatform.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/cffi/__pycache__/lock.cpython-312.pyc b/venv/Lib/site-packages/cffi/__pycache__/lock.cpython-312.pyc index 315f563..1269622 100644 Binary files a/venv/Lib/site-packages/cffi/__pycache__/lock.cpython-312.pyc and b/venv/Lib/site-packages/cffi/__pycache__/lock.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/cffi/__pycache__/model.cpython-312.pyc b/venv/Lib/site-packages/cffi/__pycache__/model.cpython-312.pyc index 16c770c..cffdb21 100644 Binary files a/venv/Lib/site-packages/cffi/__pycache__/model.cpython-312.pyc and b/venv/Lib/site-packages/cffi/__pycache__/model.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/cffi/__pycache__/pkgconfig.cpython-312.pyc b/venv/Lib/site-packages/cffi/__pycache__/pkgconfig.cpython-312.pyc index 90ba533..68a84cf 100644 Binary files a/venv/Lib/site-packages/cffi/__pycache__/pkgconfig.cpython-312.pyc and b/venv/Lib/site-packages/cffi/__pycache__/pkgconfig.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/cffi/__pycache__/recompiler.cpython-312.pyc b/venv/Lib/site-packages/cffi/__pycache__/recompiler.cpython-312.pyc index a2f2efa..8f3450f 100644 Binary files a/venv/Lib/site-packages/cffi/__pycache__/recompiler.cpython-312.pyc and b/venv/Lib/site-packages/cffi/__pycache__/recompiler.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/cffi/__pycache__/setuptools_ext.cpython-312.pyc b/venv/Lib/site-packages/cffi/__pycache__/setuptools_ext.cpython-312.pyc index badb05e..ba0d66e 100644 Binary files a/venv/Lib/site-packages/cffi/__pycache__/setuptools_ext.cpython-312.pyc and b/venv/Lib/site-packages/cffi/__pycache__/setuptools_ext.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/cffi/__pycache__/vengine_cpy.cpython-312.pyc b/venv/Lib/site-packages/cffi/__pycache__/vengine_cpy.cpython-312.pyc index 799daa2..11bdf9f 100644 Binary files a/venv/Lib/site-packages/cffi/__pycache__/vengine_cpy.cpython-312.pyc and b/venv/Lib/site-packages/cffi/__pycache__/vengine_cpy.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/cffi/__pycache__/vengine_gen.cpython-312.pyc b/venv/Lib/site-packages/cffi/__pycache__/vengine_gen.cpython-312.pyc index 4787744..1c323b4 100644 Binary files a/venv/Lib/site-packages/cffi/__pycache__/vengine_gen.cpython-312.pyc and b/venv/Lib/site-packages/cffi/__pycache__/vengine_gen.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/cffi/__pycache__/verifier.cpython-312.pyc b/venv/Lib/site-packages/cffi/__pycache__/verifier.cpython-312.pyc index da67621..76902ca 100644 Binary files a/venv/Lib/site-packages/cffi/__pycache__/verifier.cpython-312.pyc and b/venv/Lib/site-packages/cffi/__pycache__/verifier.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/charset_normalizer-3.4.4.dist-info/RECORD b/venv/Lib/site-packages/charset_normalizer-3.4.4.dist-info/RECORD index dfa0299..f8d68fc 100644 --- a/venv/Lib/site-packages/charset_normalizer-3.4.4.dist-info/RECORD +++ b/venv/Lib/site-packages/charset_normalizer-3.4.4.dist-info/RECORD @@ -1,7 +1,8 @@ -../../Scripts/normalizer.exe,sha256=nNqWiS9uuvMDewF9IIk7aPuSNN235MWriQozVbWcR5c,108404 +../../Scripts/normalizer.exe,sha256=cmHBk2yUw25KOJDRjGLUO2K4ezV8239Po6fXAiI0WY8,108402 charset_normalizer-3.4.4.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 charset_normalizer-3.4.4.dist-info/METADATA,sha256=Mg5oc0yfpVMtDcprHt_pPbbV0qUSHEeaEz4NG53pmyY,38067 charset_normalizer-3.4.4.dist-info/RECORD,, +charset_normalizer-3.4.4.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 charset_normalizer-3.4.4.dist-info/WHEEL,sha256=8UP9x9puWI0P1V_d7K2oMTBqfeLNm21CTzZ_Ptr0NXU,101 charset_normalizer-3.4.4.dist-info/entry_points.txt,sha256=ADSTKrkXZ3hhdOVFi6DcUEHQRS0xfxDIE_pEz4wLIXA,65 charset_normalizer-3.4.4.dist-info/licenses/LICENSE,sha256=GFd0hdNwTxpHne2OVzwJds_tMV_S_ReYP6mI2kwvcNE,1092 diff --git a/venv/Lib/site-packages/charset_normalizer-3.4.4.dist-info/REQUESTED b/venv/Lib/site-packages/charset_normalizer-3.4.4.dist-info/REQUESTED new file mode 100644 index 0000000..e69de29 diff --git a/venv/Lib/site-packages/charset_normalizer/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/charset_normalizer/__pycache__/__init__.cpython-312.pyc index d73ea53..af3681b 100644 Binary files a/venv/Lib/site-packages/charset_normalizer/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/charset_normalizer/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/charset_normalizer/__pycache__/__main__.cpython-312.pyc b/venv/Lib/site-packages/charset_normalizer/__pycache__/__main__.cpython-312.pyc index a37b8cb..f174834 100644 Binary files a/venv/Lib/site-packages/charset_normalizer/__pycache__/__main__.cpython-312.pyc and b/venv/Lib/site-packages/charset_normalizer/__pycache__/__main__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/charset_normalizer/__pycache__/api.cpython-312.pyc b/venv/Lib/site-packages/charset_normalizer/__pycache__/api.cpython-312.pyc index 2eadbb2..1235a95 100644 Binary files a/venv/Lib/site-packages/charset_normalizer/__pycache__/api.cpython-312.pyc and b/venv/Lib/site-packages/charset_normalizer/__pycache__/api.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/charset_normalizer/__pycache__/cd.cpython-312.pyc b/venv/Lib/site-packages/charset_normalizer/__pycache__/cd.cpython-312.pyc index ad88460..ea831e9 100644 Binary files a/venv/Lib/site-packages/charset_normalizer/__pycache__/cd.cpython-312.pyc and b/venv/Lib/site-packages/charset_normalizer/__pycache__/cd.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/charset_normalizer/__pycache__/constant.cpython-312.pyc b/venv/Lib/site-packages/charset_normalizer/__pycache__/constant.cpython-312.pyc index 4de4e0a..c550086 100644 Binary files a/venv/Lib/site-packages/charset_normalizer/__pycache__/constant.cpython-312.pyc and b/venv/Lib/site-packages/charset_normalizer/__pycache__/constant.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/charset_normalizer/__pycache__/legacy.cpython-312.pyc b/venv/Lib/site-packages/charset_normalizer/__pycache__/legacy.cpython-312.pyc index 32170ef..c7e381b 100644 Binary files a/venv/Lib/site-packages/charset_normalizer/__pycache__/legacy.cpython-312.pyc and b/venv/Lib/site-packages/charset_normalizer/__pycache__/legacy.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/charset_normalizer/__pycache__/md.cpython-312.pyc b/venv/Lib/site-packages/charset_normalizer/__pycache__/md.cpython-312.pyc index f124052..339e032 100644 Binary files a/venv/Lib/site-packages/charset_normalizer/__pycache__/md.cpython-312.pyc and b/venv/Lib/site-packages/charset_normalizer/__pycache__/md.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/charset_normalizer/__pycache__/models.cpython-312.pyc b/venv/Lib/site-packages/charset_normalizer/__pycache__/models.cpython-312.pyc index 2d1aa06..8bf261a 100644 Binary files a/venv/Lib/site-packages/charset_normalizer/__pycache__/models.cpython-312.pyc and b/venv/Lib/site-packages/charset_normalizer/__pycache__/models.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/charset_normalizer/__pycache__/utils.cpython-312.pyc b/venv/Lib/site-packages/charset_normalizer/__pycache__/utils.cpython-312.pyc index 9b32e39..ab34031 100644 Binary files a/venv/Lib/site-packages/charset_normalizer/__pycache__/utils.cpython-312.pyc and b/venv/Lib/site-packages/charset_normalizer/__pycache__/utils.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/charset_normalizer/__pycache__/version.cpython-312.pyc b/venv/Lib/site-packages/charset_normalizer/__pycache__/version.cpython-312.pyc index df00ac1..5c30288 100644 Binary files a/venv/Lib/site-packages/charset_normalizer/__pycache__/version.cpython-312.pyc and b/venv/Lib/site-packages/charset_normalizer/__pycache__/version.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/charset_normalizer/cli/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/charset_normalizer/cli/__pycache__/__init__.cpython-312.pyc index 508ced8..3396607 100644 Binary files a/venv/Lib/site-packages/charset_normalizer/cli/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/charset_normalizer/cli/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/charset_normalizer/cli/__pycache__/__main__.cpython-312.pyc b/venv/Lib/site-packages/charset_normalizer/cli/__pycache__/__main__.cpython-312.pyc index ebe6b1f..5612093 100644 Binary files a/venv/Lib/site-packages/charset_normalizer/cli/__pycache__/__main__.cpython-312.pyc and b/venv/Lib/site-packages/charset_normalizer/cli/__pycache__/__main__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/click-8.3.1.dist-info/RECORD b/venv/Lib/site-packages/click-8.3.1.dist-info/RECORD index 008d697..f3a18c5 100644 --- a/venv/Lib/site-packages/click-8.3.1.dist-info/RECORD +++ b/venv/Lib/site-packages/click-8.3.1.dist-info/RECORD @@ -1,6 +1,7 @@ click-8.3.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 click-8.3.1.dist-info/METADATA,sha256=XZeBrMAE0ghTE88SjfrSDuSyNCpBPplxJR1tbwD9oZg,2621 click-8.3.1.dist-info/RECORD,, +click-8.3.1.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 click-8.3.1.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82 click-8.3.1.dist-info/licenses/LICENSE.txt,sha256=morRBqOU6FO_4h9C9OctWSgZoigF2ZG18ydQKSkrZY0,1475 click/__init__.py,sha256=6YyS1aeyknZ0LYweWozNZy0A9nZ_11wmYIhv3cbQrYo,4473 diff --git a/venv/Lib/site-packages/click-8.3.1.dist-info/REQUESTED b/venv/Lib/site-packages/click-8.3.1.dist-info/REQUESTED new file mode 100644 index 0000000..e69de29 diff --git a/venv/Lib/site-packages/click/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/click/__pycache__/__init__.cpython-312.pyc index 6bec424..8272159 100644 Binary files a/venv/Lib/site-packages/click/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/click/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/click/__pycache__/_compat.cpython-312.pyc b/venv/Lib/site-packages/click/__pycache__/_compat.cpython-312.pyc index 8f6d5bb..07cbcae 100644 Binary files a/venv/Lib/site-packages/click/__pycache__/_compat.cpython-312.pyc and b/venv/Lib/site-packages/click/__pycache__/_compat.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/click/__pycache__/_termui_impl.cpython-312.pyc b/venv/Lib/site-packages/click/__pycache__/_termui_impl.cpython-312.pyc index a65ba50..2f72178 100644 Binary files a/venv/Lib/site-packages/click/__pycache__/_termui_impl.cpython-312.pyc and b/venv/Lib/site-packages/click/__pycache__/_termui_impl.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/click/__pycache__/_textwrap.cpython-312.pyc b/venv/Lib/site-packages/click/__pycache__/_textwrap.cpython-312.pyc index eda6014..f248a0e 100644 Binary files a/venv/Lib/site-packages/click/__pycache__/_textwrap.cpython-312.pyc and b/venv/Lib/site-packages/click/__pycache__/_textwrap.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/click/__pycache__/_utils.cpython-312.pyc b/venv/Lib/site-packages/click/__pycache__/_utils.cpython-312.pyc index 178efcc..e39b589 100644 Binary files a/venv/Lib/site-packages/click/__pycache__/_utils.cpython-312.pyc and b/venv/Lib/site-packages/click/__pycache__/_utils.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/click/__pycache__/_winconsole.cpython-312.pyc b/venv/Lib/site-packages/click/__pycache__/_winconsole.cpython-312.pyc index 47306ba..de47c26 100644 Binary files a/venv/Lib/site-packages/click/__pycache__/_winconsole.cpython-312.pyc and b/venv/Lib/site-packages/click/__pycache__/_winconsole.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/click/__pycache__/core.cpython-312.pyc b/venv/Lib/site-packages/click/__pycache__/core.cpython-312.pyc index 6453939..d804319 100644 Binary files a/venv/Lib/site-packages/click/__pycache__/core.cpython-312.pyc and b/venv/Lib/site-packages/click/__pycache__/core.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/click/__pycache__/decorators.cpython-312.pyc b/venv/Lib/site-packages/click/__pycache__/decorators.cpython-312.pyc index cbb48a5..b4a74c0 100644 Binary files a/venv/Lib/site-packages/click/__pycache__/decorators.cpython-312.pyc and b/venv/Lib/site-packages/click/__pycache__/decorators.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/click/__pycache__/exceptions.cpython-312.pyc b/venv/Lib/site-packages/click/__pycache__/exceptions.cpython-312.pyc index 3cbfa48..e7ba68e 100644 Binary files a/venv/Lib/site-packages/click/__pycache__/exceptions.cpython-312.pyc and b/venv/Lib/site-packages/click/__pycache__/exceptions.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/click/__pycache__/formatting.cpython-312.pyc b/venv/Lib/site-packages/click/__pycache__/formatting.cpython-312.pyc index 768363e..f6e7e47 100644 Binary files a/venv/Lib/site-packages/click/__pycache__/formatting.cpython-312.pyc and b/venv/Lib/site-packages/click/__pycache__/formatting.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/click/__pycache__/globals.cpython-312.pyc b/venv/Lib/site-packages/click/__pycache__/globals.cpython-312.pyc index 8587841..93aa4af 100644 Binary files a/venv/Lib/site-packages/click/__pycache__/globals.cpython-312.pyc and b/venv/Lib/site-packages/click/__pycache__/globals.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/click/__pycache__/parser.cpython-312.pyc b/venv/Lib/site-packages/click/__pycache__/parser.cpython-312.pyc index d7b846c..9222bc9 100644 Binary files a/venv/Lib/site-packages/click/__pycache__/parser.cpython-312.pyc and b/venv/Lib/site-packages/click/__pycache__/parser.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/click/__pycache__/shell_completion.cpython-312.pyc b/venv/Lib/site-packages/click/__pycache__/shell_completion.cpython-312.pyc index 5d2618c..fc624e5 100644 Binary files a/venv/Lib/site-packages/click/__pycache__/shell_completion.cpython-312.pyc and b/venv/Lib/site-packages/click/__pycache__/shell_completion.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/click/__pycache__/termui.cpython-312.pyc b/venv/Lib/site-packages/click/__pycache__/termui.cpython-312.pyc index b83dd4b..64deedc 100644 Binary files a/venv/Lib/site-packages/click/__pycache__/termui.cpython-312.pyc and b/venv/Lib/site-packages/click/__pycache__/termui.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/click/__pycache__/testing.cpython-312.pyc b/venv/Lib/site-packages/click/__pycache__/testing.cpython-312.pyc index b2a90df..d4996cb 100644 Binary files a/venv/Lib/site-packages/click/__pycache__/testing.cpython-312.pyc and b/venv/Lib/site-packages/click/__pycache__/testing.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/click/__pycache__/types.cpython-312.pyc b/venv/Lib/site-packages/click/__pycache__/types.cpython-312.pyc index 024795a..cbd7c62 100644 Binary files a/venv/Lib/site-packages/click/__pycache__/types.cpython-312.pyc and b/venv/Lib/site-packages/click/__pycache__/types.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/click/__pycache__/utils.cpython-312.pyc b/venv/Lib/site-packages/click/__pycache__/utils.cpython-312.pyc index 875ba76..b80260b 100644 Binary files a/venv/Lib/site-packages/click/__pycache__/utils.cpython-312.pyc and b/venv/Lib/site-packages/click/__pycache__/utils.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/colorama-0.4.6.dist-info/RECORD b/venv/Lib/site-packages/colorama-0.4.6.dist-info/RECORD index cd6b130..d1eaa50 100644 --- a/venv/Lib/site-packages/colorama-0.4.6.dist-info/RECORD +++ b/venv/Lib/site-packages/colorama-0.4.6.dist-info/RECORD @@ -1,6 +1,7 @@ colorama-0.4.6.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 colorama-0.4.6.dist-info/METADATA,sha256=e67SnrUMOym9sz_4TjF3vxvAV4T3aF7NyqRHHH3YEMw,17158 colorama-0.4.6.dist-info/RECORD,, +colorama-0.4.6.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 colorama-0.4.6.dist-info/WHEEL,sha256=cdcF4Fbd0FPtw2EMIOwH-3rSOTUdTCeOSXRMD1iLUb8,105 colorama-0.4.6.dist-info/licenses/LICENSE.txt,sha256=ysNcAmhuXQSlpxQL-zs25zrtSWZW6JEQLkKIhteTAxg,1491 colorama/__init__.py,sha256=wePQA4U20tKgYARySLEC047ucNX-g8pRLpYBuiHlLb8,266 diff --git a/venv/Lib/site-packages/colorama-0.4.6.dist-info/REQUESTED b/venv/Lib/site-packages/colorama-0.4.6.dist-info/REQUESTED new file mode 100644 index 0000000..e69de29 diff --git a/venv/Lib/site-packages/colorama/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/colorama/__pycache__/__init__.cpython-312.pyc index 49747ca..86aa408 100644 Binary files a/venv/Lib/site-packages/colorama/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/colorama/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/colorama/__pycache__/ansi.cpython-312.pyc b/venv/Lib/site-packages/colorama/__pycache__/ansi.cpython-312.pyc index 4f1c4b2..037aa42 100644 Binary files a/venv/Lib/site-packages/colorama/__pycache__/ansi.cpython-312.pyc and b/venv/Lib/site-packages/colorama/__pycache__/ansi.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/colorama/__pycache__/ansitowin32.cpython-312.pyc b/venv/Lib/site-packages/colorama/__pycache__/ansitowin32.cpython-312.pyc index 80cd5c8..0770305 100644 Binary files a/venv/Lib/site-packages/colorama/__pycache__/ansitowin32.cpython-312.pyc and b/venv/Lib/site-packages/colorama/__pycache__/ansitowin32.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/colorama/__pycache__/initialise.cpython-312.pyc b/venv/Lib/site-packages/colorama/__pycache__/initialise.cpython-312.pyc index f4c8065..02eec1a 100644 Binary files a/venv/Lib/site-packages/colorama/__pycache__/initialise.cpython-312.pyc and b/venv/Lib/site-packages/colorama/__pycache__/initialise.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/colorama/__pycache__/win32.cpython-312.pyc b/venv/Lib/site-packages/colorama/__pycache__/win32.cpython-312.pyc index c84843e..9474ea4 100644 Binary files a/venv/Lib/site-packages/colorama/__pycache__/win32.cpython-312.pyc and b/venv/Lib/site-packages/colorama/__pycache__/win32.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/colorama/__pycache__/winterm.cpython-312.pyc b/venv/Lib/site-packages/colorama/__pycache__/winterm.cpython-312.pyc index 8790568..2ce8379 100644 Binary files a/venv/Lib/site-packages/colorama/__pycache__/winterm.cpython-312.pyc and b/venv/Lib/site-packages/colorama/__pycache__/winterm.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/colorama/tests/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/colorama/tests/__pycache__/__init__.cpython-312.pyc index 86e2e74..d23a7ae 100644 Binary files a/venv/Lib/site-packages/colorama/tests/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/colorama/tests/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/colorama/tests/__pycache__/ansi_test.cpython-312.pyc b/venv/Lib/site-packages/colorama/tests/__pycache__/ansi_test.cpython-312.pyc index 179db10..59bbfab 100644 Binary files a/venv/Lib/site-packages/colorama/tests/__pycache__/ansi_test.cpython-312.pyc and b/venv/Lib/site-packages/colorama/tests/__pycache__/ansi_test.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/colorama/tests/__pycache__/ansitowin32_test.cpython-312.pyc b/venv/Lib/site-packages/colorama/tests/__pycache__/ansitowin32_test.cpython-312.pyc index de52e0d..690e57f 100644 Binary files a/venv/Lib/site-packages/colorama/tests/__pycache__/ansitowin32_test.cpython-312.pyc and b/venv/Lib/site-packages/colorama/tests/__pycache__/ansitowin32_test.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/colorama/tests/__pycache__/initialise_test.cpython-312.pyc b/venv/Lib/site-packages/colorama/tests/__pycache__/initialise_test.cpython-312.pyc index 4e31972..1a4677b 100644 Binary files a/venv/Lib/site-packages/colorama/tests/__pycache__/initialise_test.cpython-312.pyc and b/venv/Lib/site-packages/colorama/tests/__pycache__/initialise_test.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/colorama/tests/__pycache__/isatty_test.cpython-312.pyc b/venv/Lib/site-packages/colorama/tests/__pycache__/isatty_test.cpython-312.pyc index c16e59c..e363a79 100644 Binary files a/venv/Lib/site-packages/colorama/tests/__pycache__/isatty_test.cpython-312.pyc and b/venv/Lib/site-packages/colorama/tests/__pycache__/isatty_test.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/colorama/tests/__pycache__/utils.cpython-312.pyc b/venv/Lib/site-packages/colorama/tests/__pycache__/utils.cpython-312.pyc index e0a9c61..cd9a176 100644 Binary files a/venv/Lib/site-packages/colorama/tests/__pycache__/utils.cpython-312.pyc and b/venv/Lib/site-packages/colorama/tests/__pycache__/utils.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/colorama/tests/__pycache__/winterm_test.cpython-312.pyc b/venv/Lib/site-packages/colorama/tests/__pycache__/winterm_test.cpython-312.pyc index e644b33..0c85261 100644 Binary files a/venv/Lib/site-packages/colorama/tests/__pycache__/winterm_test.cpython-312.pyc and b/venv/Lib/site-packages/colorama/tests/__pycache__/winterm_test.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/cryptography-44.0.3.dist-info/WHEEL b/venv/Lib/site-packages/cryptography-44.0.3.dist-info/WHEEL deleted file mode 100644 index 3e276aa..0000000 --- a/venv/Lib/site-packages/cryptography-44.0.3.dist-info/WHEEL +++ /dev/null @@ -1,4 +0,0 @@ -Wheel-Version: 1.0 -Generator: maturin (1.7.5) -Root-Is-Purelib: false -Tag: cp39-abi3-win_amd64 diff --git a/venv/Lib/site-packages/cryptography-44.0.3.dist-info/INSTALLER b/venv/Lib/site-packages/cryptography-46.0.3.dist-info/INSTALLER similarity index 100% rename from venv/Lib/site-packages/cryptography-44.0.3.dist-info/INSTALLER rename to venv/Lib/site-packages/cryptography-46.0.3.dist-info/INSTALLER diff --git a/venv/Lib/site-packages/cryptography-44.0.3.dist-info/METADATA b/venv/Lib/site-packages/cryptography-46.0.3.dist-info/METADATA similarity index 68% rename from venv/Lib/site-packages/cryptography-44.0.3.dist-info/METADATA rename to venv/Lib/site-packages/cryptography-46.0.3.dist-info/METADATA index a67ad96..7b07ee7 100644 --- a/venv/Lib/site-packages/cryptography-44.0.3.dist-info/METADATA +++ b/venv/Lib/site-packages/cryptography-46.0.3.dist-info/METADATA @@ -1,10 +1,8 @@ -Metadata-Version: 2.3 +Metadata-Version: 2.4 Name: cryptography -Version: 44.0.3 +Version: 46.0.3 Classifier: Development Status :: 5 - Production/Stable Classifier: Intended Audience :: Developers -Classifier: License :: OSI Approved :: Apache Software License -Classifier: License :: OSI Approved :: BSD License Classifier: Natural Language :: English Classifier: Operating System :: MacOS :: MacOS X Classifier: Operating System :: POSIX @@ -14,38 +12,41 @@ Classifier: Operating System :: Microsoft :: Windows Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3 :: Only -Classifier: Programming Language :: Python :: 3.7 Classifier: Programming Language :: Python :: 3.8 Classifier: Programming Language :: Python :: 3.9 Classifier: Programming Language :: Python :: 3.10 Classifier: Programming Language :: Python :: 3.11 Classifier: Programming Language :: Python :: 3.12 Classifier: Programming Language :: Python :: 3.13 +Classifier: Programming Language :: Python :: 3.14 Classifier: Programming Language :: Python :: Implementation :: CPython Classifier: Programming Language :: Python :: Implementation :: PyPy +Classifier: Programming Language :: Python :: Free Threading :: 3 - Stable Classifier: Topic :: Security :: Cryptography -Requires-Dist: cffi >=1.12 ; platform_python_implementation != 'PyPy' -Requires-Dist: bcrypt >=3.1.5 ; extra == 'ssh' -Requires-Dist: nox >=2024.4.15 ; extra == 'nox' -Requires-Dist: nox[uv] >=2024.3.2 ; python_version >= '3.8' and extra == 'nox' -Requires-Dist: cryptography-vectors ==44.0.3 ; extra == 'test' -Requires-Dist: pytest >=7.4.0 ; extra == 'test' -Requires-Dist: pytest-benchmark >=4.0 ; extra == 'test' -Requires-Dist: pytest-cov >=2.10.1 ; extra == 'test' -Requires-Dist: pytest-xdist >=3.5.0 ; extra == 'test' -Requires-Dist: pretend >=0.7 ; extra == 'test' -Requires-Dist: certifi >=2024 ; extra == 'test' +Requires-Dist: cffi>=1.14 ; python_full_version == '3.8.*' and platform_python_implementation != 'PyPy' +Requires-Dist: cffi>=2.0.0 ; python_full_version >= '3.9' and platform_python_implementation != 'PyPy' +Requires-Dist: typing-extensions>=4.13.2 ; python_full_version < '3.11' +Requires-Dist: bcrypt>=3.1.5 ; extra == 'ssh' +Requires-Dist: nox[uv]>=2024.4.15 ; extra == 'nox' +Requires-Dist: cryptography-vectors==46.0.3 ; extra == 'test' +Requires-Dist: pytest>=7.4.0 ; extra == 'test' +Requires-Dist: pytest-benchmark>=4.0 ; extra == 'test' +Requires-Dist: pytest-cov>=2.10.1 ; extra == 'test' +Requires-Dist: pytest-xdist>=3.5.0 ; extra == 'test' +Requires-Dist: pretend>=0.7 ; extra == 'test' +Requires-Dist: certifi>=2024 ; extra == 'test' Requires-Dist: pytest-randomly ; extra == 'test-randomorder' -Requires-Dist: sphinx >=5.3.0 ; extra == 'docs' -Requires-Dist: sphinx-rtd-theme >=3.0.0 ; python_version >= '3.8' and extra == 'docs' -Requires-Dist: pyenchant >=3 ; extra == 'docstest' -Requires-Dist: readme-renderer >=30.0 ; extra == 'docstest' -Requires-Dist: sphinxcontrib-spelling >=7.3.1 ; extra == 'docstest' -Requires-Dist: build >=1.0.0 ; extra == 'sdist' -Requires-Dist: ruff >=0.3.6 ; extra == 'pep8test' -Requires-Dist: mypy >=1.4 ; extra == 'pep8test' -Requires-Dist: check-sdist ; python_version >= '3.8' and extra == 'pep8test' -Requires-Dist: click >=8.0.1 ; extra == 'pep8test' +Requires-Dist: sphinx>=5.3.0 ; extra == 'docs' +Requires-Dist: sphinx-rtd-theme>=3.0.0 ; extra == 'docs' +Requires-Dist: sphinx-inline-tabs ; extra == 'docs' +Requires-Dist: pyenchant>=3 ; extra == 'docstest' +Requires-Dist: readme-renderer>=30.0 ; extra == 'docstest' +Requires-Dist: sphinxcontrib-spelling>=7.3.1 ; extra == 'docstest' +Requires-Dist: build>=1.0.0 ; extra == 'sdist' +Requires-Dist: ruff>=0.11.11 ; extra == 'pep8test' +Requires-Dist: mypy>=1.14 ; extra == 'pep8test' +Requires-Dist: check-sdist ; extra == 'pep8test' +Requires-Dist: click>=8.0.1 ; extra == 'pep8test' Provides-Extra: ssh Provides-Extra: nox Provides-Extra: test @@ -58,10 +59,9 @@ License-File: LICENSE License-File: LICENSE.APACHE License-File: LICENSE.BSD Summary: cryptography is a package which provides cryptographic recipes and primitives to Python developers. -Author: The cryptography developers Author-email: The Python Cryptographic Authority and individual contributors -License: Apache-2.0 OR BSD-3-Clause -Requires-Python: >=3.7, !=3.9.0, !=3.9.1 +License-Expression: Apache-2.0 OR BSD-3-Clause +Requires-Python: >=3.8, !=3.9.0, !=3.9.1 Description-Content-Type: text/x-rst; charset=UTF-8 Project-URL: homepage, https://github.com/pyca/cryptography Project-URL: documentation, https://cryptography.io/ @@ -80,13 +80,12 @@ pyca/cryptography :target: https://cryptography.io :alt: Latest Docs -.. image:: https://github.com/pyca/cryptography/workflows/CI/badge.svg?branch=main - :target: https://github.com/pyca/cryptography/actions?query=workflow%3ACI+branch%3Amain - +.. image:: https://github.com/pyca/cryptography/actions/workflows/ci.yml/badge.svg + :target: https://github.com/pyca/cryptography/actions/workflows/ci.yml?query=branch%3Amain ``cryptography`` is a package which provides cryptographic recipes and primitives to Python developers. Our goal is for it to be your "cryptographic -standard library". It supports Python 3.7+ and PyPy3 7.3.11+. +standard library". It supports Python 3.8+ and PyPy3 7.3.11+. ``cryptography`` includes both high level recipes and low level interfaces to common cryptographic algorithms such as symmetric ciphers, message digests, and diff --git a/venv/Lib/site-packages/cryptography-44.0.3.dist-info/RECORD b/venv/Lib/site-packages/cryptography-46.0.3.dist-info/RECORD similarity index 54% rename from venv/Lib/site-packages/cryptography-44.0.3.dist-info/RECORD rename to venv/Lib/site-packages/cryptography-46.0.3.dist-info/RECORD index 304eb5f..d3e3233 100644 --- a/venv/Lib/site-packages/cryptography-44.0.3.dist-info/RECORD +++ b/venv/Lib/site-packages/cryptography-46.0.3.dist-info/RECORD @@ -1,70 +1,75 @@ -cryptography-44.0.3.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -cryptography-44.0.3.dist-info/METADATA,sha256=N2HCybALCy-5akCnV9cwLVzy7MWOxK7US732RZhSnOw,5724 -cryptography-44.0.3.dist-info/RECORD,, -cryptography-44.0.3.dist-info/WHEEL,sha256=Hn9bytZpOGoR6M4U5xUTHC1AJpPD9B1xPrM4STxljEU,94 -cryptography-44.0.3.dist-info/licenses/LICENSE,sha256=Pgx8CRqUi4JTO6mP18u0BDLW8amsv4X1ki0vmak65rs,197 -cryptography-44.0.3.dist-info/licenses/LICENSE.APACHE,sha256=qsc7MUj20dcRHbyjIJn2jSbGRMaBOuHk8F9leaomY_4,11360 -cryptography-44.0.3.dist-info/licenses/LICENSE.BSD,sha256=YCxMdILeZHndLpeTzaJ15eY9dz2s0eymiSMqtwCPtPs,1532 -cryptography/__about__.py,sha256=awPE0zq9hPdDu1cYrUd7hGJcA-POPpSD-ams74j4eag,445 -cryptography/__init__.py,sha256=XsRL_PxbU6UgoyoglAgJQSrJCP97ovBA8YIEQ2-uI68,762 +cryptography-46.0.3.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +cryptography-46.0.3.dist-info/METADATA,sha256=bx2LyCEmOVUC8FH5hsGEZewWPiZoIIYTq0hM9mu9r4s,5748 +cryptography-46.0.3.dist-info/RECORD,, +cryptography-46.0.3.dist-info/WHEEL,sha256=8hEf8NzM1FnmM77AjVt5h8nDuYkN3UqZ79LoIAHXeRE,95 +cryptography-46.0.3.dist-info/licenses/LICENSE,sha256=Pgx8CRqUi4JTO6mP18u0BDLW8amsv4X1ki0vmak65rs,197 +cryptography-46.0.3.dist-info/licenses/LICENSE.APACHE,sha256=qsc7MUj20dcRHbyjIJn2jSbGRMaBOuHk8F9leaomY_4,11360 +cryptography-46.0.3.dist-info/licenses/LICENSE.BSD,sha256=YCxMdILeZHndLpeTzaJ15eY9dz2s0eymiSMqtwCPtPs,1532 +cryptography/__about__.py,sha256=QCLxNH_Abbygdc9RQGpUmrK14Wp3Cl_SEiB2byLwyxo,445 +cryptography/__init__.py,sha256=mthuUrTd4FROCpUYrTIqhjz6s6T9djAZrV7nZ1oMm2o,364 cryptography/__pycache__/__about__.cpython-312.pyc,, cryptography/__pycache__/__init__.cpython-312.pyc,, cryptography/__pycache__/exceptions.cpython-312.pyc,, cryptography/__pycache__/fernet.cpython-312.pyc,, cryptography/__pycache__/utils.cpython-312.pyc,, cryptography/exceptions.py,sha256=835EWILc2fwxw-gyFMriciC2SqhViETB10LBSytnDIc,1087 -cryptography/fernet.py,sha256=aMU2HyDJ5oRGjg8AkFvHwE7BSmHY4fVUCaioxZcd8gA,6933 +cryptography/fernet.py,sha256=3Cvxkh0KJSbX8HbnCHu4wfCW7U0GgfUA3v_qQ8a8iWc,6963 cryptography/hazmat/__init__.py,sha256=5IwrLWrVp0AjEr_4FdWG_V057NSJGY_W4egNNsuct0g,455 cryptography/hazmat/__pycache__/__init__.cpython-312.pyc,, cryptography/hazmat/__pycache__/_oid.cpython-312.pyc,, -cryptography/hazmat/_oid.py,sha256=xcGtygUQX1p2ozVjhqKk016E5--BC7ituI1EGuoiWds,15294 +cryptography/hazmat/_oid.py,sha256=p8ThjwJB56Ci_rAIrjyJ1f8VjgD6e39es2dh8JIUBOw,17240 +cryptography/hazmat/asn1/__init__.py,sha256=hS_EWx3wVvZzfbCcNV8hzcDnyMM8H-BhIoS1TipUosk,293 +cryptography/hazmat/asn1/__pycache__/__init__.cpython-312.pyc,, +cryptography/hazmat/asn1/__pycache__/asn1.cpython-312.pyc,, +cryptography/hazmat/asn1/asn1.py,sha256=eMEThEXa19LQjcyVofgHsW6tsZnjp3ddH7bWkkcxfLM,3860 cryptography/hazmat/backends/__init__.py,sha256=O5jvKFQdZnXhKeqJ-HtulaEL9Ni7mr1mDzZY5kHlYhI,361 cryptography/hazmat/backends/__pycache__/__init__.cpython-312.pyc,, cryptography/hazmat/backends/openssl/__init__.py,sha256=p3jmJfnCag9iE5sdMrN6VvVEu55u46xaS_IjoI0SrmA,305 cryptography/hazmat/backends/openssl/__pycache__/__init__.cpython-312.pyc,, cryptography/hazmat/backends/openssl/__pycache__/backend.cpython-312.pyc,, -cryptography/hazmat/backends/openssl/backend.py,sha256=_H02YwpjWOV19Mcc04QgedqGTSSjBaWEb6KIIvLyfzk,9655 +cryptography/hazmat/backends/openssl/backend.py,sha256=tV5AxBoFJ2GfA0DMWSY-0TxQJrpQoexzI9R4Kybb--4,10215 cryptography/hazmat/bindings/__init__.py,sha256=s9oKCQ2ycFdXoERdS1imafueSkBsL9kvbyfghaauZ9Y,180 cryptography/hazmat/bindings/__pycache__/__init__.cpython-312.pyc,, -cryptography/hazmat/bindings/_rust.pyd,sha256=mqsL1zIb8Dt9gyrddrazHWulgIQFBbA8I8d3Nmnmckc,8315904 -cryptography/hazmat/bindings/_rust/__init__.pyi,sha256=s73-NWxZs-5r2vAzDT9Eqo9mRiWE__A4VJKyFBkjHdM,879 +cryptography/hazmat/bindings/_rust.pyd,sha256=kvWLtPAadaDvTdlCXcKpbd_iX8k_2dwR6o8NBbek8IU,9245696 +cryptography/hazmat/bindings/_rust/__init__.pyi,sha256=KhqLhXFPArPzzJ7DYO9Fl8FoXB_BagAd_r4Dm_Ze9Xo,1257 cryptography/hazmat/bindings/_rust/_openssl.pyi,sha256=mpNJLuYLbCVrd5i33FBTmWwL_55Dw7JPkSLlSX9Q7oI,230 cryptography/hazmat/bindings/_rust/asn1.pyi,sha256=BrGjC8J6nwuS-r3EVcdXJB8ndotfY9mbQYOfpbPG0HA,354 +cryptography/hazmat/bindings/_rust/declarative_asn1.pyi,sha256=2ECFmYue1EPkHEE2Bm7aLwkjB0mSUTpr23v9MN4pri4,892 cryptography/hazmat/bindings/_rust/exceptions.pyi,sha256=exXr2xw_0pB1kk93cYbM3MohbzoUkjOms1ZMUi0uQZE,640 -cryptography/hazmat/bindings/_rust/ocsp.pyi,sha256=mNrMO5sYEnftD_b2-NvvR6M8QdYGZ1jpTdazpgzXgl0,4004 -cryptography/hazmat/bindings/_rust/openssl/__init__.pyi,sha256=FS2gi2eALVzqTTic8an8enD431pkwKbRxeAZaNMV4Ts,1410 -cryptography/hazmat/bindings/_rust/openssl/aead.pyi,sha256=i0gA3jUQ4rkJXTGGZrq-AuY-VQLN31lyDeWuDZ0zJYw,2553 -cryptography/hazmat/bindings/_rust/openssl/ciphers.pyi,sha256=iK0ZhQ-WyCQbjaraaFgK6q4PpD-7Rf5RDHkFD3YEW_g,1301 +cryptography/hazmat/bindings/_rust/ocsp.pyi,sha256=VPVWuKHI9EMs09ZLRYAGvR0Iz0mCMmEzXAkgJHovpoM,4020 +cryptography/hazmat/bindings/_rust/openssl/__init__.pyi,sha256=iOAMDyHoNwwCSZfZzuXDr64g4GpGUeDgEN-LjXqdrBM,1522 +cryptography/hazmat/bindings/_rust/openssl/aead.pyi,sha256=4Nddw6-ynzIB3w2W86WvkGKTLlTDk_6F5l54RHCuy3E,2688 +cryptography/hazmat/bindings/_rust/openssl/ciphers.pyi,sha256=LhPzHWSXJq4grAJXn6zSvSSdV-aYIIscHDwIPlJGGPs,1315 cryptography/hazmat/bindings/_rust/openssl/cmac.pyi,sha256=nPH0X57RYpsAkRowVpjQiHE566ThUTx7YXrsadmrmHk,564 cryptography/hazmat/bindings/_rust/openssl/dh.pyi,sha256=Z3TC-G04-THtSdAOPLM1h2G7ml5bda1ElZUcn5wpuhk,1564 cryptography/hazmat/bindings/_rust/openssl/dsa.pyi,sha256=qBtkgj2albt2qFcnZ9UDrhzoNhCVO7HTby5VSf1EXMI,1299 cryptography/hazmat/bindings/_rust/openssl/ec.pyi,sha256=zJy0pRa5n-_p2dm45PxECB_-B6SVZyNKfjxFDpPqT38,1691 -cryptography/hazmat/bindings/_rust/openssl/ed25519.pyi,sha256=OJsrblS2nHptZctva-pAKFL5q8yPEAkhmjPZpJ6TA94,493 -cryptography/hazmat/bindings/_rust/openssl/ed448.pyi,sha256=SkPHK2HdbYN02TVQEUOgW3iTdiEY7HBE4DijpdkAzmk,475 -cryptography/hazmat/bindings/_rust/openssl/hashes.pyi,sha256=p8sdf41mPBlV_W9v_18JItuMoHE8UkBxj9Tuqi0WiTE,639 -cryptography/hazmat/bindings/_rust/openssl/hmac.pyi,sha256=ZmLJ73pmxcZFC1XosWEiXMRYtvJJor3ZLdCQOJu85Cw,662 -cryptography/hazmat/bindings/_rust/openssl/kdf.pyi,sha256=hvZSV2C3MQd9jC1Tuh5Lsb0iGBgcLVF2xFYdTo7USO4,1129 -cryptography/hazmat/bindings/_rust/openssl/keys.pyi,sha256=JSrlGNaW49ZCZ1hcb-YJdS1EAbsMwRbVEcLL0P9OApA,872 -cryptography/hazmat/bindings/_rust/openssl/poly1305.pyi,sha256=9iogF7Q4i81IkOS-IMXp6HvxFF_3cNy_ucrAjVQnn14,540 +cryptography/hazmat/bindings/_rust/openssl/ed25519.pyi,sha256=VXfXd5G6hUivg399R1DYdmW3eTb0EebzDTqjRC2gaRw,532 +cryptography/hazmat/bindings/_rust/openssl/ed448.pyi,sha256=Yx49lqdnjsD7bxiDV1kcaMrDktug5evi5a6zerMiy2s,514 +cryptography/hazmat/bindings/_rust/openssl/hashes.pyi,sha256=OWZvBx7xfo_HJl41Nc--DugVyCVPIprZ3HlOPTSWH9g,984 +cryptography/hazmat/bindings/_rust/openssl/hmac.pyi,sha256=BXZn7NDjL3JAbYW0SQ8pg1iyC5DbQXVhUAiwsi8DFR8,702 +cryptography/hazmat/bindings/_rust/openssl/kdf.pyi,sha256=xXfFBb9QehHfDtEaxV_65Z0YK7NquOVIChpTLkgAs_k,2029 +cryptography/hazmat/bindings/_rust/openssl/keys.pyi,sha256=teIt8M6ZEMJrn4s3W0UnW0DZ-30Jd68WnSsKKG124l0,912 +cryptography/hazmat/bindings/_rust/openssl/poly1305.pyi,sha256=_SW9NtQ5FDlAbdclFtWpT4lGmxKIKHpN-4j8J2BzYfQ,585 cryptography/hazmat/bindings/_rust/openssl/rsa.pyi,sha256=2OQCNSXkxgc-3uw1xiCCloIQTV6p9_kK79Yu0rhZgPc,1364 -cryptography/hazmat/bindings/_rust/openssl/x25519.pyi,sha256=2BKdbrddM_9SMUpdvHKGhb9MNjURCarPxccbUDzHeoA,484 -cryptography/hazmat/bindings/_rust/openssl/x448.pyi,sha256=AoRMWNvCJTiH5L-lkIkCdPlrPLUdJvvfXpIvf1GmxpM,466 -cryptography/hazmat/bindings/_rust/pkcs12.pyi,sha256=afhB_6M8xI1MIE5vxkaDF1jSxA48ib1--NiOxtf6boM,1394 -cryptography/hazmat/bindings/_rust/pkcs7.pyi,sha256=Ag9coB8kRwrUJEg1do6BJABs9DqxZiY8WJIFUVa7StE,1545 -cryptography/hazmat/bindings/_rust/test_support.pyi,sha256=FXe7t_tqI3e9ULirYcr5Zlw5szGY7TiZyb7W83ak0Nk,718 -cryptography/hazmat/bindings/_rust/x509.pyi,sha256=0p-Ak_zj-9WfyZKPo08YT6cOx1c-lhjeYd0jJ8c4oT0,8318 +cryptography/hazmat/bindings/_rust/openssl/x25519.pyi,sha256=ewn4GpQyb7zPwE-ni7GtyQgMC0A1mLuqYsSyqv6nI_s,523 +cryptography/hazmat/bindings/_rust/openssl/x448.pyi,sha256=juTZTmli8jO_5Vcufg-vHvx_tCyezmSLIh_9PU3TczI,505 +cryptography/hazmat/bindings/_rust/pkcs12.pyi,sha256=vEEd5wDiZvb8ZGFaziLCaWLzAwoG_tvPUxLQw5_uOl8,1605 +cryptography/hazmat/bindings/_rust/pkcs7.pyi,sha256=txGBJijqZshEcqra6byPNbnisIdlxzOSIHP2hl9arPs,1601 +cryptography/hazmat/bindings/_rust/test_support.pyi,sha256=PPhld-WkO743iXFPebeG0LtgK0aTzGdjcIsay1Gm5GE,757 +cryptography/hazmat/bindings/_rust/x509.pyi,sha256=n9X0IQ6ICbdIi-ExdCFZoBgeY6njm3QOVAVZwDQdnbk,9784 cryptography/hazmat/bindings/openssl/__init__.py,sha256=s9oKCQ2ycFdXoERdS1imafueSkBsL9kvbyfghaauZ9Y,180 cryptography/hazmat/bindings/openssl/__pycache__/__init__.cpython-312.pyc,, cryptography/hazmat/bindings/openssl/__pycache__/_conditional.cpython-312.pyc,, cryptography/hazmat/bindings/openssl/__pycache__/binding.cpython-312.pyc,, -cryptography/hazmat/bindings/openssl/_conditional.py,sha256=dkGKGU-22uR2ZKeOOwaSxEJCGaafgUjb2romWcu03QE,5163 -cryptography/hazmat/bindings/openssl/binding.py,sha256=e1gnFAZBPrkJ3CsiZV-ug6kaPdNTAEROaUFiFrUh71M,4042 +cryptography/hazmat/bindings/openssl/_conditional.py,sha256=DMOpA_XN4l70zTc5_J9DpwlbQeUBRTWpfIJ4yRIn1-U,5791 +cryptography/hazmat/bindings/openssl/binding.py,sha256=x8eocEmukO4cm7cHqfVmOoYY7CCXdoF1v1WhZQt9neo,4610 cryptography/hazmat/decrepit/__init__.py,sha256=wHCbWfaefa-fk6THSw9th9fJUsStJo7245wfFBqmduA,216 cryptography/hazmat/decrepit/__pycache__/__init__.cpython-312.pyc,, cryptography/hazmat/decrepit/ciphers/__init__.py,sha256=wHCbWfaefa-fk6THSw9th9fJUsStJo7245wfFBqmduA,216 cryptography/hazmat/decrepit/ciphers/__pycache__/__init__.cpython-312.pyc,, cryptography/hazmat/decrepit/ciphers/__pycache__/algorithms.cpython-312.pyc,, -cryptography/hazmat/decrepit/ciphers/algorithms.py,sha256=HWA4PKDS2w4D2dQoRerpLRU7Kntt5vJeJC7j--AlZVU,2520 +cryptography/hazmat/decrepit/ciphers/algorithms.py,sha256=YrKgHS4MfwWaMmPBYRymRRlC0phwWp9ycICFezeJPGk,2595 cryptography/hazmat/primitives/__init__.py,sha256=s9oKCQ2ycFdXoERdS1imafueSkBsL9kvbyfghaauZ9Y,180 cryptography/hazmat/primitives/__pycache__/__init__.cpython-312.pyc,, cryptography/hazmat/primitives/__pycache__/_asymmetric.cpython-312.pyc,, @@ -78,8 +83,8 @@ cryptography/hazmat/primitives/__pycache__/keywrap.cpython-312.pyc,, cryptography/hazmat/primitives/__pycache__/padding.cpython-312.pyc,, cryptography/hazmat/primitives/__pycache__/poly1305.cpython-312.pyc,, cryptography/hazmat/primitives/_asymmetric.py,sha256=RhgcouUB6HTiFDBrR1LxqkMjpUxIiNvQ1r_zJjRG6qQ,532 -cryptography/hazmat/primitives/_cipheralgorithm.py,sha256=gKa0WrLz6K4fqhnGbfBYKDSxgLxsPU0uj_EK2UT47W4,1495 -cryptography/hazmat/primitives/_serialization.py,sha256=qrozc8fw2WZSbjk3DAlSl3ResxpauwJ74ZgGoUL-mj0,5142 +cryptography/hazmat/primitives/_cipheralgorithm.py,sha256=Eh3i7lwedHfi0eLSsH93PZxQKzY9I6lkK67vL4V5tOc,1522 +cryptography/hazmat/primitives/_serialization.py,sha256=chgPCSF2jxI2Cr5gB-qbWXOvOfupBh4CARS0KAhv9AM,5123 cryptography/hazmat/primitives/asymmetric/__init__.py,sha256=s9oKCQ2ycFdXoERdS1imafueSkBsL9kvbyfghaauZ9Y,180 cryptography/hazmat/primitives/asymmetric/__pycache__/__init__.cpython-312.pyc,, cryptography/hazmat/primitives/asymmetric/__pycache__/dh.cpython-312.pyc,, @@ -93,17 +98,17 @@ cryptography/hazmat/primitives/asymmetric/__pycache__/types.cpython-312.pyc,, cryptography/hazmat/primitives/asymmetric/__pycache__/utils.cpython-312.pyc,, cryptography/hazmat/primitives/asymmetric/__pycache__/x25519.cpython-312.pyc,, cryptography/hazmat/primitives/asymmetric/__pycache__/x448.cpython-312.pyc,, -cryptography/hazmat/primitives/asymmetric/dh.py,sha256=OOCjMClH1Bf14Sy7jAdwzEeCxFPb8XUe2qePbExvXwc,3420 -cryptography/hazmat/primitives/asymmetric/dsa.py,sha256=xBwdf0pZOgvqjUKcO7Q0L3NxwalYj0SJDUqThemhSmI,3945 -cryptography/hazmat/primitives/asymmetric/ec.py,sha256=lwZmtAwi3PM8lsY1MsNaby_bVi--49OCxwE_1yqKC-A,10428 -cryptography/hazmat/primitives/asymmetric/ed25519.py,sha256=kl63fg7myuMjNTmMoVFeH6iVr0x5FkjNmggxIRTloJk,3423 -cryptography/hazmat/primitives/asymmetric/ed448.py,sha256=2UzEDzzfkPn83UFVFlMZfIMbAixxY09WmQyrwinWTn8,3456 -cryptography/hazmat/primitives/asymmetric/padding.py,sha256=eZcvUqVLbe3u48SunLdeniaPlV4-k6pwBl67OW4jSy8,2885 -cryptography/hazmat/primitives/asymmetric/rsa.py,sha256=dvj4i2js78qpgotEKn3SU5Eh2unDSMiZpTVo2kx_NWU,7668 +cryptography/hazmat/primitives/asymmetric/dh.py,sha256=0v_vEFFz5pQ1QG-FkWDyvgv7IfuVZSH5Q6LyFI5A8rg,3645 +cryptography/hazmat/primitives/asymmetric/dsa.py,sha256=Ld_bbbqQFz12dObHxIkzEQzX0SWWP41RLSWkYSaKhqE,4213 +cryptography/hazmat/primitives/asymmetric/ec.py,sha256=Vf5ig2PcS3PVnsb5N49Kx1uIkFBJyhg4BWXThDz5cug,12999 +cryptography/hazmat/primitives/asymmetric/ed25519.py,sha256=jZW5cs472wXXV3eB0sE1b8w64gdazwwU0_MT5UOTiXs,3700 +cryptography/hazmat/primitives/asymmetric/ed448.py,sha256=yAetgn2f2JYf0BO8MapGzXeThsvSMG5LmUCrxVOidAA,3729 +cryptography/hazmat/primitives/asymmetric/padding.py,sha256=vQ6l6gOg9HqcbOsvHrSiJRVLdEj9L4m4HkRGYziTyFA,2854 +cryptography/hazmat/primitives/asymmetric/rsa.py,sha256=ZnKOo2f34MCCOupC03Y1uR-_jiSG5IrelHEmxaME3D4,8303 cryptography/hazmat/primitives/asymmetric/types.py,sha256=LnsOJym-wmPUJ7Knu_7bCNU3kIiELCd6krOaW_JU08I,2996 cryptography/hazmat/primitives/asymmetric/utils.py,sha256=DPTs6T4F-UhwzFQTh-1fSEpQzazH2jf2xpIro3ItF4o,790 -cryptography/hazmat/primitives/asymmetric/x25519.py,sha256=VGYuRdIYuVBtizpFdNWd2bTrT10JRa1admQdBr08xz8,3341 -cryptography/hazmat/primitives/asymmetric/x448.py,sha256=GKKJBqYLr03VewMF18bXIM941aaWcZIQ4rC02GLLEmw,3374 +cryptography/hazmat/primitives/asymmetric/x25519.py,sha256=_4nQeZ3yJ3Lg0RpXnaqA-1yt6vbx1F-wzLcaZHwSpeE,3613 +cryptography/hazmat/primitives/asymmetric/x448.py,sha256=WKBLtuVfJqiBRro654fGaQAlvsKbqbNkK7c4A_ZCdV0,3642 cryptography/hazmat/primitives/ciphers/__init__.py,sha256=eyEXmjk6_CZXaOPYDr7vAYGXr29QvzgWL2-4CSolLFs,680 cryptography/hazmat/primitives/ciphers/__pycache__/__init__.cpython-312.pyc,, cryptography/hazmat/primitives/ciphers/__pycache__/aead.cpython-312.pyc,, @@ -111,12 +116,12 @@ cryptography/hazmat/primitives/ciphers/__pycache__/algorithms.cpython-312.pyc,, cryptography/hazmat/primitives/ciphers/__pycache__/base.cpython-312.pyc,, cryptography/hazmat/primitives/ciphers/__pycache__/modes.cpython-312.pyc,, cryptography/hazmat/primitives/ciphers/aead.py,sha256=Fzlyx7w8KYQakzDp1zWgJnIr62zgZrgVh1u2h4exB54,634 -cryptography/hazmat/primitives/ciphers/algorithms.py,sha256=cPzrUizm_RfUi7DDqf3WNezkFy2IxfllsJv6s16bWS8,4493 -cryptography/hazmat/primitives/ciphers/base.py,sha256=tg-XNaKUyETBi7ounGDEL1_ICn-s4FF9LR7moV58blI,4211 -cryptography/hazmat/primitives/ciphers/modes.py,sha256=BFpxEGSaxoeZjrQ4sqpyPDvKClrqfDKIBv7kYtFURhE,8192 +cryptography/hazmat/primitives/ciphers/algorithms.py,sha256=Q7ZJwcsx83Mgxv5y7r6CyJKSdsOwC-my-5A67-ma2vw,3407 +cryptography/hazmat/primitives/ciphers/base.py,sha256=aBC7HHBBoixebmparVr0UlODs3VD0A7B6oz_AaRjDv8,4253 +cryptography/hazmat/primitives/ciphers/modes.py,sha256=20stpwhDtbAvpH0SMf9EDHIciwmTF-JMBUOZ9bU8WiQ,8318 cryptography/hazmat/primitives/cmac.py,sha256=sz_s6H_cYnOvx-VNWdIKhRhe3Ymp8z8J0D3CBqOX3gg,338 cryptography/hazmat/primitives/constant_time.py,sha256=xdunWT0nf8OvKdcqUhhlFKayGp4_PgVJRU2W1wLSr_A,422 -cryptography/hazmat/primitives/hashes.py,sha256=EvDIJBhj83Z7f-oHbsA0TzZLFSDV_Yv8hQRdM4o8FD0,5091 +cryptography/hazmat/primitives/hashes.py,sha256=M8BrlKB3U6DEtHvWTV5VRjpteHv1kS3Zxm_Bsk04cr8,5184 cryptography/hazmat/primitives/hmac.py,sha256=RpB3z9z5skirCQrm7zQbtnp9pLMnAjrlTUvKqF5aDDc,423 cryptography/hazmat/primitives/kdf/__init__.py,sha256=4XibZnrYq4hh5xBjWiIXzaYW6FKx8hPbVaa_cB9zS64,750 cryptography/hazmat/primitives/kdf/__pycache__/__init__.cpython-312.pyc,, @@ -128,34 +133,34 @@ cryptography/hazmat/primitives/kdf/__pycache__/pbkdf2.cpython-312.pyc,, cryptography/hazmat/primitives/kdf/__pycache__/scrypt.cpython-312.pyc,, cryptography/hazmat/primitives/kdf/__pycache__/x963kdf.cpython-312.pyc,, cryptography/hazmat/primitives/kdf/argon2.py,sha256=UFDNXG0v-rw3DqAQTB1UQAsQC2M5Ejg0k_6OCyhLKus,460 -cryptography/hazmat/primitives/kdf/concatkdf.py,sha256=bcn4NGXse-EsFl7nlU83e5ilop7TSHcX-CJJS107W80,3686 -cryptography/hazmat/primitives/kdf/hkdf.py,sha256=uhN5L87w4JvtAqQcPh_Ji2TPSc18IDThpaYJiHOWy3A,3015 -cryptography/hazmat/primitives/kdf/kbkdf.py,sha256=eSuLK1sATkamgCAit794jLr7sDNlu5X0USdcWhwJdmk,9146 -cryptography/hazmat/primitives/kdf/pbkdf2.py,sha256=Xj3YIeX30h2BUaoJAtOo1RMXV_em0-eCG0PU_0FHJzM,1950 +cryptography/hazmat/primitives/kdf/concatkdf.py,sha256=Ua8KoLXXnzgsrAUmHpyKymaPt8aPRP0EHEaBz7QCQ9I,3737 +cryptography/hazmat/primitives/kdf/hkdf.py,sha256=M0lAEfRoc4kpp4-nwDj9yB-vNZukIOYEQrUlWsBNn9o,543 +cryptography/hazmat/primitives/kdf/kbkdf.py,sha256=oZepvo4evhKkkJQWRDwaPoIbyTaFmDc5NPimxg6lfKg,9165 +cryptography/hazmat/primitives/kdf/pbkdf2.py,sha256=1WIwhELR0w8ztTpTu8BrFiYWmK3hUfJq08I79TxwieE,1957 cryptography/hazmat/primitives/kdf/scrypt.py,sha256=XyWUdUUmhuI9V6TqAPOvujCSMGv1XQdg0a21IWCmO-U,590 -cryptography/hazmat/primitives/kdf/x963kdf.py,sha256=wCpWmwQjZ2vAu2rlk3R_PX0nINl8WGXYBmlyMOC5iPw,1992 +cryptography/hazmat/primitives/kdf/x963kdf.py,sha256=zLTcF665QFvXX2f8TS7fmBZTteXpFjKahzfjjQcCJyw,1999 cryptography/hazmat/primitives/keywrap.py,sha256=XV4Pj2fqSeD-RqZVvY2cA3j5_7RwJSFygYuLfk2ujCo,5650 -cryptography/hazmat/primitives/padding.py,sha256=Qu1VVsCiqfQMPPqU0qU6ig9Y802jZlXVOUDLIxN5KeQ,4932 +cryptography/hazmat/primitives/padding.py,sha256=QT-U-NvV2eQGO1wVPbDiNGNSc9keRDS-ig5cQOrLz0E,1865 cryptography/hazmat/primitives/poly1305.py,sha256=P5EPQV-RB_FJPahpg01u0Ts4S_PnAmsroxIGXbGeRRo,355 -cryptography/hazmat/primitives/serialization/__init__.py,sha256=jyNx_7NcOEbVRBY4nP9ks0IVXBafbcYnTK27vafPLW8,1653 +cryptography/hazmat/primitives/serialization/__init__.py,sha256=Q7uTgDlt7n3WfsMT6jYwutC6DIg_7SEeoAm1GHZ5B5E,1705 cryptography/hazmat/primitives/serialization/__pycache__/__init__.cpython-312.pyc,, cryptography/hazmat/primitives/serialization/__pycache__/base.cpython-312.pyc,, cryptography/hazmat/primitives/serialization/__pycache__/pkcs12.cpython-312.pyc,, cryptography/hazmat/primitives/serialization/__pycache__/pkcs7.cpython-312.pyc,, cryptography/hazmat/primitives/serialization/__pycache__/ssh.cpython-312.pyc,, cryptography/hazmat/primitives/serialization/base.py,sha256=ikq5MJIwp_oUnjiaBco_PmQwOTYuGi-XkYUYHKy8Vo0,615 -cryptography/hazmat/primitives/serialization/pkcs12.py,sha256=7vVXbiP7qhhvKAHJT_M8-LBZdbpOwrpWRHWxNrNqzXE,4492 -cryptography/hazmat/primitives/serialization/pkcs7.py,sha256=n25jEw__vkZWSlumwgYnqJ0lzyPh5xljMsJDyp2QomM,12346 -cryptography/hazmat/primitives/serialization/ssh.py,sha256=VKscMrVdYK5B9PQISjjdRMglRvqa_L3sDNm5vdjVHJY,51915 +cryptography/hazmat/primitives/serialization/pkcs12.py,sha256=mS9cFNG4afzvseoc5e1MWoY2VskfL8N8Y_OFjl67luY,5104 +cryptography/hazmat/primitives/serialization/pkcs7.py,sha256=5OR_Tkysxaprn4FegvJIfbep9rJ9wok6FLWvWwQ5-Mg,13943 +cryptography/hazmat/primitives/serialization/ssh.py,sha256=hPV5obFznz0QhFfXFPOeQ8y6MsurA0xVMQiLnLESEs8,53700 cryptography/hazmat/primitives/twofactor/__init__.py,sha256=tmMZGB-g4IU1r7lIFqASU019zr0uPp_wEBYcwdDCKCA,258 cryptography/hazmat/primitives/twofactor/__pycache__/__init__.cpython-312.pyc,, cryptography/hazmat/primitives/twofactor/__pycache__/hotp.cpython-312.pyc,, cryptography/hazmat/primitives/twofactor/__pycache__/totp.cpython-312.pyc,, -cryptography/hazmat/primitives/twofactor/hotp.py,sha256=rv507uNznUs22XlaqGBbZKkkGjmiTUAcwghTYMem6uM,3219 -cryptography/hazmat/primitives/twofactor/totp.py,sha256=BQ0oPTp2JW1SMZqdgv95NBG3u_ODiDtzVJENHWYhvXY,1613 +cryptography/hazmat/primitives/twofactor/hotp.py,sha256=ivZo5BrcCGWLsqql4nZV0XXCjyGPi_iHfDFltGlOJwk,3256 +cryptography/hazmat/primitives/twofactor/totp.py,sha256=m5LPpRL00kp4zY8gTjr55Hfz9aMlPS53kHmVkSQCmdY,1652 cryptography/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -cryptography/utils.py,sha256=Rp7ppg4XIBVVzNQ6XngGndwkICJoYp6FoFOOgTWLJ7g,3925 -cryptography/x509/__init__.py,sha256=Q8P-MnUGrgFxRt5423bE-gzSvgZLAdddWuPheHnuA_c,8132 +cryptography/utils.py,sha256=bZAjFC5KVpfmF29qS_18vvpW3mKxmdiRALcusHhTTkg,4301 +cryptography/x509/__init__.py,sha256=xloN0swseNx-m2WFZmCA17gOoxQWqeU82UVjEdJBePQ,8257 cryptography/x509/__pycache__/__init__.cpython-312.pyc,, cryptography/x509/__pycache__/base.cpython-312.pyc,, cryptography/x509/__pycache__/certificate_transparency.cpython-312.pyc,, @@ -165,18 +170,11 @@ cryptography/x509/__pycache__/name.cpython-312.pyc,, cryptography/x509/__pycache__/ocsp.cpython-312.pyc,, cryptography/x509/__pycache__/oid.cpython-312.pyc,, cryptography/x509/__pycache__/verification.cpython-312.pyc,, -cryptography/x509/base.py,sha256=-F5KWjxbyjSqluUSr7LRC_sqN_s-qHP5K0rW-41PI4E,26909 +cryptography/x509/base.py,sha256=OrmTw3y8B6AE_nGXQPN8x9kq-d7rDWeH13gCq6T6D6U,27997 cryptography/x509/certificate_transparency.py,sha256=JqoOIDhlwInrYMFW6IFn77WJ0viF-PB_rlZV3vs9MYc,797 -cryptography/x509/extensions.py,sha256=iX-3WFm4yFjstFIs1F30f3tixIp6i0WgGdc6GwJ-QiQ,76158 +cryptography/x509/extensions.py,sha256=QxYrqR6SF1qzR9ZraP8wDiIczlEVlAFuwDRVcltB6Tk,77724 cryptography/x509/general_name.py,sha256=sP_rV11Qlpsk4x3XXGJY_Mv0Q_s9dtjeLckHsjpLQoQ,7836 -cryptography/x509/name.py,sha256=MYCxCSTQTpzhjxFPZaANqJ9fGrhESH73vPkoay8HSWM,14830 -cryptography/x509/ocsp.py,sha256=vbrg3p1hBJQEEFIZ35GHcjbGwTrsxPhlot-OVpyP-C8,11390 -cryptography/x509/oid.py,sha256=X8EbhkRTLrGuv9vHZSGqPd9zpvRVsonU_joWAL5LLY8,885 -cryptography/x509/verification.py,sha256=alfx3VaTSb2bMz7_7s788oL90vzgHwBjVINssdz0Gv0,796 -rust/Cargo.toml,sha256=gaBJTn9TwBCG7U3JgETYbTmK8DNUxl4gKKS65nDWuwM,1320 -rust/cryptography-cffi/Cargo.toml,sha256=CjVBJTYW1TwzXgLgY8TZ92NP_9XSmHzSfRIzVaZh9Bk,386 -rust/cryptography-keepalive/Cargo.toml,sha256=_ABt1o-uFnxDqhb7YzNynb6YEQ2eW2QpnPD1RXBUsrI,210 -rust/cryptography-key-parsing/Cargo.toml,sha256=yLWh172kspq6BJVZA2PjFw17Rt0xTYKn_TTzp3IVhxg,455 -rust/cryptography-openssl/Cargo.toml,sha256=mI0cIDv-kQTl24C-bLvDCqiWn6QobBdqCMYSi_UWPE0,545 -rust/cryptography-x509-verification/Cargo.toml,sha256=vECbxPiNu-dQhW4baTuSPzgqaBnBgwZYnJCSaJQbIUA,426 -rust/cryptography-x509/Cargo.toml,sha256=wAuwnc1eKnSUNFjf4GpQM__FTig-hqF2ZPXJPmqb6cA,248 +cryptography/x509/name.py,sha256=ty0_xf0LnHwZAdEf-d8FLO1K4hGqx_7DsD3CHwoLJiY,15101 +cryptography/x509/ocsp.py,sha256=Yey6NdFV1MPjop24Mj_VenjEpg3kUaMopSWOK0AbeBs,12699 +cryptography/x509/oid.py,sha256=BUzgXXGVWilkBkdKPTm9R4qElE9gAGHgdYPMZAp7PJo,931 +cryptography/x509/verification.py,sha256=gR2C2c-XZQtblZhT5T5vjSKOtCb74ef2alPVmEcwFlM,958 diff --git a/venv/Lib/site-packages/cryptography-46.0.3.dist-info/WHEEL b/venv/Lib/site-packages/cryptography-46.0.3.dist-info/WHEEL new file mode 100644 index 0000000..dcfb13d --- /dev/null +++ b/venv/Lib/site-packages/cryptography-46.0.3.dist-info/WHEEL @@ -0,0 +1,4 @@ +Wheel-Version: 1.0 +Generator: maturin (1.9.4) +Root-Is-Purelib: false +Tag: cp311-abi3-win_amd64 diff --git a/venv/Lib/site-packages/cryptography-44.0.3.dist-info/licenses/LICENSE b/venv/Lib/site-packages/cryptography-46.0.3.dist-info/licenses/LICENSE similarity index 100% rename from venv/Lib/site-packages/cryptography-44.0.3.dist-info/licenses/LICENSE rename to venv/Lib/site-packages/cryptography-46.0.3.dist-info/licenses/LICENSE diff --git a/venv/Lib/site-packages/cryptography-44.0.3.dist-info/licenses/LICENSE.APACHE b/venv/Lib/site-packages/cryptography-46.0.3.dist-info/licenses/LICENSE.APACHE similarity index 100% rename from venv/Lib/site-packages/cryptography-44.0.3.dist-info/licenses/LICENSE.APACHE rename to venv/Lib/site-packages/cryptography-46.0.3.dist-info/licenses/LICENSE.APACHE diff --git a/venv/Lib/site-packages/cryptography-44.0.3.dist-info/licenses/LICENSE.BSD b/venv/Lib/site-packages/cryptography-46.0.3.dist-info/licenses/LICENSE.BSD similarity index 100% rename from venv/Lib/site-packages/cryptography-44.0.3.dist-info/licenses/LICENSE.BSD rename to venv/Lib/site-packages/cryptography-46.0.3.dist-info/licenses/LICENSE.BSD diff --git a/venv/Lib/site-packages/cryptography/__about__.py b/venv/Lib/site-packages/cryptography/__about__.py index 8bbf96e..a811628 100644 --- a/venv/Lib/site-packages/cryptography/__about__.py +++ b/venv/Lib/site-packages/cryptography/__about__.py @@ -10,8 +10,8 @@ __all__ = [ "__version__", ] -__version__ = "44.0.3" +__version__ = "46.0.3" __author__ = "The Python Cryptographic Authority and individual contributors" -__copyright__ = f"Copyright 2013-2024 {__author__}" +__copyright__ = f"Copyright 2013-2025 {__author__}" diff --git a/venv/Lib/site-packages/cryptography/__init__.py b/venv/Lib/site-packages/cryptography/__init__.py index f37370e..d374f75 100644 --- a/venv/Lib/site-packages/cryptography/__init__.py +++ b/venv/Lib/site-packages/cryptography/__init__.py @@ -4,10 +4,6 @@ from __future__ import annotations -import sys -import warnings - -from cryptography import utils from cryptography.__about__ import __author__, __copyright__, __version__ __all__ = [ @@ -15,12 +11,3 @@ __all__ = [ "__copyright__", "__version__", ] - -if sys.version_info[:2] == (3, 7): - warnings.warn( - "Python 3.7 is no longer supported by the Python core team " - "and support for it is deprecated in cryptography. A future " - "release of cryptography will remove support for Python 3.7.", - utils.CryptographyDeprecationWarning, - stacklevel=2, - ) diff --git a/venv/Lib/site-packages/cryptography/__pycache__/__about__.cpython-312.pyc b/venv/Lib/site-packages/cryptography/__pycache__/__about__.cpython-312.pyc index 7492a9e..221a8b8 100644 Binary files a/venv/Lib/site-packages/cryptography/__pycache__/__about__.cpython-312.pyc and b/venv/Lib/site-packages/cryptography/__pycache__/__about__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/cryptography/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/cryptography/__pycache__/__init__.cpython-312.pyc index 1392813..9a5aab1 100644 Binary files a/venv/Lib/site-packages/cryptography/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/cryptography/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/cryptography/__pycache__/exceptions.cpython-312.pyc b/venv/Lib/site-packages/cryptography/__pycache__/exceptions.cpython-312.pyc index 06de9d0..c809fa5 100644 Binary files a/venv/Lib/site-packages/cryptography/__pycache__/exceptions.cpython-312.pyc and b/venv/Lib/site-packages/cryptography/__pycache__/exceptions.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/cryptography/__pycache__/fernet.cpython-312.pyc b/venv/Lib/site-packages/cryptography/__pycache__/fernet.cpython-312.pyc index 35580f7..cb9a59a 100644 Binary files a/venv/Lib/site-packages/cryptography/__pycache__/fernet.cpython-312.pyc and b/venv/Lib/site-packages/cryptography/__pycache__/fernet.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/cryptography/__pycache__/utils.cpython-312.pyc b/venv/Lib/site-packages/cryptography/__pycache__/utils.cpython-312.pyc index b8a66e1..8eeff62 100644 Binary files a/venv/Lib/site-packages/cryptography/__pycache__/utils.cpython-312.pyc and b/venv/Lib/site-packages/cryptography/__pycache__/utils.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/cryptography/fernet.py b/venv/Lib/site-packages/cryptography/fernet.py index 868ecb2..c6744ae 100644 --- a/venv/Lib/site-packages/cryptography/fernet.py +++ b/venv/Lib/site-packages/cryptography/fernet.py @@ -9,6 +9,7 @@ import binascii import os import time import typing +from collections.abc import Iterable from cryptography import utils from cryptography.exceptions import InvalidSignature @@ -168,7 +169,7 @@ class Fernet: class MultiFernet: - def __init__(self, fernets: typing.Iterable[Fernet]): + def __init__(self, fernets: Iterable[Fernet]): fernets = list(fernets) if not fernets: raise ValueError( diff --git a/venv/Lib/site-packages/cryptography/hazmat/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/cryptography/hazmat/__pycache__/__init__.cpython-312.pyc index 642f41d..4e7e156 100644 Binary files a/venv/Lib/site-packages/cryptography/hazmat/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/cryptography/hazmat/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/cryptography/hazmat/__pycache__/_oid.cpython-312.pyc b/venv/Lib/site-packages/cryptography/hazmat/__pycache__/_oid.cpython-312.pyc index 3bb010a..f598656 100644 Binary files a/venv/Lib/site-packages/cryptography/hazmat/__pycache__/_oid.cpython-312.pyc and b/venv/Lib/site-packages/cryptography/hazmat/__pycache__/_oid.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/cryptography/hazmat/_oid.py b/venv/Lib/site-packages/cryptography/hazmat/_oid.py index 8bd240d..4bf138d 100644 --- a/venv/Lib/site-packages/cryptography/hazmat/_oid.py +++ b/venv/Lib/site-packages/cryptography/hazmat/_oid.py @@ -14,6 +14,7 @@ class ExtensionOID: SUBJECT_DIRECTORY_ATTRIBUTES = ObjectIdentifier("2.5.29.9") SUBJECT_KEY_IDENTIFIER = ObjectIdentifier("2.5.29.14") KEY_USAGE = ObjectIdentifier("2.5.29.15") + PRIVATE_KEY_USAGE_PERIOD = ObjectIdentifier("2.5.29.16") SUBJECT_ALTERNATIVE_NAME = ObjectIdentifier("2.5.29.17") ISSUER_ALTERNATIVE_NAME = ObjectIdentifier("2.5.29.18") BASIC_CONSTRAINTS = ObjectIdentifier("2.5.29.19") @@ -155,6 +156,22 @@ _SIG_OIDS_TO_HASH: dict[ObjectIdentifier, hashes.HashAlgorithm | None] = { } +class HashAlgorithmOID: + SHA1 = ObjectIdentifier("1.3.14.3.2.26") + SHA224 = ObjectIdentifier("2.16.840.1.101.3.4.2.4") + SHA256 = ObjectIdentifier("2.16.840.1.101.3.4.2.1") + SHA384 = ObjectIdentifier("2.16.840.1.101.3.4.2.2") + SHA512 = ObjectIdentifier("2.16.840.1.101.3.4.2.3") + SHA3_224 = ObjectIdentifier("1.3.6.1.4.1.37476.3.2.1.99.7.224") + SHA3_256 = ObjectIdentifier("1.3.6.1.4.1.37476.3.2.1.99.7.256") + SHA3_384 = ObjectIdentifier("1.3.6.1.4.1.37476.3.2.1.99.7.384") + SHA3_512 = ObjectIdentifier("1.3.6.1.4.1.37476.3.2.1.99.7.512") + SHA3_224_NIST = ObjectIdentifier("2.16.840.1.101.3.4.2.7") + SHA3_256_NIST = ObjectIdentifier("2.16.840.1.101.3.4.2.8") + SHA3_384_NIST = ObjectIdentifier("2.16.840.1.101.3.4.2.9") + SHA3_512_NIST = ObjectIdentifier("2.16.840.1.101.3.4.2.10") + + class PublicKeyAlgorithmOID: DSA = ObjectIdentifier("1.2.840.10040.4.1") EC_PUBLIC_KEY = ObjectIdentifier("1.2.840.10045.2.1") @@ -177,9 +194,20 @@ class ExtendedKeyUsageOID: SMARTCARD_LOGON = ObjectIdentifier("1.3.6.1.4.1.311.20.2.2") KERBEROS_PKINIT_KDC = ObjectIdentifier("1.3.6.1.5.2.3.5") IPSEC_IKE = ObjectIdentifier("1.3.6.1.5.5.7.3.17") + BUNDLE_SECURITY = ObjectIdentifier("1.3.6.1.5.5.7.3.35") CERTIFICATE_TRANSPARENCY = ObjectIdentifier("1.3.6.1.4.1.11129.2.4.4") +class OtherNameFormOID: + PERMANENT_IDENTIFIER = ObjectIdentifier("1.3.6.1.5.5.7.8.3") + HW_MODULE_NAME = ObjectIdentifier("1.3.6.1.5.5.7.8.4") + DNS_SRV = ObjectIdentifier("1.3.6.1.5.5.7.8.7") + NAI_REALM = ObjectIdentifier("1.3.6.1.5.5.7.8.8") + SMTP_UTF8_MAILBOX = ObjectIdentifier("1.3.6.1.5.5.7.8.9") + ACP_NODE_NAME = ObjectIdentifier("1.3.6.1.5.5.7.8.10") + BUNDLE_EID = ObjectIdentifier("1.3.6.1.5.5.7.8.11") + + class AuthorityInformationAccessOID: CA_ISSUERS = ObjectIdentifier("1.3.6.1.5.5.7.48.2") OCSP = ObjectIdentifier("1.3.6.1.5.5.7.48.1") @@ -237,7 +265,7 @@ _OID_NAMES = { SignatureAlgorithmOID.RSA_WITH_SHA256: "sha256WithRSAEncryption", SignatureAlgorithmOID.RSA_WITH_SHA384: "sha384WithRSAEncryption", SignatureAlgorithmOID.RSA_WITH_SHA512: "sha512WithRSAEncryption", - SignatureAlgorithmOID.RSASSA_PSS: "RSASSA-PSS", + SignatureAlgorithmOID.RSASSA_PSS: "rsassaPss", SignatureAlgorithmOID.ECDSA_WITH_SHA1: "ecdsa-with-SHA1", SignatureAlgorithmOID.ECDSA_WITH_SHA224: "ecdsa-with-SHA224", SignatureAlgorithmOID.ECDSA_WITH_SHA256: "ecdsa-with-SHA256", @@ -257,10 +285,22 @@ _OID_NAMES = { SignatureAlgorithmOID.GOSTR3410_2012_WITH_3411_2012_512: ( "GOST R 34.10-2012 with GOST R 34.11-2012 (512 bit)" ), + HashAlgorithmOID.SHA1: "sha1", + HashAlgorithmOID.SHA224: "sha224", + HashAlgorithmOID.SHA256: "sha256", + HashAlgorithmOID.SHA384: "sha384", + HashAlgorithmOID.SHA512: "sha512", + HashAlgorithmOID.SHA3_224: "sha3_224", + HashAlgorithmOID.SHA3_256: "sha3_256", + HashAlgorithmOID.SHA3_384: "sha3_384", + HashAlgorithmOID.SHA3_512: "sha3_512", + HashAlgorithmOID.SHA3_224_NIST: "sha3_224", + HashAlgorithmOID.SHA3_256_NIST: "sha3_256", + HashAlgorithmOID.SHA3_384_NIST: "sha3_384", + HashAlgorithmOID.SHA3_512_NIST: "sha3_512", PublicKeyAlgorithmOID.DSA: "dsaEncryption", PublicKeyAlgorithmOID.EC_PUBLIC_KEY: "id-ecPublicKey", PublicKeyAlgorithmOID.RSAES_PKCS1_v1_5: "rsaEncryption", - PublicKeyAlgorithmOID.RSASSA_PSS: "rsassaPss", PublicKeyAlgorithmOID.X25519: "X25519", PublicKeyAlgorithmOID.X448: "X448", ExtendedKeyUsageOID.SERVER_AUTH: "serverAuth", @@ -274,6 +314,7 @@ _OID_NAMES = { ExtensionOID.SUBJECT_DIRECTORY_ATTRIBUTES: "subjectDirectoryAttributes", ExtensionOID.SUBJECT_KEY_IDENTIFIER: "subjectKeyIdentifier", ExtensionOID.KEY_USAGE: "keyUsage", + ExtensionOID.PRIVATE_KEY_USAGE_PERIOD: "privateKeyUsagePeriod", ExtensionOID.SUBJECT_ALTERNATIVE_NAME: "subjectAltName", ExtensionOID.ISSUER_ALTERNATIVE_NAME: "issuerAltName", ExtensionOID.BASIC_CONSTRAINTS: "basicConstraints", diff --git a/venv/Lib/site-packages/cryptography/hazmat/asn1/__init__.py b/venv/Lib/site-packages/cryptography/hazmat/asn1/__init__.py new file mode 100644 index 0000000..be68373 --- /dev/null +++ b/venv/Lib/site-packages/cryptography/hazmat/asn1/__init__.py @@ -0,0 +1,10 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from cryptography.hazmat.asn1.asn1 import encode_der, sequence + +__all__ = [ + "encode_der", + "sequence", +] diff --git a/venv/Lib/site-packages/cryptography/hazmat/asn1/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/cryptography/hazmat/asn1/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000..43c39c2 Binary files /dev/null and b/venv/Lib/site-packages/cryptography/hazmat/asn1/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/cryptography/hazmat/asn1/__pycache__/asn1.cpython-312.pyc b/venv/Lib/site-packages/cryptography/hazmat/asn1/__pycache__/asn1.cpython-312.pyc new file mode 100644 index 0000000..06c0de1 Binary files /dev/null and b/venv/Lib/site-packages/cryptography/hazmat/asn1/__pycache__/asn1.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/cryptography/hazmat/asn1/asn1.py b/venv/Lib/site-packages/cryptography/hazmat/asn1/asn1.py new file mode 100644 index 0000000..dedad6f --- /dev/null +++ b/venv/Lib/site-packages/cryptography/hazmat/asn1/asn1.py @@ -0,0 +1,116 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import annotations + +import dataclasses +import sys +import typing + +if sys.version_info < (3, 11): + import typing_extensions + + # We use the `include_extras` parameter of `get_type_hints`, which was + # added in Python 3.9. This can be replaced by the `typing` version + # once the min version is >= 3.9 + if sys.version_info < (3, 9): + get_type_hints = typing_extensions.get_type_hints + else: + get_type_hints = typing.get_type_hints +else: + get_type_hints = typing.get_type_hints + +from cryptography.hazmat.bindings._rust import declarative_asn1 + +T = typing.TypeVar("T", covariant=True) +U = typing.TypeVar("U") + + +encode_der = declarative_asn1.encode_der + + +def _normalize_field_type( + field_type: typing.Any, field_name: str +) -> declarative_asn1.AnnotatedType: + annotation = declarative_asn1.Annotation() + + if hasattr(field_type, "__asn1_root__"): + annotated_root = field_type.__asn1_root__ + if not isinstance(annotated_root, declarative_asn1.AnnotatedType): + raise TypeError(f"unsupported root type: {annotated_root}") + return annotated_root + else: + rust_field_type = declarative_asn1.non_root_python_to_rust(field_type) + + return declarative_asn1.AnnotatedType(rust_field_type, annotation) + + +def _annotate_fields( + raw_fields: dict[str, type], +) -> dict[str, declarative_asn1.AnnotatedType]: + fields = {} + for field_name, field_type in raw_fields.items(): + # Recursively normalize the field type into something that the + # Rust code can understand. + annotated_field_type = _normalize_field_type(field_type, field_name) + fields[field_name] = annotated_field_type + + return fields + + +def _register_asn1_sequence(cls: type[U]) -> None: + raw_fields = get_type_hints(cls, include_extras=True) + root = declarative_asn1.AnnotatedType( + declarative_asn1.Type.Sequence(cls, _annotate_fields(raw_fields)), + declarative_asn1.Annotation(), + ) + + setattr(cls, "__asn1_root__", root) + + +# Due to https://github.com/python/mypy/issues/19731, we can't define an alias +# for `dataclass_transform` that conditionally points to `typing` or +# `typing_extensions` depending on the Python version (like we do for +# `get_type_hints`). +# We work around it by making the whole decorated class conditional on the +# Python version. +if sys.version_info < (3, 11): + + @typing_extensions.dataclass_transform(kw_only_default=True) + def sequence(cls: type[U]) -> type[U]: + # We use `dataclasses.dataclass` to add an __init__ method + # to the class with keyword-only parameters. + if sys.version_info >= (3, 10): + dataclass_cls = dataclasses.dataclass( + repr=False, + eq=False, + # `match_args` was added in Python 3.10 and defaults + # to True + match_args=False, + # `kw_only` was added in Python 3.10 and defaults to + # False + kw_only=True, + )(cls) + else: + dataclass_cls = dataclasses.dataclass( + repr=False, + eq=False, + )(cls) + _register_asn1_sequence(dataclass_cls) + return dataclass_cls + +else: + + @typing.dataclass_transform(kw_only_default=True) + def sequence(cls: type[U]) -> type[U]: + # Only add an __init__ method, with keyword-only + # parameters. + dataclass_cls = dataclasses.dataclass( + repr=False, + eq=False, + match_args=False, + kw_only=True, + )(cls) + _register_asn1_sequence(dataclass_cls) + return dataclass_cls diff --git a/venv/Lib/site-packages/cryptography/hazmat/backends/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/cryptography/hazmat/backends/__pycache__/__init__.cpython-312.pyc index 8bda4ed..a6355d0 100644 Binary files a/venv/Lib/site-packages/cryptography/hazmat/backends/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/cryptography/hazmat/backends/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/cryptography/hazmat/backends/openssl/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/cryptography/hazmat/backends/openssl/__pycache__/__init__.cpython-312.pyc index a75caaf..b94f428 100644 Binary files a/venv/Lib/site-packages/cryptography/hazmat/backends/openssl/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/cryptography/hazmat/backends/openssl/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/cryptography/hazmat/backends/openssl/__pycache__/backend.cpython-312.pyc b/venv/Lib/site-packages/cryptography/hazmat/backends/openssl/__pycache__/backend.cpython-312.pyc index 30f1dd0..d58c775 100644 Binary files a/venv/Lib/site-packages/cryptography/hazmat/backends/openssl/__pycache__/backend.cpython-312.pyc and b/venv/Lib/site-packages/cryptography/hazmat/backends/openssl/__pycache__/backend.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/cryptography/hazmat/backends/openssl/backend.py b/venv/Lib/site-packages/cryptography/hazmat/backends/openssl/backend.py index 34899d4..248b8c5 100644 --- a/venv/Lib/site-packages/cryptography/hazmat/backends/openssl/backend.py +++ b/venv/Lib/site-packages/cryptography/hazmat/backends/openssl/backend.py @@ -132,7 +132,19 @@ class Backend: # FIPS mode still allows SHA1 for HMAC if self._fips_enabled and isinstance(algorithm, hashes.SHA1): return True - + if rust_openssl.CRYPTOGRAPHY_IS_AWSLC: + return isinstance( + algorithm, + ( + hashes.SHA1, + hashes.SHA224, + hashes.SHA256, + hashes.SHA384, + hashes.SHA512, + hashes.SHA512_224, + hashes.SHA512_256, + ), + ) return self.hash_supported(algorithm) def cipher_supported(self, cipher: CipherAlgorithm, mode: Mode) -> bool: @@ -239,15 +251,16 @@ class Backend: ) def dh_supported(self) -> bool: - return not rust_openssl.CRYPTOGRAPHY_IS_BORINGSSL + return ( + not rust_openssl.CRYPTOGRAPHY_IS_BORINGSSL + and not rust_openssl.CRYPTOGRAPHY_IS_AWSLC + ) def dh_x942_serialization_supported(self) -> bool: return self._lib.Cryptography_HAS_EVP_PKEY_DHX == 1 def x25519_supported(self) -> bool: - if self._fips_enabled: - return False - return True + return not self._fips_enabled def x448_supported(self) -> bool: if self._fips_enabled: @@ -255,12 +268,11 @@ class Backend: return ( not rust_openssl.CRYPTOGRAPHY_IS_LIBRESSL and not rust_openssl.CRYPTOGRAPHY_IS_BORINGSSL + and not rust_openssl.CRYPTOGRAPHY_IS_AWSLC ) def ed25519_supported(self) -> bool: - if self._fips_enabled: - return False - return True + return not self._fips_enabled def ed448_supported(self) -> bool: if self._fips_enabled: @@ -268,6 +280,7 @@ class Backend: return ( not rust_openssl.CRYPTOGRAPHY_IS_LIBRESSL and not rust_openssl.CRYPTOGRAPHY_IS_BORINGSSL + and not rust_openssl.CRYPTOGRAPHY_IS_AWSLC ) def ecdsa_deterministic_supported(self) -> bool: @@ -277,12 +290,13 @@ class Backend: ) def poly1305_supported(self) -> bool: - if self._fips_enabled: - return False - return True + return not self._fips_enabled def pkcs7_supported(self) -> bool: - return not rust_openssl.CRYPTOGRAPHY_IS_BORINGSSL + return ( + not rust_openssl.CRYPTOGRAPHY_IS_BORINGSSL + and not rust_openssl.CRYPTOGRAPHY_IS_AWSLC + ) backend = Backend() diff --git a/venv/Lib/site-packages/cryptography/hazmat/bindings/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/cryptography/hazmat/bindings/__pycache__/__init__.cpython-312.pyc index 1f6f46c..84eec86 100644 Binary files a/venv/Lib/site-packages/cryptography/hazmat/bindings/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/cryptography/hazmat/bindings/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/cryptography/hazmat/bindings/_rust.pyd b/venv/Lib/site-packages/cryptography/hazmat/bindings/_rust.pyd index 7d8f8ab..5c93835 100644 Binary files a/venv/Lib/site-packages/cryptography/hazmat/bindings/_rust.pyd and b/venv/Lib/site-packages/cryptography/hazmat/bindings/_rust.pyd differ diff --git a/venv/Lib/site-packages/cryptography/hazmat/bindings/_rust/__init__.pyi b/venv/Lib/site-packages/cryptography/hazmat/bindings/_rust/__init__.pyi index 30b67d8..2f4eef4 100644 --- a/venv/Lib/site-packages/cryptography/hazmat/bindings/_rust/__init__.pyi +++ b/venv/Lib/site-packages/cryptography/hazmat/bindings/_rust/__init__.pyi @@ -5,21 +5,30 @@ import typing from cryptography.hazmat.primitives import padding - -def check_ansix923_padding(data: bytes) -> bool: ... +from cryptography.utils import Buffer class PKCS7PaddingContext(padding.PaddingContext): def __init__(self, block_size: int) -> None: ... - def update(self, data: bytes) -> bytes: ... + def update(self, data: Buffer) -> bytes: ... + def finalize(self) -> bytes: ... + +class ANSIX923PaddingContext(padding.PaddingContext): + def __init__(self, block_size: int) -> None: ... + def update(self, data: Buffer) -> bytes: ... def finalize(self) -> bytes: ... class PKCS7UnpaddingContext(padding.PaddingContext): def __init__(self, block_size: int) -> None: ... - def update(self, data: bytes) -> bytes: ... + def update(self, data: Buffer) -> bytes: ... + def finalize(self) -> bytes: ... + +class ANSIX923UnpaddingContext(padding.PaddingContext): + def __init__(self, block_size: int) -> None: ... + def update(self, data: Buffer) -> bytes: ... def finalize(self) -> bytes: ... class ObjectIdentifier: - def __init__(self, val: str) -> None: ... + def __init__(self, value: str) -> None: ... @property def dotted_string(self) -> str: ... @property diff --git a/venv/Lib/site-packages/cryptography/hazmat/bindings/_rust/declarative_asn1.pyi b/venv/Lib/site-packages/cryptography/hazmat/bindings/_rust/declarative_asn1.pyi new file mode 100644 index 0000000..8563c11 --- /dev/null +++ b/venv/Lib/site-packages/cryptography/hazmat/bindings/_rust/declarative_asn1.pyi @@ -0,0 +1,32 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. +import typing + +def encode_der(value: typing.Any) -> bytes: ... +def non_root_python_to_rust(cls: type) -> Type: ... + +# Type is a Rust enum with tuple variants. For now, we express the type +# annotations like this: +class Type: + Sequence: typing.ClassVar[type] + PyInt: typing.ClassVar[type] + +class Annotation: + def __new__( + cls, + ) -> Annotation: ... + +class AnnotatedType: + inner: Type + annotation: Annotation + + def __new__(cls, inner: Type, annotation: Annotation) -> AnnotatedType: ... + +class AnnotatedTypeObject: + annotated_type: AnnotatedType + value: typing.Any + + def __new__( + cls, annotated_type: AnnotatedType, value: typing.Any + ) -> AnnotatedTypeObject: ... diff --git a/venv/Lib/site-packages/cryptography/hazmat/bindings/_rust/ocsp.pyi b/venv/Lib/site-packages/cryptography/hazmat/bindings/_rust/ocsp.pyi index e4321be..103e96c 100644 --- a/venv/Lib/site-packages/cryptography/hazmat/bindings/_rust/ocsp.pyi +++ b/venv/Lib/site-packages/cryptography/hazmat/bindings/_rust/ocsp.pyi @@ -3,7 +3,7 @@ # for complete details. import datetime -import typing +from collections.abc import Iterator from cryptography import x509 from cryptography.hazmat.primitives import hashes, serialization @@ -25,7 +25,7 @@ class OCSPRequest: class OCSPResponse: @property - def responses(self) -> typing.Iterator[OCSPSingleResponse]: ... + def responses(self) -> Iterator[OCSPSingleResponse]: ... @property def response_status(self) -> ocsp.OCSPResponseStatus: ... @property diff --git a/venv/Lib/site-packages/cryptography/hazmat/bindings/_rust/openssl/__init__.pyi b/venv/Lib/site-packages/cryptography/hazmat/bindings/_rust/openssl/__init__.pyi index 320cef1..5fb3cb2 100644 --- a/venv/Lib/site-packages/cryptography/hazmat/bindings/_rust/openssl/__init__.pyi +++ b/venv/Lib/site-packages/cryptography/hazmat/bindings/_rust/openssl/__init__.pyi @@ -47,9 +47,12 @@ __all__ = [ CRYPTOGRAPHY_IS_LIBRESSL: bool CRYPTOGRAPHY_IS_BORINGSSL: bool +CRYPTOGRAPHY_IS_AWSLC: bool CRYPTOGRAPHY_OPENSSL_300_OR_GREATER: bool CRYPTOGRAPHY_OPENSSL_309_OR_GREATER: bool CRYPTOGRAPHY_OPENSSL_320_OR_GREATER: bool +CRYPTOGRAPHY_OPENSSL_330_OR_GREATER: bool +CRYPTOGRAPHY_OPENSSL_350_OR_GREATER: bool class Providers: ... diff --git a/venv/Lib/site-packages/cryptography/hazmat/bindings/_rust/openssl/aead.pyi b/venv/Lib/site-packages/cryptography/hazmat/bindings/_rust/openssl/aead.pyi index 047f49d..831fcd1 100644 --- a/venv/Lib/site-packages/cryptography/hazmat/bindings/_rust/openssl/aead.pyi +++ b/venv/Lib/site-packages/cryptography/hazmat/bindings/_rust/openssl/aead.pyi @@ -2,102 +2,106 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from collections.abc import Sequence + +from cryptography.utils import Buffer + class AESGCM: - def __init__(self, key: bytes) -> None: ... + def __init__(self, key: Buffer) -> None: ... @staticmethod - def generate_key(key_size: int) -> bytes: ... + def generate_key(bit_length: int) -> bytes: ... def encrypt( self, - nonce: bytes, - data: bytes, - associated_data: bytes | None, + nonce: Buffer, + data: Buffer, + associated_data: Buffer | None, ) -> bytes: ... def decrypt( self, - nonce: bytes, - data: bytes, - associated_data: bytes | None, + nonce: Buffer, + data: Buffer, + associated_data: Buffer | None, ) -> bytes: ... class ChaCha20Poly1305: - def __init__(self, key: bytes) -> None: ... + def __init__(self, key: Buffer) -> None: ... @staticmethod def generate_key() -> bytes: ... def encrypt( self, - nonce: bytes, - data: bytes, - associated_data: bytes | None, + nonce: Buffer, + data: Buffer, + associated_data: Buffer | None, ) -> bytes: ... def decrypt( self, - nonce: bytes, - data: bytes, - associated_data: bytes | None, + nonce: Buffer, + data: Buffer, + associated_data: Buffer | None, ) -> bytes: ... class AESCCM: - def __init__(self, key: bytes, tag_length: int = 16) -> None: ... + def __init__(self, key: Buffer, tag_length: int = 16) -> None: ... @staticmethod - def generate_key(key_size: int) -> bytes: ... + def generate_key(bit_length: int) -> bytes: ... def encrypt( self, - nonce: bytes, - data: bytes, - associated_data: bytes | None, + nonce: Buffer, + data: Buffer, + associated_data: Buffer | None, ) -> bytes: ... def decrypt( self, - nonce: bytes, - data: bytes, - associated_data: bytes | None, + nonce: Buffer, + data: Buffer, + associated_data: Buffer | None, ) -> bytes: ... class AESSIV: - def __init__(self, key: bytes) -> None: ... + def __init__(self, key: Buffer) -> None: ... @staticmethod - def generate_key(key_size: int) -> bytes: ... + def generate_key(bit_length: int) -> bytes: ... def encrypt( self, - data: bytes, - associated_data: list[bytes] | None, + data: Buffer, + associated_data: Sequence[Buffer] | None, ) -> bytes: ... def decrypt( self, - data: bytes, - associated_data: list[bytes] | None, + data: Buffer, + associated_data: Sequence[Buffer] | None, ) -> bytes: ... class AESOCB3: - def __init__(self, key: bytes) -> None: ... + def __init__(self, key: Buffer) -> None: ... @staticmethod - def generate_key(key_size: int) -> bytes: ... + def generate_key(bit_length: int) -> bytes: ... def encrypt( self, - nonce: bytes, - data: bytes, - associated_data: bytes | None, + nonce: Buffer, + data: Buffer, + associated_data: Buffer | None, ) -> bytes: ... def decrypt( self, - nonce: bytes, - data: bytes, - associated_data: bytes | None, + nonce: Buffer, + data: Buffer, + associated_data: Buffer | None, ) -> bytes: ... class AESGCMSIV: - def __init__(self, key: bytes) -> None: ... + def __init__(self, key: Buffer) -> None: ... @staticmethod - def generate_key(key_size: int) -> bytes: ... + def generate_key(bit_length: int) -> bytes: ... def encrypt( self, - nonce: bytes, - data: bytes, - associated_data: bytes | None, + nonce: Buffer, + data: Buffer, + associated_data: Buffer | None, ) -> bytes: ... def decrypt( self, - nonce: bytes, - data: bytes, - associated_data: bytes | None, + nonce: Buffer, + data: Buffer, + associated_data: Buffer | None, ) -> bytes: ... diff --git a/venv/Lib/site-packages/cryptography/hazmat/bindings/_rust/openssl/ciphers.pyi b/venv/Lib/site-packages/cryptography/hazmat/bindings/_rust/openssl/ciphers.pyi index 759f3b5..a48fb01 100644 --- a/venv/Lib/site-packages/cryptography/hazmat/bindings/_rust/openssl/ciphers.pyi +++ b/venv/Lib/site-packages/cryptography/hazmat/bindings/_rust/openssl/ciphers.pyi @@ -13,7 +13,7 @@ def create_encryption_ctx( ) -> ciphers.AEADEncryptionContext: ... @typing.overload def create_encryption_ctx( - algorithm: ciphers.CipherAlgorithm, mode: modes.Mode + algorithm: ciphers.CipherAlgorithm, mode: modes.Mode | None ) -> ciphers.CipherContext: ... @typing.overload def create_decryption_ctx( @@ -21,7 +21,7 @@ def create_decryption_ctx( ) -> ciphers.AEADDecryptionContext: ... @typing.overload def create_decryption_ctx( - algorithm: ciphers.CipherAlgorithm, mode: modes.Mode + algorithm: ciphers.CipherAlgorithm, mode: modes.Mode | None ) -> ciphers.CipherContext: ... def cipher_supported( algorithm: ciphers.CipherAlgorithm, mode: modes.Mode diff --git a/venv/Lib/site-packages/cryptography/hazmat/bindings/_rust/openssl/ed25519.pyi b/venv/Lib/site-packages/cryptography/hazmat/bindings/_rust/openssl/ed25519.pyi index 5233f9a..f85b3d1 100644 --- a/venv/Lib/site-packages/cryptography/hazmat/bindings/_rust/openssl/ed25519.pyi +++ b/venv/Lib/site-packages/cryptography/hazmat/bindings/_rust/openssl/ed25519.pyi @@ -3,10 +3,11 @@ # for complete details. from cryptography.hazmat.primitives.asymmetric import ed25519 +from cryptography.utils import Buffer class Ed25519PrivateKey: ... class Ed25519PublicKey: ... def generate_key() -> ed25519.Ed25519PrivateKey: ... -def from_private_bytes(data: bytes) -> ed25519.Ed25519PrivateKey: ... +def from_private_bytes(data: Buffer) -> ed25519.Ed25519PrivateKey: ... def from_public_bytes(data: bytes) -> ed25519.Ed25519PublicKey: ... diff --git a/venv/Lib/site-packages/cryptography/hazmat/bindings/_rust/openssl/ed448.pyi b/venv/Lib/site-packages/cryptography/hazmat/bindings/_rust/openssl/ed448.pyi index 7a06520..c8ca0ec 100644 --- a/venv/Lib/site-packages/cryptography/hazmat/bindings/_rust/openssl/ed448.pyi +++ b/venv/Lib/site-packages/cryptography/hazmat/bindings/_rust/openssl/ed448.pyi @@ -3,10 +3,11 @@ # for complete details. from cryptography.hazmat.primitives.asymmetric import ed448 +from cryptography.utils import Buffer class Ed448PrivateKey: ... class Ed448PublicKey: ... def generate_key() -> ed448.Ed448PrivateKey: ... -def from_private_bytes(data: bytes) -> ed448.Ed448PrivateKey: ... +def from_private_bytes(data: Buffer) -> ed448.Ed448PrivateKey: ... def from_public_bytes(data: bytes) -> ed448.Ed448PublicKey: ... diff --git a/venv/Lib/site-packages/cryptography/hazmat/bindings/_rust/openssl/hashes.pyi b/venv/Lib/site-packages/cryptography/hazmat/bindings/_rust/openssl/hashes.pyi index 56f3170..6bfd295 100644 --- a/venv/Lib/site-packages/cryptography/hazmat/bindings/_rust/openssl/hashes.pyi +++ b/venv/Lib/site-packages/cryptography/hazmat/bindings/_rust/openssl/hashes.pyi @@ -5,6 +5,7 @@ import typing from cryptography.hazmat.primitives import hashes +from cryptography.utils import Buffer class Hash(hashes.HashContext): def __init__( @@ -12,8 +13,16 @@ class Hash(hashes.HashContext): ) -> None: ... @property def algorithm(self) -> hashes.HashAlgorithm: ... - def update(self, data: bytes) -> None: ... + def update(self, data: Buffer) -> None: ... def finalize(self) -> bytes: ... def copy(self) -> Hash: ... def hash_supported(algorithm: hashes.HashAlgorithm) -> bool: ... + +class XOFHash: + def __init__(self, algorithm: hashes.ExtendableOutputFunction) -> None: ... + @property + def algorithm(self) -> hashes.ExtendableOutputFunction: ... + def update(self, data: Buffer) -> None: ... + def squeeze(self, length: int) -> bytes: ... + def copy(self) -> XOFHash: ... diff --git a/venv/Lib/site-packages/cryptography/hazmat/bindings/_rust/openssl/hmac.pyi b/venv/Lib/site-packages/cryptography/hazmat/bindings/_rust/openssl/hmac.pyi index e38d9b5..3883d1b 100644 --- a/venv/Lib/site-packages/cryptography/hazmat/bindings/_rust/openssl/hmac.pyi +++ b/venv/Lib/site-packages/cryptography/hazmat/bindings/_rust/openssl/hmac.pyi @@ -5,17 +5,18 @@ import typing from cryptography.hazmat.primitives import hashes +from cryptography.utils import Buffer class HMAC(hashes.HashContext): def __init__( self, - key: bytes, + key: Buffer, algorithm: hashes.HashAlgorithm, backend: typing.Any = None, ) -> None: ... @property def algorithm(self) -> hashes.HashAlgorithm: ... - def update(self, data: bytes) -> None: ... + def update(self, data: Buffer) -> None: ... def finalize(self) -> bytes: ... def verify(self, signature: bytes) -> None: ... def copy(self) -> HMAC: ... diff --git a/venv/Lib/site-packages/cryptography/hazmat/bindings/_rust/openssl/kdf.pyi b/venv/Lib/site-packages/cryptography/hazmat/bindings/_rust/openssl/kdf.pyi index 4b90bb4..9e2d8d9 100644 --- a/venv/Lib/site-packages/cryptography/hazmat/bindings/_rust/openssl/kdf.pyi +++ b/venv/Lib/site-packages/cryptography/hazmat/bindings/_rust/openssl/kdf.pyi @@ -5,9 +5,10 @@ import typing from cryptography.hazmat.primitives.hashes import HashAlgorithm +from cryptography.utils import Buffer def derive_pbkdf2_hmac( - key_material: bytes, + key_material: Buffer, algorithm: HashAlgorithm, salt: bytes, iterations: int, @@ -24,7 +25,7 @@ class Scrypt: p: int, backend: typing.Any = None, ) -> None: ... - def derive(self, key_material: bytes) -> bytes: ... + def derive(self, key_material: Buffer) -> bytes: ... def verify(self, key_material: bytes, expected_key: bytes) -> None: ... class Argon2id: @@ -41,3 +42,31 @@ class Argon2id: ) -> None: ... def derive(self, key_material: bytes) -> bytes: ... def verify(self, key_material: bytes, expected_key: bytes) -> None: ... + def derive_phc_encoded(self, key_material: bytes) -> str: ... + @classmethod + def verify_phc_encoded( + cls, key_material: bytes, phc_encoded: str, secret: bytes | None = None + ) -> None: ... + +class HKDF: + def __init__( + self, + algorithm: HashAlgorithm, + length: int, + salt: bytes | None, + info: bytes | None, + backend: typing.Any = None, + ): ... + def derive(self, key_material: Buffer) -> bytes: ... + def verify(self, key_material: bytes, expected_key: bytes) -> None: ... + +class HKDFExpand: + def __init__( + self, + algorithm: HashAlgorithm, + length: int, + info: bytes | None, + backend: typing.Any = None, + ): ... + def derive(self, key_material: Buffer) -> bytes: ... + def verify(self, key_material: bytes, expected_key: bytes) -> None: ... diff --git a/venv/Lib/site-packages/cryptography/hazmat/bindings/_rust/openssl/keys.pyi b/venv/Lib/site-packages/cryptography/hazmat/bindings/_rust/openssl/keys.pyi index 6815b7d..404057e 100644 --- a/venv/Lib/site-packages/cryptography/hazmat/bindings/_rust/openssl/keys.pyi +++ b/venv/Lib/site-packages/cryptography/hazmat/bindings/_rust/openssl/keys.pyi @@ -8,16 +8,17 @@ from cryptography.hazmat.primitives.asymmetric.types import ( PrivateKeyTypes, PublicKeyTypes, ) +from cryptography.utils import Buffer def load_der_private_key( - data: bytes, + data: Buffer, password: bytes | None, backend: typing.Any = None, *, unsafe_skip_rsa_key_validation: bool = False, ) -> PrivateKeyTypes: ... def load_pem_private_key( - data: bytes, + data: Buffer, password: bytes | None, backend: typing.Any = None, *, diff --git a/venv/Lib/site-packages/cryptography/hazmat/bindings/_rust/openssl/poly1305.pyi b/venv/Lib/site-packages/cryptography/hazmat/bindings/_rust/openssl/poly1305.pyi index 2e9b0a9..45a2a39 100644 --- a/venv/Lib/site-packages/cryptography/hazmat/bindings/_rust/openssl/poly1305.pyi +++ b/venv/Lib/site-packages/cryptography/hazmat/bindings/_rust/openssl/poly1305.pyi @@ -2,12 +2,14 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +from cryptography.utils import Buffer + class Poly1305: - def __init__(self, key: bytes) -> None: ... + def __init__(self, key: Buffer) -> None: ... @staticmethod - def generate_tag(key: bytes, data: bytes) -> bytes: ... + def generate_tag(key: Buffer, data: Buffer) -> bytes: ... @staticmethod - def verify_tag(key: bytes, data: bytes, tag: bytes) -> None: ... - def update(self, data: bytes) -> None: ... + def verify_tag(key: Buffer, data: Buffer, tag: bytes) -> None: ... + def update(self, data: Buffer) -> None: ... def finalize(self) -> bytes: ... def verify(self, tag: bytes) -> None: ... diff --git a/venv/Lib/site-packages/cryptography/hazmat/bindings/_rust/openssl/x25519.pyi b/venv/Lib/site-packages/cryptography/hazmat/bindings/_rust/openssl/x25519.pyi index da0f3ec..38d2add 100644 --- a/venv/Lib/site-packages/cryptography/hazmat/bindings/_rust/openssl/x25519.pyi +++ b/venv/Lib/site-packages/cryptography/hazmat/bindings/_rust/openssl/x25519.pyi @@ -3,10 +3,11 @@ # for complete details. from cryptography.hazmat.primitives.asymmetric import x25519 +from cryptography.utils import Buffer class X25519PrivateKey: ... class X25519PublicKey: ... def generate_key() -> x25519.X25519PrivateKey: ... -def from_private_bytes(data: bytes) -> x25519.X25519PrivateKey: ... +def from_private_bytes(data: Buffer) -> x25519.X25519PrivateKey: ... def from_public_bytes(data: bytes) -> x25519.X25519PublicKey: ... diff --git a/venv/Lib/site-packages/cryptography/hazmat/bindings/_rust/openssl/x448.pyi b/venv/Lib/site-packages/cryptography/hazmat/bindings/_rust/openssl/x448.pyi index e51cfeb..3ac0980 100644 --- a/venv/Lib/site-packages/cryptography/hazmat/bindings/_rust/openssl/x448.pyi +++ b/venv/Lib/site-packages/cryptography/hazmat/bindings/_rust/openssl/x448.pyi @@ -3,10 +3,11 @@ # for complete details. from cryptography.hazmat.primitives.asymmetric import x448 +from cryptography.utils import Buffer class X448PrivateKey: ... class X448PublicKey: ... def generate_key() -> x448.X448PrivateKey: ... -def from_private_bytes(data: bytes) -> x448.X448PrivateKey: ... +def from_private_bytes(data: Buffer) -> x448.X448PrivateKey: ... def from_public_bytes(data: bytes) -> x448.X448PublicKey: ... diff --git a/venv/Lib/site-packages/cryptography/hazmat/bindings/_rust/pkcs12.pyi b/venv/Lib/site-packages/cryptography/hazmat/bindings/_rust/pkcs12.pyi index 40514c4..b25becb 100644 --- a/venv/Lib/site-packages/cryptography/hazmat/bindings/_rust/pkcs12.pyi +++ b/venv/Lib/site-packages/cryptography/hazmat/bindings/_rust/pkcs12.pyi @@ -3,6 +3,7 @@ # for complete details. import typing +from collections.abc import Iterable from cryptography import x509 from cryptography.hazmat.primitives.asymmetric.types import PrivateKeyTypes @@ -13,6 +14,7 @@ from cryptography.hazmat.primitives.serialization.pkcs12 import ( PKCS12KeyAndCertificates, PKCS12PrivateKeyTypes, ) +from cryptography.utils import Buffer class PKCS12Certificate: def __init__( @@ -24,8 +26,8 @@ class PKCS12Certificate: def certificate(self) -> x509.Certificate: ... def load_key_and_certificates( - data: bytes, - password: bytes | None, + data: Buffer, + password: Buffer | None, backend: typing.Any = None, ) -> tuple[ PrivateKeyTypes | None, @@ -37,10 +39,14 @@ def load_pkcs12( password: bytes | None, backend: typing.Any = None, ) -> PKCS12KeyAndCertificates: ... +def serialize_java_truststore( + certs: Iterable[PKCS12Certificate], + encryption_algorithm: KeySerializationEncryption, +) -> bytes: ... def serialize_key_and_certificates( name: bytes | None, key: PKCS12PrivateKeyTypes | None, cert: x509.Certificate | None, - cas: typing.Iterable[x509.Certificate | PKCS12Certificate] | None, + cas: Iterable[x509.Certificate | PKCS12Certificate] | None, encryption_algorithm: KeySerializationEncryption, ) -> bytes: ... diff --git a/venv/Lib/site-packages/cryptography/hazmat/bindings/_rust/pkcs7.pyi b/venv/Lib/site-packages/cryptography/hazmat/bindings/_rust/pkcs7.pyi index f9aa81e..358b135 100644 --- a/venv/Lib/site-packages/cryptography/hazmat/bindings/_rust/pkcs7.pyi +++ b/venv/Lib/site-packages/cryptography/hazmat/bindings/_rust/pkcs7.pyi @@ -2,7 +2,7 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. -import typing +from collections.abc import Iterable from cryptography import x509 from cryptography.hazmat.primitives import serialization @@ -15,31 +15,32 @@ def serialize_certificates( ) -> bytes: ... def encrypt_and_serialize( builder: pkcs7.PKCS7EnvelopeBuilder, + content_encryption_algorithm: pkcs7.ContentEncryptionAlgorithm, encoding: serialization.Encoding, - options: typing.Iterable[pkcs7.PKCS7Options], + options: Iterable[pkcs7.PKCS7Options], ) -> bytes: ... def sign_and_serialize( builder: pkcs7.PKCS7SignatureBuilder, encoding: serialization.Encoding, - options: typing.Iterable[pkcs7.PKCS7Options], + options: Iterable[pkcs7.PKCS7Options], ) -> bytes: ... def decrypt_der( data: bytes, certificate: x509.Certificate, private_key: rsa.RSAPrivateKey, - options: typing.Iterable[pkcs7.PKCS7Options], + options: Iterable[pkcs7.PKCS7Options], ) -> bytes: ... def decrypt_pem( data: bytes, certificate: x509.Certificate, private_key: rsa.RSAPrivateKey, - options: typing.Iterable[pkcs7.PKCS7Options], + options: Iterable[pkcs7.PKCS7Options], ) -> bytes: ... def decrypt_smime( data: bytes, certificate: x509.Certificate, private_key: rsa.RSAPrivateKey, - options: typing.Iterable[pkcs7.PKCS7Options], + options: Iterable[pkcs7.PKCS7Options], ) -> bytes: ... def load_pem_pkcs7_certificates( data: bytes, diff --git a/venv/Lib/site-packages/cryptography/hazmat/bindings/_rust/test_support.pyi b/venv/Lib/site-packages/cryptography/hazmat/bindings/_rust/test_support.pyi index ef9f779..c6c6d0b 100644 --- a/venv/Lib/site-packages/cryptography/hazmat/bindings/_rust/test_support.pyi +++ b/venv/Lib/site-packages/cryptography/hazmat/bindings/_rust/test_support.pyi @@ -5,6 +5,7 @@ from cryptography import x509 from cryptography.hazmat.primitives import serialization from cryptography.hazmat.primitives.serialization import pkcs7 +from cryptography.utils import Buffer class TestCertificate: not_after_tag: int @@ -16,7 +17,7 @@ def test_parse_certificate(data: bytes) -> TestCertificate: ... def pkcs7_verify( encoding: serialization.Encoding, sig: bytes, - msg: bytes | None, + msg: Buffer | None, certs: list[x509.Certificate], options: list[pkcs7.PKCS7Options], ) -> None: ... diff --git a/venv/Lib/site-packages/cryptography/hazmat/bindings/_rust/x509.pyi b/venv/Lib/site-packages/cryptography/hazmat/bindings/_rust/x509.pyi index b494fb6..83c3441 100644 --- a/venv/Lib/site-packages/cryptography/hazmat/bindings/_rust/x509.pyi +++ b/venv/Lib/site-packages/cryptography/hazmat/bindings/_rust/x509.pyi @@ -4,6 +4,7 @@ import datetime import typing +from collections.abc import Iterator from cryptography import x509 from cryptography.hazmat.primitives import hashes, serialization @@ -44,18 +45,21 @@ def create_x509_certificate( private_key: PrivateKeyTypes, hash_algorithm: hashes.HashAlgorithm | None, rsa_padding: PKCS1v15 | PSS | None, + ecdsa_deterministic: bool | None, ) -> x509.Certificate: ... def create_x509_csr( builder: x509.CertificateSigningRequestBuilder, private_key: PrivateKeyTypes, hash_algorithm: hashes.HashAlgorithm | None, rsa_padding: PKCS1v15 | PSS | None, + ecdsa_deterministic: bool | None, ) -> x509.CertificateSigningRequest: ... def create_x509_crl( builder: x509.CertificateRevocationListBuilder, private_key: PrivateKeyTypes, hash_algorithm: hashes.HashAlgorithm | None, rsa_padding: PKCS1v15 | PSS | None, + ecdsa_deterministic: bool | None, ) -> x509.CertificateRevocationList: ... class Sct: @@ -108,7 +112,7 @@ class Certificate: @property def signature_algorithm_parameters( self, - ) -> None | PSS | PKCS1v15 | ECDSA: ... + ) -> PSS | PKCS1v15 | ECDSA | None: ... @property def extensions(self) -> x509.Extensions: ... @property @@ -129,7 +133,7 @@ class CertificateRevocationList: def fingerprint(self, algorithm: hashes.HashAlgorithm) -> bytes: ... def get_revoked_certificate_by_serial_number( self, serial_number: int - ) -> RevokedCertificate | None: ... + ) -> x509.RevokedCertificate | None: ... @property def signature_hash_algorithm( self, @@ -139,7 +143,7 @@ class CertificateRevocationList: @property def signature_algorithm_parameters( self, - ) -> None | PSS | PKCS1v15 | ECDSA: ... + ) -> PSS | PKCS1v15 | ECDSA | None: ... @property def issuer(self) -> x509.Name: ... @property @@ -162,7 +166,7 @@ class CertificateRevocationList: def __getitem__(self, idx: int) -> x509.RevokedCertificate: ... @typing.overload def __getitem__(self, idx: slice) -> list[x509.RevokedCertificate]: ... - def __iter__(self) -> typing.Iterator[x509.RevokedCertificate]: ... + def __iter__(self) -> Iterator[x509.RevokedCertificate]: ... def is_signature_valid( self, public_key: CertificateIssuerPublicKeyTypes ) -> bool: ... @@ -182,7 +186,7 @@ class CertificateSigningRequest: @property def signature_algorithm_parameters( self, - ) -> None | PSS | PKCS1v15 | ECDSA: ... + ) -> PSS | PKCS1v15 | ECDSA | None: ... @property def extensions(self) -> x509.Extensions: ... @property @@ -194,17 +198,75 @@ class CertificateSigningRequest: def tbs_certrequest_bytes(self) -> bytes: ... @property def is_signature_valid(self) -> bool: ... - def get_attribute_for_oid(self, oid: x509.ObjectIdentifier) -> bytes: ... class PolicyBuilder: - def time(self, new_time: datetime.datetime) -> PolicyBuilder: ... - def store(self, new_store: Store) -> PolicyBuilder: ... - def max_chain_depth(self, new_max_chain_depth: int) -> PolicyBuilder: ... + def time(self, time: datetime.datetime) -> PolicyBuilder: ... + def store(self, store: Store) -> PolicyBuilder: ... + def max_chain_depth(self, max_chain_depth: int) -> PolicyBuilder: ... + def extension_policies( + self, *, ca_policy: ExtensionPolicy, ee_policy: ExtensionPolicy + ) -> PolicyBuilder: ... def build_client_verifier(self) -> ClientVerifier: ... def build_server_verifier( self, subject: x509.verification.Subject ) -> ServerVerifier: ... +class Policy: + @property + def max_chain_depth(self) -> int: ... + @property + def subject(self) -> x509.verification.Subject | None: ... + @property + def validation_time(self) -> datetime.datetime: ... + @property + def extended_key_usage(self) -> x509.ObjectIdentifier: ... + @property + def minimum_rsa_modulus(self) -> int: ... + +class Criticality: + CRITICAL: Criticality + AGNOSTIC: Criticality + NON_CRITICAL: Criticality + +T = typing.TypeVar("T", contravariant=True, bound=x509.ExtensionType) + +MaybeExtensionValidatorCallback = typing.Callable[ + [ + Policy, + x509.Certificate, + T | None, + ], + None, +] + +PresentExtensionValidatorCallback = typing.Callable[ + [Policy, x509.Certificate, T], + None, +] + +class ExtensionPolicy: + @staticmethod + def permit_all() -> ExtensionPolicy: ... + @staticmethod + def webpki_defaults_ca() -> ExtensionPolicy: ... + @staticmethod + def webpki_defaults_ee() -> ExtensionPolicy: ... + def require_not_present( + self, extension_type: type[x509.ExtensionType] + ) -> ExtensionPolicy: ... + def may_be_present( + self, + extension_type: type[T], + criticality: Criticality, + validator: MaybeExtensionValidatorCallback[T] | None, + ) -> ExtensionPolicy: ... + def require_present( + self, + extension_type: type[T], + criticality: Criticality, + validator: PresentExtensionValidatorCallback[T] | None, + ) -> ExtensionPolicy: ... + class VerifiedClient: @property def subjects(self) -> list[x509.GeneralName] | None: ... @@ -213,11 +275,9 @@ class VerifiedClient: class ClientVerifier: @property - def validation_time(self) -> datetime.datetime: ... + def policy(self) -> Policy: ... @property def store(self) -> Store: ... - @property - def max_chain_depth(self) -> int: ... def verify( self, leaf: x509.Certificate, @@ -226,13 +286,9 @@ class ClientVerifier: class ServerVerifier: @property - def subject(self) -> x509.verification.Subject: ... - @property - def validation_time(self) -> datetime.datetime: ... + def policy(self) -> Policy: ... @property def store(self) -> Store: ... - @property - def max_chain_depth(self) -> int: ... def verify( self, leaf: x509.Certificate, @@ -242,5 +298,4 @@ class ServerVerifier: class Store: def __init__(self, certs: list[x509.Certificate]) -> None: ... -class VerificationError(Exception): - pass +class VerificationError(Exception): ... diff --git a/venv/Lib/site-packages/cryptography/hazmat/bindings/openssl/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/cryptography/hazmat/bindings/openssl/__pycache__/__init__.cpython-312.pyc index 21462e6..fa59cc7 100644 Binary files a/venv/Lib/site-packages/cryptography/hazmat/bindings/openssl/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/cryptography/hazmat/bindings/openssl/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/cryptography/hazmat/bindings/openssl/__pycache__/_conditional.cpython-312.pyc b/venv/Lib/site-packages/cryptography/hazmat/bindings/openssl/__pycache__/_conditional.cpython-312.pyc index cae1ea8..20c491e 100644 Binary files a/venv/Lib/site-packages/cryptography/hazmat/bindings/openssl/__pycache__/_conditional.cpython-312.pyc and b/venv/Lib/site-packages/cryptography/hazmat/bindings/openssl/__pycache__/_conditional.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/cryptography/hazmat/bindings/openssl/__pycache__/binding.cpython-312.pyc b/venv/Lib/site-packages/cryptography/hazmat/bindings/openssl/__pycache__/binding.cpython-312.pyc index 7acb532..5542a32 100644 Binary files a/venv/Lib/site-packages/cryptography/hazmat/bindings/openssl/__pycache__/binding.cpython-312.pyc and b/venv/Lib/site-packages/cryptography/hazmat/bindings/openssl/__pycache__/binding.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/cryptography/hazmat/bindings/openssl/_conditional.py b/venv/Lib/site-packages/cryptography/hazmat/bindings/openssl/_conditional.py index 73c06f7..063bcf5 100644 --- a/venv/Lib/site-packages/cryptography/hazmat/bindings/openssl/_conditional.py +++ b/venv/Lib/site-packages/cryptography/hazmat/bindings/openssl/_conditional.py @@ -64,8 +64,13 @@ def cryptography_has_custom_ext() -> list[str]: def cryptography_has_tlsv13_functions() -> list[str]: return [ - "SSL_VERIFY_POST_HANDSHAKE", "SSL_CTX_set_ciphersuites", + ] + + +def cryptography_has_tlsv13_hs_functions() -> list[str]: + return [ + "SSL_VERIFY_POST_HANDSHAKE", "SSL_verify_client_post_handshake", "SSL_CTX_set_post_handshake_auth", "SSL_set_post_handshake_auth", @@ -76,6 +81,12 @@ def cryptography_has_tlsv13_functions() -> list[str]: ] +def cryptography_has_ssl_verify_client_post_handshake() -> list[str]: + return [ + "SSL_verify_client_post_handshake", + ] + + def cryptography_has_engine() -> list[str]: return [ "ENGINE_by_id", @@ -150,6 +161,10 @@ def cryptography_has_get_extms_support() -> list[str]: return ["SSL_get_extms_support"] +def cryptography_has_ssl_get0_group_name() -> list[str]: + return ["SSL_get0_group_name"] + + # This is a mapping of # {condition: function-returning-names-dependent-on-that-condition} so we can # loop over them and delete unsupported names at runtime. It will be removed @@ -164,6 +179,12 @@ CONDITIONAL_NAMES = { "Cryptography_HAS_PSK_TLSv1_3": cryptography_has_psk_tlsv13, "Cryptography_HAS_CUSTOM_EXT": cryptography_has_custom_ext, "Cryptography_HAS_TLSv1_3_FUNCTIONS": cryptography_has_tlsv13_functions, + "Cryptography_HAS_TLSv1_3_HS_FUNCTIONS": ( + cryptography_has_tlsv13_hs_functions + ), + "Cryptography_HAS_SSL_VERIFY_CLIENT_POST_HANDSHAKE": ( + cryptography_has_ssl_verify_client_post_handshake + ), "Cryptography_HAS_ENGINE": cryptography_has_engine, "Cryptography_HAS_VERIFIED_CHAIN": cryptography_has_verified_chain, "Cryptography_HAS_SRTP": cryptography_has_srtp, @@ -180,4 +201,7 @@ CONDITIONAL_NAMES = { cryptography_has_ssl_op_ignore_unexpected_eof ), "Cryptography_HAS_GET_EXTMS_SUPPORT": cryptography_has_get_extms_support, + "Cryptography_HAS_SSL_GET0_GROUP_NAME": ( + cryptography_has_ssl_get0_group_name + ), } diff --git a/venv/Lib/site-packages/cryptography/hazmat/bindings/openssl/binding.py b/venv/Lib/site-packages/cryptography/hazmat/bindings/openssl/binding.py index d4dfeef..4494c71 100644 --- a/venv/Lib/site-packages/cryptography/hazmat/bindings/openssl/binding.py +++ b/venv/Lib/site-packages/cryptography/hazmat/bindings/openssl/binding.py @@ -10,11 +10,13 @@ import threading import types import typing import warnings +from collections.abc import Callable import cryptography from cryptography.exceptions import InternalError from cryptography.hazmat.bindings._rust import _openssl, openssl from cryptography.hazmat.bindings.openssl._conditional import CONDITIONAL_NAMES +from cryptography.utils import CryptographyDeprecationWarning def _openssl_assert(ok: bool) -> None: @@ -35,7 +37,7 @@ def _openssl_assert(ok: bool) -> None: def build_conditional_library( lib: typing.Any, - conditional_names: dict[str, typing.Callable[[], list[str]]], + conditional_names: dict[str, Callable[[], list[str]]], ) -> typing.Any: conditional_lib = types.ModuleType("lib") conditional_lib._original_lib = lib # type: ignore[attr-defined] @@ -56,7 +58,7 @@ class Binding: OpenSSL API wrapper. """ - lib: typing.ClassVar = None + lib: typing.ClassVar[typing.Any] = None ffi = _openssl.ffi _lib_loaded = False _init_lock = threading.Lock() @@ -119,3 +121,17 @@ if ( UserWarning, stacklevel=2, ) + +if ( + not openssl.CRYPTOGRAPHY_IS_LIBRESSL + and not openssl.CRYPTOGRAPHY_IS_BORINGSSL + and not openssl.CRYPTOGRAPHY_IS_AWSLC + and not openssl.CRYPTOGRAPHY_OPENSSL_300_OR_GREATER +): + warnings.warn( + "You are using OpenSSL < 3.0. Support for OpenSSL < 3.0 is deprecated " + "and will be removed in the next release. Please upgrade to OpenSSL " + "3.0 or later.", + CryptographyDeprecationWarning, + stacklevel=2, + ) diff --git a/venv/Lib/site-packages/cryptography/hazmat/decrepit/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/cryptography/hazmat/decrepit/__pycache__/__init__.cpython-312.pyc index 185715b..a6133c8 100644 Binary files a/venv/Lib/site-packages/cryptography/hazmat/decrepit/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/cryptography/hazmat/decrepit/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/cryptography/hazmat/decrepit/ciphers/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/cryptography/hazmat/decrepit/ciphers/__pycache__/__init__.cpython-312.pyc index 896a932..cdcfb4c 100644 Binary files a/venv/Lib/site-packages/cryptography/hazmat/decrepit/ciphers/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/cryptography/hazmat/decrepit/ciphers/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/cryptography/hazmat/decrepit/ciphers/__pycache__/algorithms.cpython-312.pyc b/venv/Lib/site-packages/cryptography/hazmat/decrepit/ciphers/__pycache__/algorithms.cpython-312.pyc index a9222e9..cee1f27 100644 Binary files a/venv/Lib/site-packages/cryptography/hazmat/decrepit/ciphers/__pycache__/algorithms.cpython-312.pyc and b/venv/Lib/site-packages/cryptography/hazmat/decrepit/ciphers/__pycache__/algorithms.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/cryptography/hazmat/decrepit/ciphers/algorithms.py b/venv/Lib/site-packages/cryptography/hazmat/decrepit/ciphers/algorithms.py index a7d4aa3..072a991 100644 --- a/venv/Lib/site-packages/cryptography/hazmat/decrepit/ciphers/algorithms.py +++ b/venv/Lib/site-packages/cryptography/hazmat/decrepit/ciphers/algorithms.py @@ -40,6 +40,11 @@ class TripleDES(BlockCipherAlgorithm): return len(self.key) * 8 +# Not actually supported, marker for tests +class _DES: + key_size = 64 + + class Blowfish(BlockCipherAlgorithm): name = "Blowfish" block_size = 64 diff --git a/venv/Lib/site-packages/cryptography/hazmat/primitives/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/cryptography/hazmat/primitives/__pycache__/__init__.cpython-312.pyc index f766ab1..277f903 100644 Binary files a/venv/Lib/site-packages/cryptography/hazmat/primitives/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/cryptography/hazmat/primitives/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/cryptography/hazmat/primitives/__pycache__/_asymmetric.cpython-312.pyc b/venv/Lib/site-packages/cryptography/hazmat/primitives/__pycache__/_asymmetric.cpython-312.pyc index 66a0424..5633505 100644 Binary files a/venv/Lib/site-packages/cryptography/hazmat/primitives/__pycache__/_asymmetric.cpython-312.pyc and b/venv/Lib/site-packages/cryptography/hazmat/primitives/__pycache__/_asymmetric.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/cryptography/hazmat/primitives/__pycache__/_cipheralgorithm.cpython-312.pyc b/venv/Lib/site-packages/cryptography/hazmat/primitives/__pycache__/_cipheralgorithm.cpython-312.pyc index 0c1d8e5..11dc2c4 100644 Binary files a/venv/Lib/site-packages/cryptography/hazmat/primitives/__pycache__/_cipheralgorithm.cpython-312.pyc and b/venv/Lib/site-packages/cryptography/hazmat/primitives/__pycache__/_cipheralgorithm.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/cryptography/hazmat/primitives/__pycache__/_serialization.cpython-312.pyc b/venv/Lib/site-packages/cryptography/hazmat/primitives/__pycache__/_serialization.cpython-312.pyc index 17d8d71..efaf465 100644 Binary files a/venv/Lib/site-packages/cryptography/hazmat/primitives/__pycache__/_serialization.cpython-312.pyc and b/venv/Lib/site-packages/cryptography/hazmat/primitives/__pycache__/_serialization.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/cryptography/hazmat/primitives/__pycache__/cmac.cpython-312.pyc b/venv/Lib/site-packages/cryptography/hazmat/primitives/__pycache__/cmac.cpython-312.pyc index c6e74db..e342eb4 100644 Binary files a/venv/Lib/site-packages/cryptography/hazmat/primitives/__pycache__/cmac.cpython-312.pyc and b/venv/Lib/site-packages/cryptography/hazmat/primitives/__pycache__/cmac.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/cryptography/hazmat/primitives/__pycache__/constant_time.cpython-312.pyc b/venv/Lib/site-packages/cryptography/hazmat/primitives/__pycache__/constant_time.cpython-312.pyc index c10709c..7177289 100644 Binary files a/venv/Lib/site-packages/cryptography/hazmat/primitives/__pycache__/constant_time.cpython-312.pyc and b/venv/Lib/site-packages/cryptography/hazmat/primitives/__pycache__/constant_time.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/cryptography/hazmat/primitives/__pycache__/hashes.cpython-312.pyc b/venv/Lib/site-packages/cryptography/hazmat/primitives/__pycache__/hashes.cpython-312.pyc index b0d9449..2f8b991 100644 Binary files a/venv/Lib/site-packages/cryptography/hazmat/primitives/__pycache__/hashes.cpython-312.pyc and b/venv/Lib/site-packages/cryptography/hazmat/primitives/__pycache__/hashes.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/cryptography/hazmat/primitives/__pycache__/hmac.cpython-312.pyc b/venv/Lib/site-packages/cryptography/hazmat/primitives/__pycache__/hmac.cpython-312.pyc index c857a31..e83e0dd 100644 Binary files a/venv/Lib/site-packages/cryptography/hazmat/primitives/__pycache__/hmac.cpython-312.pyc and b/venv/Lib/site-packages/cryptography/hazmat/primitives/__pycache__/hmac.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/cryptography/hazmat/primitives/__pycache__/keywrap.cpython-312.pyc b/venv/Lib/site-packages/cryptography/hazmat/primitives/__pycache__/keywrap.cpython-312.pyc index d941c70..7a8b133 100644 Binary files a/venv/Lib/site-packages/cryptography/hazmat/primitives/__pycache__/keywrap.cpython-312.pyc and b/venv/Lib/site-packages/cryptography/hazmat/primitives/__pycache__/keywrap.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/cryptography/hazmat/primitives/__pycache__/padding.cpython-312.pyc b/venv/Lib/site-packages/cryptography/hazmat/primitives/__pycache__/padding.cpython-312.pyc index 61ff723..01fecc4 100644 Binary files a/venv/Lib/site-packages/cryptography/hazmat/primitives/__pycache__/padding.cpython-312.pyc and b/venv/Lib/site-packages/cryptography/hazmat/primitives/__pycache__/padding.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/cryptography/hazmat/primitives/__pycache__/poly1305.cpython-312.pyc b/venv/Lib/site-packages/cryptography/hazmat/primitives/__pycache__/poly1305.cpython-312.pyc index bcf67fa..0b97348 100644 Binary files a/venv/Lib/site-packages/cryptography/hazmat/primitives/__pycache__/poly1305.cpython-312.pyc and b/venv/Lib/site-packages/cryptography/hazmat/primitives/__pycache__/poly1305.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/cryptography/hazmat/primitives/_cipheralgorithm.py b/venv/Lib/site-packages/cryptography/hazmat/primitives/_cipheralgorithm.py index 588a616..305a9fd 100644 --- a/venv/Lib/site-packages/cryptography/hazmat/primitives/_cipheralgorithm.py +++ b/venv/Lib/site-packages/cryptography/hazmat/primitives/_cipheralgorithm.py @@ -36,7 +36,7 @@ class CipherAlgorithm(metaclass=abc.ABCMeta): class BlockCipherAlgorithm(CipherAlgorithm): - key: bytes + key: utils.Buffer @property @abc.abstractmethod @@ -46,7 +46,9 @@ class BlockCipherAlgorithm(CipherAlgorithm): """ -def _verify_key_size(algorithm: CipherAlgorithm, key: bytes) -> bytes: +def _verify_key_size( + algorithm: CipherAlgorithm, key: utils.Buffer +) -> utils.Buffer: # Verify that the key is instance of bytes utils._check_byteslike("key", key) diff --git a/venv/Lib/site-packages/cryptography/hazmat/primitives/_serialization.py b/venv/Lib/site-packages/cryptography/hazmat/primitives/_serialization.py index 4615772..e998865 100644 --- a/venv/Lib/site-packages/cryptography/hazmat/primitives/_serialization.py +++ b/venv/Lib/site-packages/cryptography/hazmat/primitives/_serialization.py @@ -126,8 +126,7 @@ class KeySerializationEncryptionBuilder: ) -> KeySerializationEncryptionBuilder: if self._format is not PrivateFormat.PKCS12: raise TypeError( - "key_cert_algorithm only supported with " - "PrivateFormat.PKCS12" + "key_cert_algorithm only supported with PrivateFormat.PKCS12" ) if self._key_cert_algorithm is not None: raise ValueError("key_cert_algorithm already set") diff --git a/venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/__init__.cpython-312.pyc index 09e12d0..5ea274d 100644 Binary files a/venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/dh.cpython-312.pyc b/venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/dh.cpython-312.pyc index 5e2f8f5..2bc5520 100644 Binary files a/venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/dh.cpython-312.pyc and b/venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/dh.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/dsa.cpython-312.pyc b/venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/dsa.cpython-312.pyc index 9716898..606fe9b 100644 Binary files a/venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/dsa.cpython-312.pyc and b/venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/dsa.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/ec.cpython-312.pyc b/venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/ec.cpython-312.pyc index b783535..4250305 100644 Binary files a/venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/ec.cpython-312.pyc and b/venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/ec.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/ed25519.cpython-312.pyc b/venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/ed25519.cpython-312.pyc index 744ef87..43877c9 100644 Binary files a/venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/ed25519.cpython-312.pyc and b/venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/ed25519.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/ed448.cpython-312.pyc b/venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/ed448.cpython-312.pyc index 87775ee..86a3780 100644 Binary files a/venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/ed448.cpython-312.pyc and b/venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/ed448.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/padding.cpython-312.pyc b/venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/padding.cpython-312.pyc index 5f0aabc..fa7ddcf 100644 Binary files a/venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/padding.cpython-312.pyc and b/venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/padding.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/rsa.cpython-312.pyc b/venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/rsa.cpython-312.pyc index c67ff7f..86d785c 100644 Binary files a/venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/rsa.cpython-312.pyc and b/venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/rsa.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/types.cpython-312.pyc b/venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/types.cpython-312.pyc index c9a0559..8cf1fb5 100644 Binary files a/venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/types.cpython-312.pyc and b/venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/types.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/utils.cpython-312.pyc b/venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/utils.cpython-312.pyc index 1487ff7..c5deb33 100644 Binary files a/venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/utils.cpython-312.pyc and b/venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/utils.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/x25519.cpython-312.pyc b/venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/x25519.cpython-312.pyc index c211b92..2052bc8 100644 Binary files a/venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/x25519.cpython-312.pyc and b/venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/x25519.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/x448.cpython-312.pyc b/venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/x448.cpython-312.pyc index aea6aae..7f87c0e 100644 Binary files a/venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/x448.cpython-312.pyc and b/venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/x448.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/dh.py b/venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/dh.py index 31c9748..1822e99 100644 --- a/venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/dh.py +++ b/venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/dh.py @@ -81,6 +81,12 @@ class DHPublicKey(metaclass=abc.ABCMeta): Checks equality. """ + @abc.abstractmethod + def __copy__(self) -> DHPublicKey: + """ + Returns a copy. + """ + DHPublicKeyWithSerialization = DHPublicKey DHPublicKey.register(rust_openssl.dh.DHPublicKey) @@ -130,6 +136,12 @@ class DHPrivateKey(metaclass=abc.ABCMeta): Returns the key serialized as bytes. """ + @abc.abstractmethod + def __copy__(self) -> DHPrivateKey: + """ + Returns a copy. + """ + DHPrivateKeyWithSerialization = DHPrivateKey DHPrivateKey.register(rust_openssl.dh.DHPrivateKey) diff --git a/venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/dsa.py b/venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/dsa.py index 6dd34c0..21d78ba 100644 --- a/venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/dsa.py +++ b/venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/dsa.py @@ -10,6 +10,7 @@ import typing from cryptography.hazmat.bindings._rust import openssl as rust_openssl from cryptography.hazmat.primitives import _serialization, hashes from cryptography.hazmat.primitives.asymmetric import utils as asym_utils +from cryptography.utils import Buffer class DSAParameters(metaclass=abc.ABCMeta): @@ -53,7 +54,7 @@ class DSAPrivateKey(metaclass=abc.ABCMeta): @abc.abstractmethod def sign( self, - data: bytes, + data: Buffer, algorithm: asym_utils.Prehashed | hashes.HashAlgorithm, ) -> bytes: """ @@ -77,6 +78,12 @@ class DSAPrivateKey(metaclass=abc.ABCMeta): Returns the key serialized as bytes. """ + @abc.abstractmethod + def __copy__(self) -> DSAPrivateKey: + """ + Returns a copy. + """ + DSAPrivateKeyWithSerialization = DSAPrivateKey DSAPrivateKey.register(rust_openssl.dsa.DSAPrivateKey) @@ -115,8 +122,8 @@ class DSAPublicKey(metaclass=abc.ABCMeta): @abc.abstractmethod def verify( self, - signature: bytes, - data: bytes, + signature: Buffer, + data: Buffer, algorithm: asym_utils.Prehashed | hashes.HashAlgorithm, ) -> None: """ @@ -129,6 +136,12 @@ class DSAPublicKey(metaclass=abc.ABCMeta): Checks equality. """ + @abc.abstractmethod + def __copy__(self) -> DSAPublicKey: + """ + Returns a copy. + """ + DSAPublicKeyWithSerialization = DSAPublicKey DSAPublicKey.register(rust_openssl.dsa.DSAPublicKey) diff --git a/venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/ec.py b/venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/ec.py index da1fbea..a13d982 100644 --- a/venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/ec.py +++ b/venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/ec.py @@ -52,6 +52,13 @@ class EllipticCurve(metaclass=abc.ABCMeta): Bit size of a secret scalar for the curve. """ + @property + @abc.abstractmethod + def group_order(self) -> int: + """ + The order of the curve's group. + """ + class EllipticCurveSignatureAlgorithm(metaclass=abc.ABCMeta): @property @@ -97,7 +104,7 @@ class EllipticCurvePrivateKey(metaclass=abc.ABCMeta): @abc.abstractmethod def sign( self, - data: bytes, + data: utils.Buffer, signature_algorithm: EllipticCurveSignatureAlgorithm, ) -> bytes: """ @@ -121,6 +128,12 @@ class EllipticCurvePrivateKey(metaclass=abc.ABCMeta): Returns the key serialized as bytes. """ + @abc.abstractmethod + def __copy__(self) -> EllipticCurvePrivateKey: + """ + Returns a copy. + """ + EllipticCurvePrivateKeyWithSerialization = EllipticCurvePrivateKey EllipticCurvePrivateKey.register(rust_openssl.ec.ECPrivateKey) @@ -160,8 +173,8 @@ class EllipticCurvePublicKey(metaclass=abc.ABCMeta): @abc.abstractmethod def verify( self, - signature: bytes, - data: bytes, + signature: utils.Buffer, + data: utils.Buffer, signature_algorithm: EllipticCurveSignatureAlgorithm, ) -> None: """ @@ -188,6 +201,12 @@ class EllipticCurvePublicKey(metaclass=abc.ABCMeta): Checks equality. """ + @abc.abstractmethod + def __copy__(self) -> EllipticCurvePublicKey: + """ + Returns a copy. + """ + EllipticCurvePublicKeyWithSerialization = EllipticCurvePublicKey EllipticCurvePublicKey.register(rust_openssl.ec.ECPublicKey) @@ -199,96 +218,121 @@ EllipticCurvePublicNumbers = rust_openssl.ec.EllipticCurvePublicNumbers class SECT571R1(EllipticCurve): name = "sect571r1" key_size = 570 + group_order = 0x3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE661CE18FF55987308059B186823851EC7DD9CA1161DE93D5174D66E8382E9BB2FE84E47 # noqa: E501 class SECT409R1(EllipticCurve): name = "sect409r1" key_size = 409 + group_order = 0x10000000000000000000000000000000000000000000000000001E2AAD6A612F33307BE5FA47C3C9E052F838164CD37D9A21173 # noqa: E501 class SECT283R1(EllipticCurve): name = "sect283r1" key_size = 283 + group_order = 0x3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEF90399660FC938A90165B042A7CEFADB307 # noqa: E501 class SECT233R1(EllipticCurve): name = "sect233r1" key_size = 233 + group_order = 0x1000000000000000000000000000013E974E72F8A6922031D2603CFE0D7 class SECT163R2(EllipticCurve): name = "sect163r2" key_size = 163 + group_order = 0x40000000000000000000292FE77E70C12A4234C33 class SECT571K1(EllipticCurve): name = "sect571k1" key_size = 571 + group_order = 0x20000000000000000000000000000000000000000000000000000000000000000000000131850E1F19A63E4B391A8DB917F4138B630D84BE5D639381E91DEB45CFE778F637C1001 # noqa: E501 class SECT409K1(EllipticCurve): name = "sect409k1" key_size = 409 + group_order = 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE5F83B2D4EA20400EC4557D5ED3E3E7CA5B4B5C83B8E01E5FCF # noqa: E501 class SECT283K1(EllipticCurve): name = "sect283k1" key_size = 283 + group_order = 0x1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE9AE2ED07577265DFF7F94451E061E163C61 # noqa: E501 class SECT233K1(EllipticCurve): name = "sect233k1" key_size = 233 + group_order = 0x8000000000000000000000000000069D5BB915BCD46EFB1AD5F173ABDF class SECT163K1(EllipticCurve): name = "sect163k1" key_size = 163 + group_order = 0x4000000000000000000020108A2E0CC0D99F8A5EF class SECP521R1(EllipticCurve): name = "secp521r1" key_size = 521 + group_order = 0x1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409 # noqa: E501 class SECP384R1(EllipticCurve): name = "secp384r1" key_size = 384 + group_order = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973 # noqa: E501 class SECP256R1(EllipticCurve): name = "secp256r1" key_size = 256 + group_order = ( + 0xFFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551 + ) class SECP256K1(EllipticCurve): name = "secp256k1" key_size = 256 + group_order = ( + 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 + ) class SECP224R1(EllipticCurve): name = "secp224r1" key_size = 224 + group_order = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFF16A2E0B8F03E13DD29455C5C2A3D class SECP192R1(EllipticCurve): name = "secp192r1" key_size = 192 + group_order = 0xFFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22831 class BrainpoolP256R1(EllipticCurve): name = "brainpoolP256r1" key_size = 256 + group_order = ( + 0xA9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A7 + ) class BrainpoolP384R1(EllipticCurve): name = "brainpoolP384r1" key_size = 384 + group_order = 0x8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B31F166E6CAC0425A7CF3AB6AF6B7FC3103B883202E9046565 # noqa: E501 class BrainpoolP512R1(EllipticCurve): name = "brainpoolP512r1" key_size = 512 + group_order = 0xAADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA70330870553E5C414CA92619418661197FAC10471DB1D381085DDADDB58796829CA90069 # noqa: E501 _CURVE_TYPES: dict[str, EllipticCurve] = { diff --git a/venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/ed25519.py b/venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/ed25519.py index 3a26185..e576dc9 100644 --- a/venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/ed25519.py +++ b/venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/ed25519.py @@ -9,6 +9,7 @@ import abc from cryptography.exceptions import UnsupportedAlgorithm, _Reasons from cryptography.hazmat.bindings._rust import openssl as rust_openssl from cryptography.hazmat.primitives import _serialization +from cryptography.utils import Buffer class Ed25519PublicKey(metaclass=abc.ABCMeta): @@ -42,7 +43,7 @@ class Ed25519PublicKey(metaclass=abc.ABCMeta): """ @abc.abstractmethod - def verify(self, signature: bytes, data: bytes) -> None: + def verify(self, signature: Buffer, data: Buffer) -> None: """ Verify the signature. """ @@ -53,6 +54,12 @@ class Ed25519PublicKey(metaclass=abc.ABCMeta): Checks equality. """ + @abc.abstractmethod + def __copy__(self) -> Ed25519PublicKey: + """ + Returns a copy. + """ + Ed25519PublicKey.register(rust_openssl.ed25519.Ed25519PublicKey) @@ -71,7 +78,7 @@ class Ed25519PrivateKey(metaclass=abc.ABCMeta): return rust_openssl.ed25519.generate_key() @classmethod - def from_private_bytes(cls, data: bytes) -> Ed25519PrivateKey: + def from_private_bytes(cls, data: Buffer) -> Ed25519PrivateKey: from cryptography.hazmat.backends.openssl.backend import backend if not backend.ed25519_supported(): @@ -107,10 +114,16 @@ class Ed25519PrivateKey(metaclass=abc.ABCMeta): """ @abc.abstractmethod - def sign(self, data: bytes) -> bytes: + def sign(self, data: Buffer) -> bytes: """ Signs the data. """ + @abc.abstractmethod + def __copy__(self) -> Ed25519PrivateKey: + """ + Returns a copy. + """ + Ed25519PrivateKey.register(rust_openssl.ed25519.Ed25519PrivateKey) diff --git a/venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/ed448.py b/venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/ed448.py index 78c82c4..89db209 100644 --- a/venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/ed448.py +++ b/venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/ed448.py @@ -9,6 +9,7 @@ import abc from cryptography.exceptions import UnsupportedAlgorithm, _Reasons from cryptography.hazmat.bindings._rust import openssl as rust_openssl from cryptography.hazmat.primitives import _serialization +from cryptography.utils import Buffer class Ed448PublicKey(metaclass=abc.ABCMeta): @@ -42,7 +43,7 @@ class Ed448PublicKey(metaclass=abc.ABCMeta): """ @abc.abstractmethod - def verify(self, signature: bytes, data: bytes) -> None: + def verify(self, signature: Buffer, data: Buffer) -> None: """ Verify the signature. """ @@ -53,6 +54,12 @@ class Ed448PublicKey(metaclass=abc.ABCMeta): Checks equality. """ + @abc.abstractmethod + def __copy__(self) -> Ed448PublicKey: + """ + Returns a copy. + """ + if hasattr(rust_openssl, "ed448"): Ed448PublicKey.register(rust_openssl.ed448.Ed448PublicKey) @@ -72,7 +79,7 @@ class Ed448PrivateKey(metaclass=abc.ABCMeta): return rust_openssl.ed448.generate_key() @classmethod - def from_private_bytes(cls, data: bytes) -> Ed448PrivateKey: + def from_private_bytes(cls, data: Buffer) -> Ed448PrivateKey: from cryptography.hazmat.backends.openssl.backend import backend if not backend.ed448_supported(): @@ -90,7 +97,7 @@ class Ed448PrivateKey(metaclass=abc.ABCMeta): """ @abc.abstractmethod - def sign(self, data: bytes) -> bytes: + def sign(self, data: Buffer) -> bytes: """ Signs the data. """ @@ -113,6 +120,12 @@ class Ed448PrivateKey(metaclass=abc.ABCMeta): Equivalent to private_bytes(Raw, Raw, NoEncryption()). """ + @abc.abstractmethod + def __copy__(self) -> Ed448PrivateKey: + """ + Returns a copy. + """ + if hasattr(rust_openssl, "x448"): Ed448PrivateKey.register(rust_openssl.ed448.Ed448PrivateKey) diff --git a/venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/padding.py b/venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/padding.py index b4babf4..5121a28 100644 --- a/venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/padding.py +++ b/venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/padding.py @@ -91,8 +91,6 @@ class MGF(metaclass=abc.ABCMeta): class MGF1(MGF): - MAX_LENGTH = _MaxLength() - def __init__(self, algorithm: hashes.HashAlgorithm): if not isinstance(algorithm, hashes.HashAlgorithm): raise TypeError("Expected instance of hashes.HashAlgorithm.") diff --git a/venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/rsa.py b/venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/rsa.py index 905068e..f94812e 100644 --- a/venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/rsa.py +++ b/venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/rsa.py @@ -63,6 +63,12 @@ class RSAPrivateKey(metaclass=abc.ABCMeta): Returns the key serialized as bytes. """ + @abc.abstractmethod + def __copy__(self) -> RSAPrivateKey: + """ + Returns a copy. + """ + RSAPrivateKeyWithSerialization = RSAPrivateKey RSAPrivateKey.register(rust_openssl.rsa.RSAPrivateKey) @@ -127,6 +133,12 @@ class RSAPublicKey(metaclass=abc.ABCMeta): Checks equality. """ + @abc.abstractmethod + def __copy__(self) -> RSAPublicKey: + """ + Returns a copy. + """ + RSAPublicKeyWithSerialization = RSAPublicKey RSAPublicKey.register(rust_openssl.rsa.RSAPublicKey) @@ -172,6 +184,8 @@ def rsa_crt_iqmp(p: int, q: int) -> int: """ Compute the CRT (q ** -1) % p value from RSA primes p and q. """ + if p <= 1 or q <= 1: + raise ValueError("Values can't be <= 1") return _modinv(q, p) @@ -180,6 +194,8 @@ def rsa_crt_dmp1(private_exponent: int, p: int) -> int: Compute the CRT private_exponent % (p - 1) value from the RSA private_exponent (d) and p. """ + if private_exponent <= 1 or p <= 1: + raise ValueError("Values can't be <= 1") return private_exponent % (p - 1) @@ -188,6 +204,8 @@ def rsa_crt_dmq1(private_exponent: int, q: int) -> int: Compute the CRT private_exponent % (q - 1) value from the RSA private_exponent (d) and q. """ + if private_exponent <= 1 or q <= 1: + raise ValueError("Values can't be <= 1") return private_exponent % (q - 1) @@ -208,6 +226,8 @@ def rsa_recover_private_exponent(e: int, p: int, q: int) -> int: # # TODO: Replace with lcm(p - 1, q - 1) once the minimum # supported Python version is >= 3.9. + if e <= 1 or p <= 1 or q <= 1: + raise ValueError("Values can't be <= 1") lambda_n = (p - 1) * (q - 1) // gcd(p - 1, q - 1) return _modinv(e, lambda_n) @@ -223,6 +243,8 @@ def rsa_recover_prime_factors(n: int, e: int, d: int) -> tuple[int, int]: no more than two factors. This function is adapted from code in PyCrypto. """ # reject invalid values early + if d <= 1 or e <= 1: + raise ValueError("d, e can't be <= 1") if 17 != pow(17, e * d, n): raise ValueError("n, d, e don't match") # See 8.2.2(i) in Handbook of Applied Cryptography. diff --git a/venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/x25519.py b/venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/x25519.py index 0cfa36e..a499376 100644 --- a/venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/x25519.py +++ b/venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/x25519.py @@ -9,6 +9,7 @@ import abc from cryptography.exceptions import UnsupportedAlgorithm, _Reasons from cryptography.hazmat.bindings._rust import openssl as rust_openssl from cryptography.hazmat.primitives import _serialization +from cryptography.utils import Buffer class X25519PublicKey(metaclass=abc.ABCMeta): @@ -47,6 +48,12 @@ class X25519PublicKey(metaclass=abc.ABCMeta): Checks equality. """ + @abc.abstractmethod + def __copy__(self) -> X25519PublicKey: + """ + Returns a copy. + """ + X25519PublicKey.register(rust_openssl.x25519.X25519PublicKey) @@ -64,7 +71,7 @@ class X25519PrivateKey(metaclass=abc.ABCMeta): return rust_openssl.x25519.generate_key() @classmethod - def from_private_bytes(cls, data: bytes) -> X25519PrivateKey: + def from_private_bytes(cls, data: Buffer) -> X25519PrivateKey: from cryptography.hazmat.backends.openssl.backend import backend if not backend.x25519_supported(): @@ -105,5 +112,11 @@ class X25519PrivateKey(metaclass=abc.ABCMeta): Performs a key exchange operation using the provided peer's public key. """ + @abc.abstractmethod + def __copy__(self) -> X25519PrivateKey: + """ + Returns a copy. + """ + X25519PrivateKey.register(rust_openssl.x25519.X25519PrivateKey) diff --git a/venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/x448.py b/venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/x448.py index 86086ab..c6fd71b 100644 --- a/venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/x448.py +++ b/venv/Lib/site-packages/cryptography/hazmat/primitives/asymmetric/x448.py @@ -9,6 +9,7 @@ import abc from cryptography.exceptions import UnsupportedAlgorithm, _Reasons from cryptography.hazmat.bindings._rust import openssl as rust_openssl from cryptography.hazmat.primitives import _serialization +from cryptography.utils import Buffer class X448PublicKey(metaclass=abc.ABCMeta): @@ -47,6 +48,12 @@ class X448PublicKey(metaclass=abc.ABCMeta): Checks equality. """ + @abc.abstractmethod + def __copy__(self) -> X448PublicKey: + """ + Returns a copy. + """ + if hasattr(rust_openssl, "x448"): X448PublicKey.register(rust_openssl.x448.X448PublicKey) @@ -66,7 +73,7 @@ class X448PrivateKey(metaclass=abc.ABCMeta): return rust_openssl.x448.generate_key() @classmethod - def from_private_bytes(cls, data: bytes) -> X448PrivateKey: + def from_private_bytes(cls, data: Buffer) -> X448PrivateKey: from cryptography.hazmat.backends.openssl.backend import backend if not backend.x448_supported(): @@ -107,6 +114,12 @@ class X448PrivateKey(metaclass=abc.ABCMeta): Performs a key exchange operation using the provided peer's public key. """ + @abc.abstractmethod + def __copy__(self) -> X448PrivateKey: + """ + Returns a copy. + """ + if hasattr(rust_openssl, "x448"): X448PrivateKey.register(rust_openssl.x448.X448PrivateKey) diff --git a/venv/Lib/site-packages/cryptography/hazmat/primitives/ciphers/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/cryptography/hazmat/primitives/ciphers/__pycache__/__init__.cpython-312.pyc index 780e6e3..3b8faae 100644 Binary files a/venv/Lib/site-packages/cryptography/hazmat/primitives/ciphers/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/cryptography/hazmat/primitives/ciphers/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/cryptography/hazmat/primitives/ciphers/__pycache__/aead.cpython-312.pyc b/venv/Lib/site-packages/cryptography/hazmat/primitives/ciphers/__pycache__/aead.cpython-312.pyc index 7abff36..130c3f7 100644 Binary files a/venv/Lib/site-packages/cryptography/hazmat/primitives/ciphers/__pycache__/aead.cpython-312.pyc and b/venv/Lib/site-packages/cryptography/hazmat/primitives/ciphers/__pycache__/aead.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/cryptography/hazmat/primitives/ciphers/__pycache__/algorithms.cpython-312.pyc b/venv/Lib/site-packages/cryptography/hazmat/primitives/ciphers/__pycache__/algorithms.cpython-312.pyc index fe0e3bd..8a810b0 100644 Binary files a/venv/Lib/site-packages/cryptography/hazmat/primitives/ciphers/__pycache__/algorithms.cpython-312.pyc and b/venv/Lib/site-packages/cryptography/hazmat/primitives/ciphers/__pycache__/algorithms.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/cryptography/hazmat/primitives/ciphers/__pycache__/base.cpython-312.pyc b/venv/Lib/site-packages/cryptography/hazmat/primitives/ciphers/__pycache__/base.cpython-312.pyc index 49bd01c..f2b5cf1 100644 Binary files a/venv/Lib/site-packages/cryptography/hazmat/primitives/ciphers/__pycache__/base.cpython-312.pyc and b/venv/Lib/site-packages/cryptography/hazmat/primitives/ciphers/__pycache__/base.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/cryptography/hazmat/primitives/ciphers/__pycache__/modes.cpython-312.pyc b/venv/Lib/site-packages/cryptography/hazmat/primitives/ciphers/__pycache__/modes.cpython-312.pyc index adee406..a1a3a28 100644 Binary files a/venv/Lib/site-packages/cryptography/hazmat/primitives/ciphers/__pycache__/modes.cpython-312.pyc and b/venv/Lib/site-packages/cryptography/hazmat/primitives/ciphers/__pycache__/modes.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/cryptography/hazmat/primitives/ciphers/algorithms.py b/venv/Lib/site-packages/cryptography/hazmat/primitives/ciphers/algorithms.py index f9fa8a5..1e402c7 100644 --- a/venv/Lib/site-packages/cryptography/hazmat/primitives/ciphers/algorithms.py +++ b/venv/Lib/site-packages/cryptography/hazmat/primitives/ciphers/algorithms.py @@ -36,7 +36,7 @@ class AES(BlockCipherAlgorithm): # 512 added to support AES-256-XTS, which uses 512-bit keys key_sizes = frozenset([128, 192, 256, 512]) - def __init__(self, key: bytes): + def __init__(self, key: utils.Buffer): self.key = _verify_key_size(self, key) @property @@ -50,7 +50,7 @@ class AES128(BlockCipherAlgorithm): key_sizes = frozenset([128]) key_size = 128 - def __init__(self, key: bytes): + def __init__(self, key: utils.Buffer): self.key = _verify_key_size(self, key) @@ -60,7 +60,7 @@ class AES256(BlockCipherAlgorithm): key_sizes = frozenset([256]) key_size = 256 - def __init__(self, key: bytes): + def __init__(self, key: utils.Buffer): self.key = _verify_key_size(self, key) @@ -69,7 +69,7 @@ class Camellia(BlockCipherAlgorithm): block_size = 128 key_sizes = frozenset([128, 192, 256]) - def __init__(self, key: bytes): + def __init__(self, key: utils.Buffer): self.key = _verify_key_size(self, key) @property @@ -100,59 +100,12 @@ utils.deprecated( name="TripleDES", ) -utils.deprecated( - Blowfish, - __name__, - "Blowfish has been moved to " - "cryptography.hazmat.decrepit.ciphers.algorithms.Blowfish and " - "will be removed from " - "cryptography.hazmat.primitives.ciphers.algorithms in 45.0.0.", - utils.DeprecatedIn37, - name="Blowfish", -) - - -utils.deprecated( - CAST5, - __name__, - "CAST5 has been moved to " - "cryptography.hazmat.decrepit.ciphers.algorithms.CAST5 and " - "will be removed from " - "cryptography.hazmat.primitives.ciphers.algorithms in 45.0.0.", - utils.DeprecatedIn37, - name="CAST5", -) - - -utils.deprecated( - IDEA, - __name__, - "IDEA has been moved to " - "cryptography.hazmat.decrepit.ciphers.algorithms.IDEA and " - "will be removed from " - "cryptography.hazmat.primitives.ciphers.algorithms in 45.0.0.", - utils.DeprecatedIn37, - name="IDEA", -) - - -utils.deprecated( - SEED, - __name__, - "SEED has been moved to " - "cryptography.hazmat.decrepit.ciphers.algorithms.SEED and " - "will be removed from " - "cryptography.hazmat.primitives.ciphers.algorithms in 45.0.0.", - utils.DeprecatedIn37, - name="SEED", -) - class ChaCha20(CipherAlgorithm): name = "ChaCha20" key_sizes = frozenset([256]) - def __init__(self, key: bytes, nonce: bytes): + def __init__(self, key: utils.Buffer, nonce: utils.Buffer): self.key = _verify_key_size(self, key) utils._check_byteslike("nonce", nonce) @@ -162,7 +115,7 @@ class ChaCha20(CipherAlgorithm): self._nonce = nonce @property - def nonce(self) -> bytes: + def nonce(self) -> utils.Buffer: return self._nonce @property diff --git a/venv/Lib/site-packages/cryptography/hazmat/primitives/ciphers/base.py b/venv/Lib/site-packages/cryptography/hazmat/primitives/ciphers/base.py index ebfa805..24fceea 100644 --- a/venv/Lib/site-packages/cryptography/hazmat/primitives/ciphers/base.py +++ b/venv/Lib/site-packages/cryptography/hazmat/primitives/ciphers/base.py @@ -10,18 +10,19 @@ import typing from cryptography.hazmat.bindings._rust import openssl as rust_openssl from cryptography.hazmat.primitives._cipheralgorithm import CipherAlgorithm from cryptography.hazmat.primitives.ciphers import modes +from cryptography.utils import Buffer class CipherContext(metaclass=abc.ABCMeta): @abc.abstractmethod - def update(self, data: bytes) -> bytes: + def update(self, data: Buffer) -> bytes: """ Processes the provided bytes through the cipher and returns the results as bytes. """ @abc.abstractmethod - def update_into(self, data: bytes, buf: bytes) -> int: + def update_into(self, data: Buffer, buf: Buffer) -> int: """ Processes the provided bytes and writes the resulting data into the provided buffer. Returns the number of bytes written. @@ -44,7 +45,7 @@ class CipherContext(metaclass=abc.ABCMeta): class AEADCipherContext(CipherContext, metaclass=abc.ABCMeta): @abc.abstractmethod - def authenticate_additional_data(self, data: bytes) -> None: + def authenticate_additional_data(self, data: Buffer) -> None: """ Authenticates the provided bytes. """ @@ -134,9 +135,9 @@ _CIPHER_TYPE = Cipher[ typing.Union[ modes.ModeWithNonce, modes.ModeWithTweak, - None, modes.ECB, modes.ModeWithInitializationVector, + None, ] ] diff --git a/venv/Lib/site-packages/cryptography/hazmat/primitives/ciphers/modes.py b/venv/Lib/site-packages/cryptography/hazmat/primitives/ciphers/modes.py index 1dd2cc1..36c555c 100644 --- a/venv/Lib/site-packages/cryptography/hazmat/primitives/ciphers/modes.py +++ b/venv/Lib/site-packages/cryptography/hazmat/primitives/ciphers/modes.py @@ -34,7 +34,7 @@ class Mode(metaclass=abc.ABCMeta): class ModeWithInitializationVector(Mode, metaclass=abc.ABCMeta): @property @abc.abstractmethod - def initialization_vector(self) -> bytes: + def initialization_vector(self) -> utils.Buffer: """ The value of the initialization vector for this mode as bytes. """ @@ -43,7 +43,7 @@ class ModeWithInitializationVector(Mode, metaclass=abc.ABCMeta): class ModeWithTweak(Mode, metaclass=abc.ABCMeta): @property @abc.abstractmethod - def tweak(self) -> bytes: + def tweak(self) -> utils.Buffer: """ The value of the tweak for this mode as bytes. """ @@ -52,7 +52,7 @@ class ModeWithTweak(Mode, metaclass=abc.ABCMeta): class ModeWithNonce(Mode, metaclass=abc.ABCMeta): @property @abc.abstractmethod - def nonce(self) -> bytes: + def nonce(self) -> utils.Buffer: """ The value of the nonce for this mode as bytes. """ @@ -83,7 +83,7 @@ def _check_iv_length( def _check_nonce_length( - nonce: bytes, name: str, algorithm: CipherAlgorithm + nonce: utils.Buffer, name: str, algorithm: CipherAlgorithm ) -> None: if not isinstance(algorithm, BlockCipherAlgorithm): raise UnsupportedAlgorithm( @@ -109,12 +109,12 @@ def _check_iv_and_key_length( class CBC(ModeWithInitializationVector): name = "CBC" - def __init__(self, initialization_vector: bytes): + def __init__(self, initialization_vector: utils.Buffer): utils._check_byteslike("initialization_vector", initialization_vector) self._initialization_vector = initialization_vector @property - def initialization_vector(self) -> bytes: + def initialization_vector(self) -> utils.Buffer: return self._initialization_vector validate_for_algorithm = _check_iv_and_key_length @@ -123,7 +123,7 @@ class CBC(ModeWithInitializationVector): class XTS(ModeWithTweak): name = "XTS" - def __init__(self, tweak: bytes): + def __init__(self, tweak: utils.Buffer): utils._check_byteslike("tweak", tweak) if len(tweak) != 16: @@ -132,7 +132,7 @@ class XTS(ModeWithTweak): self._tweak = tweak @property - def tweak(self) -> bytes: + def tweak(self) -> utils.Buffer: return self._tweak def validate_for_algorithm(self, algorithm: CipherAlgorithm) -> None: @@ -158,12 +158,12 @@ class ECB(Mode): class OFB(ModeWithInitializationVector): name = "OFB" - def __init__(self, initialization_vector: bytes): + def __init__(self, initialization_vector: utils.Buffer): utils._check_byteslike("initialization_vector", initialization_vector) self._initialization_vector = initialization_vector @property - def initialization_vector(self) -> bytes: + def initialization_vector(self) -> utils.Buffer: return self._initialization_vector validate_for_algorithm = _check_iv_and_key_length @@ -172,12 +172,12 @@ class OFB(ModeWithInitializationVector): class CFB(ModeWithInitializationVector): name = "CFB" - def __init__(self, initialization_vector: bytes): + def __init__(self, initialization_vector: utils.Buffer): utils._check_byteslike("initialization_vector", initialization_vector) self._initialization_vector = initialization_vector @property - def initialization_vector(self) -> bytes: + def initialization_vector(self) -> utils.Buffer: return self._initialization_vector validate_for_algorithm = _check_iv_and_key_length @@ -186,12 +186,12 @@ class CFB(ModeWithInitializationVector): class CFB8(ModeWithInitializationVector): name = "CFB8" - def __init__(self, initialization_vector: bytes): + def __init__(self, initialization_vector: utils.Buffer): utils._check_byteslike("initialization_vector", initialization_vector) self._initialization_vector = initialization_vector @property - def initialization_vector(self) -> bytes: + def initialization_vector(self) -> utils.Buffer: return self._initialization_vector validate_for_algorithm = _check_iv_and_key_length @@ -200,12 +200,12 @@ class CFB8(ModeWithInitializationVector): class CTR(ModeWithNonce): name = "CTR" - def __init__(self, nonce: bytes): + def __init__(self, nonce: utils.Buffer): utils._check_byteslike("nonce", nonce) self._nonce = nonce @property - def nonce(self) -> bytes: + def nonce(self) -> utils.Buffer: return self._nonce def validate_for_algorithm(self, algorithm: CipherAlgorithm) -> None: @@ -220,7 +220,7 @@ class GCM(ModeWithInitializationVector, ModeWithAuthenticationTag): def __init__( self, - initialization_vector: bytes, + initialization_vector: utils.Buffer, tag: bytes | None = None, min_tag_length: int = 16, ): @@ -250,7 +250,7 @@ class GCM(ModeWithInitializationVector, ModeWithAuthenticationTag): return self._tag @property - def initialization_vector(self) -> bytes: + def initialization_vector(self) -> utils.Buffer: return self._initialization_vector def validate_for_algorithm(self, algorithm: CipherAlgorithm) -> None: diff --git a/venv/Lib/site-packages/cryptography/hazmat/primitives/hashes.py b/venv/Lib/site-packages/cryptography/hazmat/primitives/hashes.py index b819e39..4b55ec3 100644 --- a/venv/Lib/site-packages/cryptography/hazmat/primitives/hashes.py +++ b/venv/Lib/site-packages/cryptography/hazmat/primitives/hashes.py @@ -7,6 +7,7 @@ from __future__ import annotations import abc from cryptography.hazmat.bindings._rust import openssl as rust_openssl +from cryptography.utils import Buffer __all__ = [ "MD5", @@ -30,6 +31,7 @@ __all__ = [ "Hash", "HashAlgorithm", "HashContext", + "XOFHash", ] @@ -66,7 +68,7 @@ class HashContext(metaclass=abc.ABCMeta): """ @abc.abstractmethod - def update(self, data: bytes) -> None: + def update(self, data: Buffer) -> None: """ Processes the provided bytes through the hash. """ @@ -87,6 +89,8 @@ class HashContext(metaclass=abc.ABCMeta): Hash = rust_openssl.hashes.Hash HashContext.register(Hash) +XOFHash = rust_openssl.hashes.XOFHash + class ExtendableOutputFunction(metaclass=abc.ABCMeta): """ diff --git a/venv/Lib/site-packages/cryptography/hazmat/primitives/kdf/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/cryptography/hazmat/primitives/kdf/__pycache__/__init__.cpython-312.pyc index fe0633d..06ae219 100644 Binary files a/venv/Lib/site-packages/cryptography/hazmat/primitives/kdf/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/cryptography/hazmat/primitives/kdf/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/cryptography/hazmat/primitives/kdf/__pycache__/argon2.cpython-312.pyc b/venv/Lib/site-packages/cryptography/hazmat/primitives/kdf/__pycache__/argon2.cpython-312.pyc index db18bda..b777e3f 100644 Binary files a/venv/Lib/site-packages/cryptography/hazmat/primitives/kdf/__pycache__/argon2.cpython-312.pyc and b/venv/Lib/site-packages/cryptography/hazmat/primitives/kdf/__pycache__/argon2.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/cryptography/hazmat/primitives/kdf/__pycache__/concatkdf.cpython-312.pyc b/venv/Lib/site-packages/cryptography/hazmat/primitives/kdf/__pycache__/concatkdf.cpython-312.pyc index 947523f..da722a6 100644 Binary files a/venv/Lib/site-packages/cryptography/hazmat/primitives/kdf/__pycache__/concatkdf.cpython-312.pyc and b/venv/Lib/site-packages/cryptography/hazmat/primitives/kdf/__pycache__/concatkdf.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/cryptography/hazmat/primitives/kdf/__pycache__/hkdf.cpython-312.pyc b/venv/Lib/site-packages/cryptography/hazmat/primitives/kdf/__pycache__/hkdf.cpython-312.pyc index b83c131..5365f9a 100644 Binary files a/venv/Lib/site-packages/cryptography/hazmat/primitives/kdf/__pycache__/hkdf.cpython-312.pyc and b/venv/Lib/site-packages/cryptography/hazmat/primitives/kdf/__pycache__/hkdf.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/cryptography/hazmat/primitives/kdf/__pycache__/kbkdf.cpython-312.pyc b/venv/Lib/site-packages/cryptography/hazmat/primitives/kdf/__pycache__/kbkdf.cpython-312.pyc index b4d2b1b..c9e886a 100644 Binary files a/venv/Lib/site-packages/cryptography/hazmat/primitives/kdf/__pycache__/kbkdf.cpython-312.pyc and b/venv/Lib/site-packages/cryptography/hazmat/primitives/kdf/__pycache__/kbkdf.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/cryptography/hazmat/primitives/kdf/__pycache__/pbkdf2.cpython-312.pyc b/venv/Lib/site-packages/cryptography/hazmat/primitives/kdf/__pycache__/pbkdf2.cpython-312.pyc index dafeaca..d9e04f8 100644 Binary files a/venv/Lib/site-packages/cryptography/hazmat/primitives/kdf/__pycache__/pbkdf2.cpython-312.pyc and b/venv/Lib/site-packages/cryptography/hazmat/primitives/kdf/__pycache__/pbkdf2.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/cryptography/hazmat/primitives/kdf/__pycache__/scrypt.cpython-312.pyc b/venv/Lib/site-packages/cryptography/hazmat/primitives/kdf/__pycache__/scrypt.cpython-312.pyc index 11b66d2..f5834e4 100644 Binary files a/venv/Lib/site-packages/cryptography/hazmat/primitives/kdf/__pycache__/scrypt.cpython-312.pyc and b/venv/Lib/site-packages/cryptography/hazmat/primitives/kdf/__pycache__/scrypt.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/cryptography/hazmat/primitives/kdf/__pycache__/x963kdf.cpython-312.pyc b/venv/Lib/site-packages/cryptography/hazmat/primitives/kdf/__pycache__/x963kdf.cpython-312.pyc index 880e804..fe3f000 100644 Binary files a/venv/Lib/site-packages/cryptography/hazmat/primitives/kdf/__pycache__/x963kdf.cpython-312.pyc and b/venv/Lib/site-packages/cryptography/hazmat/primitives/kdf/__pycache__/x963kdf.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/cryptography/hazmat/primitives/kdf/concatkdf.py b/venv/Lib/site-packages/cryptography/hazmat/primitives/kdf/concatkdf.py index 96d9d4c..1b92841 100644 --- a/venv/Lib/site-packages/cryptography/hazmat/primitives/kdf/concatkdf.py +++ b/venv/Lib/site-packages/cryptography/hazmat/primitives/kdf/concatkdf.py @@ -5,6 +5,7 @@ from __future__ import annotations import typing +from collections.abc import Callable from cryptography import utils from cryptography.exceptions import AlreadyFinalized, InvalidKey @@ -29,9 +30,9 @@ def _common_args_checks( def _concatkdf_derive( - key_material: bytes, + key_material: utils.Buffer, length: int, - auxfn: typing.Callable[[], hashes.HashContext], + auxfn: Callable[[], hashes.HashContext], otherinfo: bytes, ) -> bytes: utils._check_byteslike("key_material", key_material) @@ -69,7 +70,7 @@ class ConcatKDFHash(KeyDerivationFunction): def _hash(self) -> hashes.Hash: return hashes.Hash(self._algorithm) - def derive(self, key_material: bytes) -> bytes: + def derive(self, key_material: utils.Buffer) -> bytes: if self._used: raise AlreadyFinalized self._used = True @@ -111,7 +112,7 @@ class ConcatKDFHMAC(KeyDerivationFunction): def _hmac(self) -> hmac.HMAC: return hmac.HMAC(self._salt, self._algorithm) - def derive(self, key_material: bytes) -> bytes: + def derive(self, key_material: utils.Buffer) -> bytes: if self._used: raise AlreadyFinalized self._used = True diff --git a/venv/Lib/site-packages/cryptography/hazmat/primitives/kdf/hkdf.py b/venv/Lib/site-packages/cryptography/hazmat/primitives/kdf/hkdf.py index ee562d2..1e162d9 100644 --- a/venv/Lib/site-packages/cryptography/hazmat/primitives/kdf/hkdf.py +++ b/venv/Lib/site-packages/cryptography/hazmat/primitives/kdf/hkdf.py @@ -4,98 +4,13 @@ from __future__ import annotations -import typing - -from cryptography import utils -from cryptography.exceptions import AlreadyFinalized, InvalidKey -from cryptography.hazmat.primitives import constant_time, hashes, hmac +from cryptography.hazmat.bindings._rust import openssl as rust_openssl from cryptography.hazmat.primitives.kdf import KeyDerivationFunction +HKDF = rust_openssl.kdf.HKDF +HKDFExpand = rust_openssl.kdf.HKDFExpand -class HKDF(KeyDerivationFunction): - def __init__( - self, - algorithm: hashes.HashAlgorithm, - length: int, - salt: bytes | None, - info: bytes | None, - backend: typing.Any = None, - ): - self._algorithm = algorithm +KeyDerivationFunction.register(HKDF) +KeyDerivationFunction.register(HKDFExpand) - if salt is None: - salt = b"\x00" * self._algorithm.digest_size - else: - utils._check_bytes("salt", salt) - - self._salt = salt - - self._hkdf_expand = HKDFExpand(self._algorithm, length, info) - - def _extract(self, key_material: bytes) -> bytes: - h = hmac.HMAC(self._salt, self._algorithm) - h.update(key_material) - return h.finalize() - - def derive(self, key_material: bytes) -> bytes: - utils._check_byteslike("key_material", key_material) - return self._hkdf_expand.derive(self._extract(key_material)) - - def verify(self, key_material: bytes, expected_key: bytes) -> None: - if not constant_time.bytes_eq(self.derive(key_material), expected_key): - raise InvalidKey - - -class HKDFExpand(KeyDerivationFunction): - def __init__( - self, - algorithm: hashes.HashAlgorithm, - length: int, - info: bytes | None, - backend: typing.Any = None, - ): - self._algorithm = algorithm - - max_length = 255 * algorithm.digest_size - - if length > max_length: - raise ValueError( - f"Cannot derive keys larger than {max_length} octets." - ) - - self._length = length - - if info is None: - info = b"" - else: - utils._check_bytes("info", info) - - self._info = info - - self._used = False - - def _expand(self, key_material: bytes) -> bytes: - output = [b""] - counter = 1 - - while self._algorithm.digest_size * (len(output) - 1) < self._length: - h = hmac.HMAC(key_material, self._algorithm) - h.update(output[-1]) - h.update(self._info) - h.update(bytes([counter])) - output.append(h.finalize()) - counter += 1 - - return b"".join(output)[: self._length] - - def derive(self, key_material: bytes) -> bytes: - utils._check_byteslike("key_material", key_material) - if self._used: - raise AlreadyFinalized - - self._used = True - return self._expand(key_material) - - def verify(self, key_material: bytes, expected_key: bytes) -> None: - if not constant_time.bytes_eq(self.derive(key_material), expected_key): - raise InvalidKey +__all__ = ["HKDF", "HKDFExpand"] diff --git a/venv/Lib/site-packages/cryptography/hazmat/primitives/kdf/kbkdf.py b/venv/Lib/site-packages/cryptography/hazmat/primitives/kdf/kbkdf.py index 802b484..5b47137 100644 --- a/venv/Lib/site-packages/cryptography/hazmat/primitives/kdf/kbkdf.py +++ b/venv/Lib/site-packages/cryptography/hazmat/primitives/kdf/kbkdf.py @@ -5,6 +5,7 @@ from __future__ import annotations import typing +from collections.abc import Callable from cryptography import utils from cryptography.exceptions import ( @@ -36,7 +37,7 @@ class CounterLocation(utils.Enum): class _KBKDFDeriver: def __init__( self, - prf: typing.Callable, + prf: Callable, mode: Mode, length: int, rlen: int, @@ -116,11 +117,11 @@ class _KBKDFDeriver: raise TypeError("value must be of type int") value_bin = utils.int_to_bytes(1, value) - if not 1 <= len(value_bin) <= 4: - return False - return True + return 1 <= len(value_bin) <= 4 - def derive(self, key_material: bytes, prf_output_size: int) -> bytes: + def derive( + self, key_material: utils.Buffer, prf_output_size: int + ) -> bytes: if self._used: raise AlreadyFinalized @@ -227,7 +228,7 @@ class KBKDFHMAC(KeyDerivationFunction): def _prf(self, key_material: bytes) -> hmac.HMAC: return hmac.HMAC(key_material, self._algorithm) - def derive(self, key_material: bytes) -> bytes: + def derive(self, key_material: utils.Buffer) -> bytes: return self._deriver.derive(key_material, self._algorithm.digest_size) def verify(self, key_material: bytes, expected_key: bytes) -> None: @@ -280,7 +281,7 @@ class KBKDFCMAC(KeyDerivationFunction): return cmac.CMAC(self._cipher) - def derive(self, key_material: bytes) -> bytes: + def derive(self, key_material: utils.Buffer) -> bytes: self._cipher = self._algorithm(key_material) assert self._cipher is not None diff --git a/venv/Lib/site-packages/cryptography/hazmat/primitives/kdf/pbkdf2.py b/venv/Lib/site-packages/cryptography/hazmat/primitives/kdf/pbkdf2.py index 82689eb..d539f13 100644 --- a/venv/Lib/site-packages/cryptography/hazmat/primitives/kdf/pbkdf2.py +++ b/venv/Lib/site-packages/cryptography/hazmat/primitives/kdf/pbkdf2.py @@ -43,7 +43,7 @@ class PBKDF2HMAC(KeyDerivationFunction): self._salt = salt self._iterations = iterations - def derive(self, key_material: bytes) -> bytes: + def derive(self, key_material: utils.Buffer) -> bytes: if self._used: raise AlreadyFinalized("PBKDF2 instances can only be used once.") self._used = True diff --git a/venv/Lib/site-packages/cryptography/hazmat/primitives/kdf/x963kdf.py b/venv/Lib/site-packages/cryptography/hazmat/primitives/kdf/x963kdf.py index 6e38366..63870cd 100644 --- a/venv/Lib/site-packages/cryptography/hazmat/primitives/kdf/x963kdf.py +++ b/venv/Lib/site-packages/cryptography/hazmat/primitives/kdf/x963kdf.py @@ -35,7 +35,7 @@ class X963KDF(KeyDerivationFunction): self._sharedinfo = sharedinfo self._used = False - def derive(self, key_material: bytes) -> bytes: + def derive(self, key_material: utils.Buffer) -> bytes: if self._used: raise AlreadyFinalized self._used = True diff --git a/venv/Lib/site-packages/cryptography/hazmat/primitives/padding.py b/venv/Lib/site-packages/cryptography/hazmat/primitives/padding.py index b2a3f1c..f9cd1f1 100644 --- a/venv/Lib/site-packages/cryptography/hazmat/primitives/padding.py +++ b/venv/Lib/site-packages/cryptography/hazmat/primitives/padding.py @@ -5,20 +5,19 @@ from __future__ import annotations import abc -import typing from cryptography import utils -from cryptography.exceptions import AlreadyFinalized from cryptography.hazmat.bindings._rust import ( + ANSIX923PaddingContext, + ANSIX923UnpaddingContext, PKCS7PaddingContext, PKCS7UnpaddingContext, - check_ansix923_padding, ) class PaddingContext(metaclass=abc.ABCMeta): @abc.abstractmethod - def update(self, data: bytes) -> bytes: + def update(self, data: utils.Buffer) -> bytes: """ Pads the provided bytes and returns any available data as bytes. """ @@ -38,74 +37,6 @@ def _byte_padding_check(block_size: int) -> None: raise ValueError("block_size must be a multiple of 8.") -def _byte_padding_update( - buffer_: bytes | None, data: bytes, block_size: int -) -> tuple[bytes, bytes]: - if buffer_ is None: - raise AlreadyFinalized("Context was already finalized.") - - utils._check_byteslike("data", data) - - buffer_ += bytes(data) - - finished_blocks = len(buffer_) // (block_size // 8) - - result = buffer_[: finished_blocks * (block_size // 8)] - buffer_ = buffer_[finished_blocks * (block_size // 8) :] - - return buffer_, result - - -def _byte_padding_pad( - buffer_: bytes | None, - block_size: int, - paddingfn: typing.Callable[[int], bytes], -) -> bytes: - if buffer_ is None: - raise AlreadyFinalized("Context was already finalized.") - - pad_size = block_size // 8 - len(buffer_) - return buffer_ + paddingfn(pad_size) - - -def _byte_unpadding_update( - buffer_: bytes | None, data: bytes, block_size: int -) -> tuple[bytes, bytes]: - if buffer_ is None: - raise AlreadyFinalized("Context was already finalized.") - - utils._check_byteslike("data", data) - - buffer_ += bytes(data) - - finished_blocks = max(len(buffer_) // (block_size // 8) - 1, 0) - - result = buffer_[: finished_blocks * (block_size // 8)] - buffer_ = buffer_[finished_blocks * (block_size // 8) :] - - return buffer_, result - - -def _byte_unpadding_check( - buffer_: bytes | None, - block_size: int, - checkfn: typing.Callable[[bytes], int], -) -> bytes: - if buffer_ is None: - raise AlreadyFinalized("Context was already finalized.") - - if len(buffer_) != block_size // 8: - raise ValueError("Invalid padding bytes.") - - valid = checkfn(buffer_) - - if not valid: - raise ValueError("Invalid padding bytes.") - - pad_size = buffer_[-1] - return buffer_[:-pad_size] - - class PKCS7: def __init__(self, block_size: int): _byte_padding_check(block_size) @@ -128,56 +59,11 @@ class ANSIX923: self.block_size = block_size def padder(self) -> PaddingContext: - return _ANSIX923PaddingContext(self.block_size) + return ANSIX923PaddingContext(self.block_size) def unpadder(self) -> PaddingContext: - return _ANSIX923UnpaddingContext(self.block_size) + return ANSIX923UnpaddingContext(self.block_size) -class _ANSIX923PaddingContext(PaddingContext): - _buffer: bytes | None - - def __init__(self, block_size: int): - self.block_size = block_size - # TODO: more copies than necessary, we should use zero-buffer (#193) - self._buffer = b"" - - def update(self, data: bytes) -> bytes: - self._buffer, result = _byte_padding_update( - self._buffer, data, self.block_size - ) - return result - - def _padding(self, size: int) -> bytes: - return bytes([0]) * (size - 1) + bytes([size]) - - def finalize(self) -> bytes: - result = _byte_padding_pad( - self._buffer, self.block_size, self._padding - ) - self._buffer = None - return result - - -class _ANSIX923UnpaddingContext(PaddingContext): - _buffer: bytes | None - - def __init__(self, block_size: int): - self.block_size = block_size - # TODO: more copies than necessary, we should use zero-buffer (#193) - self._buffer = b"" - - def update(self, data: bytes) -> bytes: - self._buffer, result = _byte_unpadding_update( - self._buffer, data, self.block_size - ) - return result - - def finalize(self) -> bytes: - result = _byte_unpadding_check( - self._buffer, - self.block_size, - check_ansix923_padding, - ) - self._buffer = None - return result +PaddingContext.register(ANSIX923PaddingContext) +PaddingContext.register(ANSIX923UnpaddingContext) diff --git a/venv/Lib/site-packages/cryptography/hazmat/primitives/serialization/__init__.py b/venv/Lib/site-packages/cryptography/hazmat/primitives/serialization/__init__.py index 07b2264..62283cc 100644 --- a/venv/Lib/site-packages/cryptography/hazmat/primitives/serialization/__init__.py +++ b/venv/Lib/site-packages/cryptography/hazmat/primitives/serialization/__init__.py @@ -33,6 +33,7 @@ from cryptography.hazmat.primitives.serialization.ssh import ( load_ssh_private_key, load_ssh_public_identity, load_ssh_public_key, + ssh_key_fingerprint, ) __all__ = [ @@ -60,4 +61,5 @@ __all__ = [ "load_ssh_private_key", "load_ssh_public_identity", "load_ssh_public_key", + "ssh_key_fingerprint", ] diff --git a/venv/Lib/site-packages/cryptography/hazmat/primitives/serialization/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/cryptography/hazmat/primitives/serialization/__pycache__/__init__.cpython-312.pyc index bf0d536..b97c7b2 100644 Binary files a/venv/Lib/site-packages/cryptography/hazmat/primitives/serialization/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/cryptography/hazmat/primitives/serialization/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/cryptography/hazmat/primitives/serialization/__pycache__/base.cpython-312.pyc b/venv/Lib/site-packages/cryptography/hazmat/primitives/serialization/__pycache__/base.cpython-312.pyc index 7fdc1e4..20b95e8 100644 Binary files a/venv/Lib/site-packages/cryptography/hazmat/primitives/serialization/__pycache__/base.cpython-312.pyc and b/venv/Lib/site-packages/cryptography/hazmat/primitives/serialization/__pycache__/base.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/cryptography/hazmat/primitives/serialization/__pycache__/pkcs12.cpython-312.pyc b/venv/Lib/site-packages/cryptography/hazmat/primitives/serialization/__pycache__/pkcs12.cpython-312.pyc index 42a9b9a..69837d2 100644 Binary files a/venv/Lib/site-packages/cryptography/hazmat/primitives/serialization/__pycache__/pkcs12.cpython-312.pyc and b/venv/Lib/site-packages/cryptography/hazmat/primitives/serialization/__pycache__/pkcs12.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/cryptography/hazmat/primitives/serialization/__pycache__/pkcs7.cpython-312.pyc b/venv/Lib/site-packages/cryptography/hazmat/primitives/serialization/__pycache__/pkcs7.cpython-312.pyc index e58f9f0..cd5063e 100644 Binary files a/venv/Lib/site-packages/cryptography/hazmat/primitives/serialization/__pycache__/pkcs7.cpython-312.pyc and b/venv/Lib/site-packages/cryptography/hazmat/primitives/serialization/__pycache__/pkcs7.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/cryptography/hazmat/primitives/serialization/__pycache__/ssh.cpython-312.pyc b/venv/Lib/site-packages/cryptography/hazmat/primitives/serialization/__pycache__/ssh.cpython-312.pyc index d3ed4d6..aa15405 100644 Binary files a/venv/Lib/site-packages/cryptography/hazmat/primitives/serialization/__pycache__/ssh.cpython-312.pyc and b/venv/Lib/site-packages/cryptography/hazmat/primitives/serialization/__pycache__/ssh.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/cryptography/hazmat/primitives/serialization/pkcs12.py b/venv/Lib/site-packages/cryptography/hazmat/primitives/serialization/pkcs12.py index 549e1f9..58884ff 100644 --- a/venv/Lib/site-packages/cryptography/hazmat/primitives/serialization/pkcs12.py +++ b/venv/Lib/site-packages/cryptography/hazmat/primitives/serialization/pkcs12.py @@ -5,6 +5,7 @@ from __future__ import annotations import typing +from collections.abc import Iterable from cryptography import x509 from cryptography.hazmat.bindings._rust import pkcs12 as rust_pkcs12 @@ -26,6 +27,7 @@ __all__ = [ "PKCS12PrivateKeyTypes", "load_key_and_certificates", "load_pkcs12", + "serialize_java_truststore", "serialize_key_and_certificates", ] @@ -118,11 +120,29 @@ _PKCS12CATypes = typing.Union[ ] +def serialize_java_truststore( + certs: Iterable[PKCS12Certificate], + encryption_algorithm: serialization.KeySerializationEncryption, +) -> bytes: + if not certs: + raise ValueError("You must supply at least one cert") + + if not isinstance( + encryption_algorithm, serialization.KeySerializationEncryption + ): + raise TypeError( + "Key encryption algorithm must be a " + "KeySerializationEncryption instance" + ) + + return rust_pkcs12.serialize_java_truststore(certs, encryption_algorithm) + + def serialize_key_and_certificates( name: bytes | None, key: PKCS12PrivateKeyTypes | None, cert: x509.Certificate | None, - cas: typing.Iterable[_PKCS12CATypes] | None, + cas: Iterable[_PKCS12CATypes] | None, encryption_algorithm: serialization.KeySerializationEncryption, ) -> bytes: if key is not None and not isinstance( diff --git a/venv/Lib/site-packages/cryptography/hazmat/primitives/serialization/pkcs7.py b/venv/Lib/site-packages/cryptography/hazmat/primitives/serialization/pkcs7.py index 882e345..456dc5b 100644 --- a/venv/Lib/site-packages/cryptography/hazmat/primitives/serialization/pkcs7.py +++ b/venv/Lib/site-packages/cryptography/hazmat/primitives/serialization/pkcs7.py @@ -10,12 +10,16 @@ import email.message import email.policy import io import typing +from collections.abc import Iterable from cryptography import utils, x509 from cryptography.exceptions import UnsupportedAlgorithm, _Reasons from cryptography.hazmat.bindings._rust import pkcs7 as rust_pkcs7 from cryptography.hazmat.primitives import hashes, serialization from cryptography.hazmat.primitives.asymmetric import ec, padding, rsa +from cryptography.hazmat.primitives.ciphers import ( + algorithms, +) from cryptography.utils import _check_byteslike load_pem_pkcs7_certificates = rust_pkcs7.load_pem_pkcs7_certificates @@ -35,6 +39,10 @@ PKCS7PrivateKeyTypes = typing.Union[ rsa.RSAPrivateKey, ec.EllipticCurvePrivateKey ] +ContentEncryptionAlgorithm = typing.Union[ + typing.Type[algorithms.AES128], typing.Type[algorithms.AES256] +] + class PKCS7Options(utils.Enum): Text = "Add text/plain MIME type" @@ -48,7 +56,7 @@ class PKCS7Options(utils.Enum): class PKCS7SignatureBuilder: def __init__( self, - data: bytes | None = None, + data: utils.Buffer | None = None, signers: list[ tuple[ x509.Certificate, @@ -63,7 +71,7 @@ class PKCS7SignatureBuilder: self._signers = signers self._additional_certs = additional_certs - def set_data(self, data: bytes) -> PKCS7SignatureBuilder: + def set_data(self, data: utils.Buffer) -> PKCS7SignatureBuilder: _check_byteslike("data", data) if self._data is not None: raise ValueError("data may only be set once") @@ -126,7 +134,7 @@ class PKCS7SignatureBuilder: def sign( self, encoding: serialization.Encoding, - options: typing.Iterable[PKCS7Options], + options: Iterable[PKCS7Options], backend: typing.Any = None, ) -> bytes: if len(self._signers) == 0: @@ -184,6 +192,8 @@ class PKCS7EnvelopeBuilder: *, _data: bytes | None = None, _recipients: list[x509.Certificate] | None = None, + _content_encryption_algorithm: ContentEncryptionAlgorithm + | None = None, ): from cryptography.hazmat.backends.openssl.backend import ( backend as ossl, @@ -197,13 +207,18 @@ class PKCS7EnvelopeBuilder: ) self._data = _data self._recipients = _recipients if _recipients is not None else [] + self._content_encryption_algorithm = _content_encryption_algorithm def set_data(self, data: bytes) -> PKCS7EnvelopeBuilder: _check_byteslike("data", data) if self._data is not None: raise ValueError("data may only be set once") - return PKCS7EnvelopeBuilder(_data=data, _recipients=self._recipients) + return PKCS7EnvelopeBuilder( + _data=data, + _recipients=self._recipients, + _content_encryption_algorithm=self._content_encryption_algorithm, + ) def add_recipient( self, @@ -221,17 +236,42 @@ class PKCS7EnvelopeBuilder: *self._recipients, certificate, ], + _content_encryption_algorithm=self._content_encryption_algorithm, + ) + + def set_content_encryption_algorithm( + self, content_encryption_algorithm: ContentEncryptionAlgorithm + ) -> PKCS7EnvelopeBuilder: + if self._content_encryption_algorithm is not None: + raise ValueError("Content encryption algo may only be set once") + if content_encryption_algorithm not in { + algorithms.AES128, + algorithms.AES256, + }: + raise TypeError("Only AES128 and AES256 are supported") + + return PKCS7EnvelopeBuilder( + _data=self._data, + _recipients=self._recipients, + _content_encryption_algorithm=content_encryption_algorithm, ) def encrypt( self, encoding: serialization.Encoding, - options: typing.Iterable[PKCS7Options], + options: Iterable[PKCS7Options], ) -> bytes: if len(self._recipients) == 0: raise ValueError("Must have at least one recipient") if self._data is None: raise ValueError("You must add data to encrypt") + + # The default content encryption algorithm is AES-128, which the S/MIME + # v3.2 RFC specifies as MUST support (https://datatracker.ietf.org/doc/html/rfc5751#section-2.7) + content_encryption_algorithm = ( + self._content_encryption_algorithm or algorithms.AES128 + ) + options = list(options) if not all(isinstance(x, PKCS7Options) for x in options): raise ValueError("options must be from the PKCS7Options enum") @@ -260,7 +300,9 @@ class PKCS7EnvelopeBuilder: "Cannot use Binary and Text options at the same time" ) - return rust_pkcs7.encrypt_and_serialize(self, encoding, options) + return rust_pkcs7.encrypt_and_serialize( + self, content_encryption_algorithm, encoding, options + ) pkcs7_decrypt_der = rust_pkcs7.decrypt_der diff --git a/venv/Lib/site-packages/cryptography/hazmat/primitives/serialization/ssh.py b/venv/Lib/site-packages/cryptography/hazmat/primitives/serialization/ssh.py index c01afb0..cb10cf8 100644 --- a/venv/Lib/site-packages/cryptography/hazmat/primitives/serialization/ssh.py +++ b/venv/Lib/site-packages/cryptography/hazmat/primitives/serialization/ssh.py @@ -169,20 +169,20 @@ def _ecdsa_key_type(public_key: ec.EllipticCurvePublicKey) -> bytes: def _ssh_pem_encode( - data: bytes, + data: utils.Buffer, prefix: bytes = _SK_START + b"\n", suffix: bytes = _SK_END + b"\n", ) -> bytes: return b"".join([prefix, _base64_encode(data), suffix]) -def _check_block_size(data: bytes, block_len: int) -> None: +def _check_block_size(data: utils.Buffer, block_len: int) -> None: """Require data to be full blocks""" if not data or len(data) % block_len != 0: raise ValueError("Corrupt data: missing padding") -def _check_empty(data: bytes) -> None: +def _check_empty(data: utils.Buffer) -> None: """All data should have been parsed.""" if data: raise ValueError("Corrupt data: unparsed data") @@ -196,7 +196,9 @@ def _init_cipher( ) -> Cipher[modes.CBC | modes.CTR | modes.GCM]: """Generate key + iv and return cipher.""" if not password: - raise ValueError("Key is password-protected.") + raise TypeError( + "Key is password-protected, but password was not provided." + ) ciph = _SSH_CIPHERS[ciphername] seed = _bcrypt_kdf( @@ -251,14 +253,14 @@ def _to_mpint(val: int) -> bytes: class _FragList: """Build recursive structure without data copy.""" - flist: list[bytes] + flist: list[utils.Buffer] - def __init__(self, init: list[bytes] | None = None) -> None: + def __init__(self, init: list[utils.Buffer] | None = None) -> None: self.flist = [] if init: self.flist.extend(init) - def put_raw(self, val: bytes) -> None: + def put_raw(self, val: utils.Buffer) -> None: """Add plain bytes""" self.flist.append(val) @@ -329,7 +331,7 @@ class _SSHFormatRSA: return public_key, data def load_private( - self, data: memoryview, pubfields + self, data: memoryview, pubfields, unsafe_skip_rsa_key_validation: bool ) -> tuple[rsa.RSAPrivateKey, memoryview]: """Make RSA private key from data.""" n, data = _get_mpint(data) @@ -347,7 +349,9 @@ class _SSHFormatRSA: private_numbers = rsa.RSAPrivateNumbers( p, q, d, dmp1, dmq1, iqmp, public_numbers ) - private_key = private_numbers.private_key() + private_key = private_numbers.private_key( + unsafe_skip_rsa_key_validation=unsafe_skip_rsa_key_validation + ) return private_key, data def encode_public( @@ -403,7 +407,7 @@ class _SSHFormatDSA: return public_key, data def load_private( - self, data: memoryview, pubfields + self, data: memoryview, pubfields, unsafe_skip_rsa_key_validation: bool ) -> tuple[dsa.DSAPrivateKey, memoryview]: """Make DSA private key from data.""" (p, q, g, y), data = self.get_public(data) @@ -483,7 +487,7 @@ class _SSHFormatECDSA: return public_key, data def load_private( - self, data: memoryview, pubfields + self, data: memoryview, pubfields, unsafe_skip_rsa_key_validation: bool ) -> tuple[ec.EllipticCurvePrivateKey, memoryview]: """Make ECDSA private key from data.""" (curve_name, point), data = self.get_public(data) @@ -543,7 +547,7 @@ class _SSHFormatEd25519: return public_key, data def load_private( - self, data: memoryview, pubfields + self, data: memoryview, pubfields, unsafe_skip_rsa_key_validation: bool ) -> tuple[ed25519.Ed25519PrivateKey, memoryview]: """Make Ed25519 private key from data.""" (point,), data = self.get_public(data) @@ -612,6 +616,13 @@ class _SSHFormatSKEd25519: _, data = load_application(data) return public_key, data + def get_public(self, data: memoryview) -> typing.NoReturn: + # Confusingly `get_public` is an entry point used by private key + # loading. + raise UnsupportedAlgorithm( + "sk-ssh-ed25519 private keys cannot be loaded" + ) + class _SSHFormatSKECDSA: """ @@ -631,6 +642,13 @@ class _SSHFormatSKECDSA: _, data = load_application(data) return public_key, data + def get_public(self, data: memoryview) -> typing.NoReturn: + # Confusingly `get_public` is an entry point used by private key + # loading. + raise UnsupportedAlgorithm( + "sk-ecdsa-sha2-nistp256 private keys cannot be loaded" + ) + _KEY_FORMATS = { _SSH_RSA: _SSHFormatRSA(), @@ -644,7 +662,7 @@ _KEY_FORMATS = { } -def _lookup_kformat(key_type: bytes): +def _lookup_kformat(key_type: utils.Buffer): """Return valid format or throw error""" if not isinstance(key_type, bytes): key_type = memoryview(key_type).tobytes() @@ -662,9 +680,11 @@ SSHPrivateKeyTypes = typing.Union[ def load_ssh_private_key( - data: bytes, + data: utils.Buffer, password: bytes | None, backend: typing.Any = None, + *, + unsafe_skip_rsa_key_validation: bool = False, ) -> SSHPrivateKeyTypes: """Load private key from OpenSSH custom encoding.""" utils._check_byteslike("data", data) @@ -696,7 +716,7 @@ def load_ssh_private_key( pubfields, pubdata = kformat.get_public(pubdata) _check_empty(pubdata) - if (ciphername, kdfname) != (_NONE, _NONE): + if ciphername != _NONE or kdfname != _NONE: ciphername_bytes = ciphername.tobytes() if ciphername_bytes not in _SSH_CIPHERS: raise UnsupportedAlgorithm( @@ -731,6 +751,10 @@ def load_ssh_private_key( # should be no output from finalize _check_empty(dec.finalize()) else: + if password: + raise TypeError( + "Password was given but private key is not encrypted." + ) # load secret data edata, data = _get_sshstr(data) _check_empty(data) @@ -745,7 +769,11 @@ def load_ssh_private_key( key_type, edata = _get_sshstr(edata) if key_type != pub_key_type: raise ValueError("Corrupt data: key type mismatch") - private_key, edata = kformat.load_private(edata, pubfields) + private_key, edata = kformat.load_private( + edata, + pubfields, + unsafe_skip_rsa_key_validation=unsafe_skip_rsa_key_validation, + ) # We don't use the comment _, edata = _get_sshstr(edata) @@ -1001,7 +1029,7 @@ def _get_ec_hash_alg(curve: ec.EllipticCurve) -> hashes.HashAlgorithm: def _load_ssh_public_identity( - data: bytes, + data: utils.Buffer, _legacy_dsa_allowed=False, ) -> SSHCertificate | SSHPublicKeyTypes: utils._check_byteslike("data", data) @@ -1096,7 +1124,7 @@ def _load_ssh_public_identity( def load_ssh_public_identity( - data: bytes, + data: utils.Buffer, ) -> SSHCertificate | SSHPublicKeyTypes: return _load_ssh_public_identity(data) @@ -1121,8 +1149,30 @@ def _parse_exts_opts(exts_opts: memoryview) -> dict[bytes, bytes]: return result +def ssh_key_fingerprint( + key: SSHPublicKeyTypes, + hash_algorithm: hashes.MD5 | hashes.SHA256, +) -> bytes: + if not isinstance(hash_algorithm, (hashes.MD5, hashes.SHA256)): + raise TypeError("hash_algorithm must be either MD5 or SHA256") + + key_type = _get_ssh_key_type(key) + kformat = _lookup_kformat(key_type) + + f_pub = _FragList() + f_pub.put_sshstr(key_type) + kformat.encode_public(key, f_pub) + + ssh_binary_data = f_pub.tobytes() + + # Hash the binary data + hash_obj = hashes.Hash(hash_algorithm) + hash_obj.update(ssh_binary_data) + return hash_obj.finalize() + + def load_ssh_public_key( - data: bytes, backend: typing.Any = None + data: utils.Buffer, backend: typing.Any = None ) -> SSHPublicKeyTypes: cert_or_key = _load_ssh_public_identity(data, _legacy_dsa_allowed=True) public_key: SSHPublicKeyTypes diff --git a/venv/Lib/site-packages/cryptography/hazmat/primitives/twofactor/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/cryptography/hazmat/primitives/twofactor/__pycache__/__init__.cpython-312.pyc index 44742a4..1e4d05d 100644 Binary files a/venv/Lib/site-packages/cryptography/hazmat/primitives/twofactor/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/cryptography/hazmat/primitives/twofactor/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/cryptography/hazmat/primitives/twofactor/__pycache__/hotp.cpython-312.pyc b/venv/Lib/site-packages/cryptography/hazmat/primitives/twofactor/__pycache__/hotp.cpython-312.pyc index cf2926f..cd700b7 100644 Binary files a/venv/Lib/site-packages/cryptography/hazmat/primitives/twofactor/__pycache__/hotp.cpython-312.pyc and b/venv/Lib/site-packages/cryptography/hazmat/primitives/twofactor/__pycache__/hotp.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/cryptography/hazmat/primitives/twofactor/__pycache__/totp.cpython-312.pyc b/venv/Lib/site-packages/cryptography/hazmat/primitives/twofactor/__pycache__/totp.cpython-312.pyc index a1f0a0c..df51313 100644 Binary files a/venv/Lib/site-packages/cryptography/hazmat/primitives/twofactor/__pycache__/totp.cpython-312.pyc and b/venv/Lib/site-packages/cryptography/hazmat/primitives/twofactor/__pycache__/totp.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/cryptography/hazmat/primitives/twofactor/hotp.py b/venv/Lib/site-packages/cryptography/hazmat/primitives/twofactor/hotp.py index 855a5d2..21fb000 100644 --- a/venv/Lib/site-packages/cryptography/hazmat/primitives/twofactor/hotp.py +++ b/venv/Lib/site-packages/cryptography/hazmat/primitives/twofactor/hotp.py @@ -11,6 +11,7 @@ from urllib.parse import quote, urlencode from cryptography.hazmat.primitives import constant_time, hmac from cryptography.hazmat.primitives.hashes import SHA1, SHA256, SHA512 from cryptography.hazmat.primitives.twofactor import InvalidToken +from cryptography.utils import Buffer HOTPHashTypes = typing.Union[SHA1, SHA256, SHA512] @@ -44,7 +45,7 @@ def _generate_uri( class HOTP: def __init__( self, - key: bytes, + key: Buffer, length: int, algorithm: HOTPHashTypes, backend: typing.Any = None, @@ -84,7 +85,7 @@ class HOTP: try: ctx.update(counter.to_bytes(length=8, byteorder="big")) except OverflowError: - raise ValueError(f"Counter must be between 0 and {2 ** 64 - 1}.") + raise ValueError(f"Counter must be between 0 and {2**64 - 1}.") hmac_value = ctx.finalize() diff --git a/venv/Lib/site-packages/cryptography/hazmat/primitives/twofactor/totp.py b/venv/Lib/site-packages/cryptography/hazmat/primitives/twofactor/totp.py index b9ed734..10c725c 100644 --- a/venv/Lib/site-packages/cryptography/hazmat/primitives/twofactor/totp.py +++ b/venv/Lib/site-packages/cryptography/hazmat/primitives/twofactor/totp.py @@ -13,12 +13,13 @@ from cryptography.hazmat.primitives.twofactor.hotp import ( HOTPHashTypes, _generate_uri, ) +from cryptography.utils import Buffer class TOTP: def __init__( self, - key: bytes, + key: Buffer, length: int, algorithm: HOTPHashTypes, time_step: int, diff --git a/venv/Lib/site-packages/cryptography/utils.py b/venv/Lib/site-packages/cryptography/utils.py index 706d0ae..a0fc3b1 100644 --- a/venv/Lib/site-packages/cryptography/utils.py +++ b/venv/Lib/site-packages/cryptography/utils.py @@ -9,6 +9,7 @@ import sys import types import typing import warnings +from collections.abc import Callable, Sequence # We use a UserWarning subclass, instead of DeprecationWarning, because CPython @@ -21,19 +22,28 @@ class CryptographyDeprecationWarning(UserWarning): # ubiquity of their use. They should not be removed until we agree on when that # cycle ends. DeprecatedIn36 = CryptographyDeprecationWarning -DeprecatedIn37 = CryptographyDeprecationWarning DeprecatedIn40 = CryptographyDeprecationWarning DeprecatedIn41 = CryptographyDeprecationWarning DeprecatedIn42 = CryptographyDeprecationWarning DeprecatedIn43 = CryptographyDeprecationWarning +# If you're wondering why we don't use `Buffer`, it's because `Buffer` would +# be more accurately named: Bufferable. It means something which has an +# `__buffer__`. Which means you can't actually treat the result as a buffer +# (and do things like take a `len()`). +if sys.version_info >= (3, 9): + Buffer = typing.Union[bytes, bytearray, memoryview] +else: + Buffer = typing.ByteString + + def _check_bytes(name: str, value: bytes) -> None: if not isinstance(value, bytes): raise TypeError(f"{name} must be bytes") -def _check_byteslike(name: str, value: bytes) -> None: +def _check_byteslike(name: str, value: Buffer) -> None: try: memoryview(value) except TypeError: @@ -81,7 +91,7 @@ class _ModuleWithDeprecations(types.ModuleType): delattr(self._module, attr) - def __dir__(self) -> typing.Sequence[str]: + def __dir__(self) -> Sequence[str]: return ["_module", *dir(self._module)] @@ -102,7 +112,7 @@ def deprecated( return dv -def cached_property(func: typing.Callable) -> property: +def cached_property(func: Callable) -> property: cached_name = f"_cached_{func}" sentinel = object() diff --git a/venv/Lib/site-packages/cryptography/x509/__init__.py b/venv/Lib/site-packages/cryptography/x509/__init__.py index 8a89d67..318eecc 100644 --- a/venv/Lib/site-packages/cryptography/x509/__init__.py +++ b/venv/Lib/site-packages/cryptography/x509/__init__.py @@ -66,6 +66,7 @@ from cryptography.x509.extensions import ( PolicyInformation, PrecertificateSignedCertificateTimestamps, PrecertPoison, + PrivateKeyUsagePeriod, ProfessionInfo, ReasonFlags, SignedCertificateTimestamps, @@ -115,6 +116,7 @@ OID_FRESHEST_CRL = ExtensionOID.FRESHEST_CRL OID_INHIBIT_ANY_POLICY = ExtensionOID.INHIBIT_ANY_POLICY OID_ISSUER_ALTERNATIVE_NAME = ExtensionOID.ISSUER_ALTERNATIVE_NAME OID_KEY_USAGE = ExtensionOID.KEY_USAGE +OID_PRIVATE_KEY_USAGE_PERIOD = ExtensionOID.PRIVATE_KEY_USAGE_PERIOD OID_NAME_CONSTRAINTS = ExtensionOID.NAME_CONSTRAINTS OID_OCSP_NO_CHECK = ExtensionOID.OCSP_NO_CHECK OID_POLICY_CONSTRAINTS = ExtensionOID.POLICY_CONSTRAINTS @@ -233,6 +235,7 @@ __all__ = [ "PolicyInformation", "PrecertPoison", "PrecertificateSignedCertificateTimestamps", + "PrivateKeyUsagePeriod", "ProfessionInfo", "PublicKeyAlgorithmOID", "RFC822Name", diff --git a/venv/Lib/site-packages/cryptography/x509/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/cryptography/x509/__pycache__/__init__.cpython-312.pyc index 8e90db4..0e62c8c 100644 Binary files a/venv/Lib/site-packages/cryptography/x509/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/cryptography/x509/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/cryptography/x509/__pycache__/base.cpython-312.pyc b/venv/Lib/site-packages/cryptography/x509/__pycache__/base.cpython-312.pyc index e80df77..94e76dd 100644 Binary files a/venv/Lib/site-packages/cryptography/x509/__pycache__/base.cpython-312.pyc and b/venv/Lib/site-packages/cryptography/x509/__pycache__/base.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/cryptography/x509/__pycache__/certificate_transparency.cpython-312.pyc b/venv/Lib/site-packages/cryptography/x509/__pycache__/certificate_transparency.cpython-312.pyc index 26526ce..af02323 100644 Binary files a/venv/Lib/site-packages/cryptography/x509/__pycache__/certificate_transparency.cpython-312.pyc and b/venv/Lib/site-packages/cryptography/x509/__pycache__/certificate_transparency.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/cryptography/x509/__pycache__/extensions.cpython-312.pyc b/venv/Lib/site-packages/cryptography/x509/__pycache__/extensions.cpython-312.pyc index 9e88daa..e83dc15 100644 Binary files a/venv/Lib/site-packages/cryptography/x509/__pycache__/extensions.cpython-312.pyc and b/venv/Lib/site-packages/cryptography/x509/__pycache__/extensions.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/cryptography/x509/__pycache__/general_name.cpython-312.pyc b/venv/Lib/site-packages/cryptography/x509/__pycache__/general_name.cpython-312.pyc index 5456d02..4d43ed7 100644 Binary files a/venv/Lib/site-packages/cryptography/x509/__pycache__/general_name.cpython-312.pyc and b/venv/Lib/site-packages/cryptography/x509/__pycache__/general_name.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/cryptography/x509/__pycache__/name.cpython-312.pyc b/venv/Lib/site-packages/cryptography/x509/__pycache__/name.cpython-312.pyc index e93e05d..045820e 100644 Binary files a/venv/Lib/site-packages/cryptography/x509/__pycache__/name.cpython-312.pyc and b/venv/Lib/site-packages/cryptography/x509/__pycache__/name.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/cryptography/x509/__pycache__/ocsp.cpython-312.pyc b/venv/Lib/site-packages/cryptography/x509/__pycache__/ocsp.cpython-312.pyc index 722c24e..a22dc13 100644 Binary files a/venv/Lib/site-packages/cryptography/x509/__pycache__/ocsp.cpython-312.pyc and b/venv/Lib/site-packages/cryptography/x509/__pycache__/ocsp.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/cryptography/x509/__pycache__/oid.cpython-312.pyc b/venv/Lib/site-packages/cryptography/x509/__pycache__/oid.cpython-312.pyc index 0b362e9..f2a3281 100644 Binary files a/venv/Lib/site-packages/cryptography/x509/__pycache__/oid.cpython-312.pyc and b/venv/Lib/site-packages/cryptography/x509/__pycache__/oid.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/cryptography/x509/__pycache__/verification.cpython-312.pyc b/venv/Lib/site-packages/cryptography/x509/__pycache__/verification.cpython-312.pyc index b294e6e..3d7ec71 100644 Binary files a/venv/Lib/site-packages/cryptography/x509/__pycache__/verification.cpython-312.pyc and b/venv/Lib/site-packages/cryptography/x509/__pycache__/verification.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/cryptography/x509/base.py b/venv/Lib/site-packages/cryptography/x509/base.py index 25b317a..1be612b 100644 --- a/venv/Lib/site-packages/cryptography/x509/base.py +++ b/venv/Lib/site-packages/cryptography/x509/base.py @@ -9,6 +9,7 @@ import datetime import os import typing import warnings +from collections.abc import Iterable from cryptography import utils from cryptography.hazmat.bindings._rust import x509 as rust_x509 @@ -131,7 +132,7 @@ class Attribute: class Attributes: def __init__( self, - attributes: typing.Iterable[Attribute], + attributes: Iterable[Attribute], ) -> None: self._attributes = list(attributes) @@ -330,6 +331,7 @@ class CertificateSigningRequestBuilder: backend: typing.Any = None, *, rsa_padding: padding.PSS | padding.PKCS1v15 | None = None, + ecdsa_deterministic: bool | None = None, ) -> CertificateSigningRequest: """ Signs the request using the requestor's private key. @@ -343,8 +345,18 @@ class CertificateSigningRequestBuilder: if not isinstance(private_key, rsa.RSAPrivateKey): raise TypeError("Padding is only supported for RSA keys") + if ecdsa_deterministic is not None: + if not isinstance(private_key, ec.EllipticCurvePrivateKey): + raise TypeError( + "Deterministic ECDSA is only supported for EC keys" + ) + return rust_x509.create_x509_csr( - self, private_key, algorithm, rsa_padding + self, + private_key, + algorithm, + rsa_padding, + ecdsa_deterministic, ) @@ -510,8 +522,7 @@ class CertificateBuilder: time = _convert_to_naive_utc_time(time) if time < _EARLIEST_UTC_TIME: raise ValueError( - "The not valid after date must be on or after" - " 1950 January 1." + "The not valid after date must be on or after 1950 January 1." ) if ( self._not_valid_before is not None @@ -560,6 +571,7 @@ class CertificateBuilder: backend: typing.Any = None, *, rsa_padding: padding.PSS | padding.PKCS1v15 | None = None, + ecdsa_deterministic: bool | None = None, ) -> Certificate: """ Signs the certificate using the CA's private key. @@ -588,8 +600,18 @@ class CertificateBuilder: if not isinstance(private_key, rsa.RSAPrivateKey): raise TypeError("Padding is only supported for RSA keys") + if ecdsa_deterministic is not None: + if not isinstance(private_key, ec.EllipticCurvePrivateKey): + raise TypeError( + "Deterministic ECDSA is only supported for EC keys" + ) + return rust_x509.create_x509_certificate( - self, private_key, algorithm, rsa_padding + self, + private_key, + algorithm, + rsa_padding, + ecdsa_deterministic, ) @@ -717,6 +739,7 @@ class CertificateRevocationListBuilder: backend: typing.Any = None, *, rsa_padding: padding.PSS | padding.PKCS1v15 | None = None, + ecdsa_deterministic: bool | None = None, ) -> CertificateRevocationList: if self._issuer_name is None: raise ValueError("A CRL must have an issuer name") @@ -733,8 +756,18 @@ class CertificateRevocationListBuilder: if not isinstance(private_key, rsa.RSAPrivateKey): raise TypeError("Padding is only supported for RSA keys") + if ecdsa_deterministic is not None: + if not isinstance(private_key, ec.EllipticCurvePrivateKey): + raise TypeError( + "Deterministic ECDSA is only supported for EC keys" + ) + return rust_x509.create_x509_crl( - self, private_key, algorithm, rsa_padding + self, + private_key, + algorithm, + rsa_padding, + ecdsa_deterministic, ) diff --git a/venv/Lib/site-packages/cryptography/x509/extensions.py b/venv/Lib/site-packages/cryptography/x509/extensions.py index fc3e773..dfa472d 100644 --- a/venv/Lib/site-packages/cryptography/x509/extensions.py +++ b/venv/Lib/site-packages/cryptography/x509/extensions.py @@ -9,6 +9,7 @@ import datetime import hashlib import ipaddress import typing +from collections.abc import Iterable, Iterator from cryptography import utils from cryptography.hazmat.bindings._rust import asn1 @@ -109,9 +110,7 @@ class ExtensionType(metaclass=abc.ABCMeta): class Extensions: - def __init__( - self, extensions: typing.Iterable[Extension[ExtensionType]] - ) -> None: + def __init__(self, extensions: Iterable[Extension[ExtensionType]]) -> None: self._extensions = list(extensions) def get_extension_for_oid( @@ -182,7 +181,7 @@ class AuthorityKeyIdentifier(ExtensionType): def __init__( self, key_identifier: bytes | None, - authority_cert_issuer: typing.Iterable[GeneralName] | None, + authority_cert_issuer: Iterable[GeneralName] | None, authority_cert_serial_number: int | None, ) -> None: if (authority_cert_issuer is None) != ( @@ -323,9 +322,7 @@ class SubjectKeyIdentifier(ExtensionType): class AuthorityInformationAccess(ExtensionType): oid = ExtensionOID.AUTHORITY_INFORMATION_ACCESS - def __init__( - self, descriptions: typing.Iterable[AccessDescription] - ) -> None: + def __init__(self, descriptions: Iterable[AccessDescription]) -> None: descriptions = list(descriptions) if not all(isinstance(x, AccessDescription) for x in descriptions): raise TypeError( @@ -356,9 +353,7 @@ class AuthorityInformationAccess(ExtensionType): class SubjectInformationAccess(ExtensionType): oid = ExtensionOID.SUBJECT_INFORMATION_ACCESS - def __init__( - self, descriptions: typing.Iterable[AccessDescription] - ) -> None: + def __init__(self, descriptions: Iterable[AccessDescription]) -> None: descriptions = list(descriptions) if not all(isinstance(x, AccessDescription) for x in descriptions): raise TypeError( @@ -456,8 +451,7 @@ class BasicConstraints(ExtensionType): def __repr__(self) -> str: return ( - f"" + f"" ) def __eq__(self, other: object) -> bool: @@ -506,7 +500,7 @@ class CRLDistributionPoints(ExtensionType): oid = ExtensionOID.CRL_DISTRIBUTION_POINTS def __init__( - self, distribution_points: typing.Iterable[DistributionPoint] + self, distribution_points: Iterable[DistributionPoint] ) -> None: distribution_points = list(distribution_points) if not all( @@ -543,7 +537,7 @@ class FreshestCRL(ExtensionType): oid = ExtensionOID.FRESHEST_CRL def __init__( - self, distribution_points: typing.Iterable[DistributionPoint] + self, distribution_points: Iterable[DistributionPoint] ) -> None: distribution_points = list(distribution_points) if not all( @@ -579,10 +573,10 @@ class FreshestCRL(ExtensionType): class DistributionPoint: def __init__( self, - full_name: typing.Iterable[GeneralName] | None, + full_name: Iterable[GeneralName] | None, relative_name: RelativeDistinguishedName | None, reasons: frozenset[ReasonFlags] | None, - crl_issuer: typing.Iterable[GeneralName] | None, + crl_issuer: Iterable[GeneralName] | None, ) -> None: if full_name and relative_name: raise ValueError( @@ -824,12 +818,11 @@ class PolicyConstraints(ExtensionType): class CertificatePolicies(ExtensionType): oid = ExtensionOID.CERTIFICATE_POLICIES - def __init__(self, policies: typing.Iterable[PolicyInformation]) -> None: + def __init__(self, policies: Iterable[PolicyInformation]) -> None: policies = list(policies) if not all(isinstance(x, PolicyInformation) for x in policies): raise TypeError( - "Every item in the policies list must be a " - "PolicyInformation" + "Every item in the policies list must be a PolicyInformation" ) self._policies = policies @@ -856,7 +849,7 @@ class PolicyInformation: def __init__( self, policy_identifier: ObjectIdentifier, - policy_qualifiers: typing.Iterable[str | UserNotice] | None, + policy_qualifiers: Iterable[str | UserNotice] | None, ) -> None: if not isinstance(policy_identifier, ObjectIdentifier): raise TypeError("policy_identifier must be an ObjectIdentifier") @@ -956,7 +949,7 @@ class NoticeReference: def __init__( self, organization: str | None, - notice_numbers: typing.Iterable[int], + notice_numbers: Iterable[int], ) -> None: self._organization = organization notice_numbers = list(notice_numbers) @@ -995,7 +988,7 @@ class NoticeReference: class ExtendedKeyUsage(ExtensionType): oid = ExtensionOID.EXTENDED_KEY_USAGE - def __init__(self, usages: typing.Iterable[ObjectIdentifier]) -> None: + def __init__(self, usages: Iterable[ObjectIdentifier]) -> None: usages = list(usages) if not all(isinstance(x, ObjectIdentifier) for x in usages): raise TypeError( @@ -1063,7 +1056,7 @@ class PrecertPoison(ExtensionType): class TLSFeature(ExtensionType): oid = ExtensionOID.TLS_FEATURE - def __init__(self, features: typing.Iterable[TLSFeatureType]) -> None: + def __init__(self, features: Iterable[TLSFeatureType]) -> None: features = list(features) if ( not all(isinstance(x, TLSFeatureType) for x in features) @@ -1273,13 +1266,78 @@ class KeyUsage(ExtensionType): return rust_x509.encode_extension_value(self) +class PrivateKeyUsagePeriod(ExtensionType): + oid = ExtensionOID.PRIVATE_KEY_USAGE_PERIOD + + def __init__( + self, + not_before: datetime.datetime | None, + not_after: datetime.datetime | None, + ) -> None: + if ( + not isinstance(not_before, datetime.datetime) + and not_before is not None + ): + raise TypeError("not_before must be a datetime.datetime or None") + + if ( + not isinstance(not_after, datetime.datetime) + and not_after is not None + ): + raise TypeError("not_after must be a datetime.datetime or None") + + if not_before is None and not_after is None: + raise ValueError( + "At least one of not_before and not_after must not be None" + ) + + if ( + not_before is not None + and not_after is not None + and not_before > not_after + ): + raise ValueError("not_before must be before not_after") + + self._not_before = not_before + self._not_after = not_after + + @property + def not_before(self) -> datetime.datetime | None: + return self._not_before + + @property + def not_after(self) -> datetime.datetime | None: + return self._not_after + + def __repr__(self) -> str: + return ( + f"" + ) + + def __eq__(self, other: object) -> bool: + if not isinstance(other, PrivateKeyUsagePeriod): + return NotImplemented + + return ( + self.not_before == other.not_before + and self.not_after == other.not_after + ) + + def __hash__(self) -> int: + return hash((self.not_before, self.not_after)) + + def public_bytes(self) -> bytes: + return rust_x509.encode_extension_value(self) + + class NameConstraints(ExtensionType): oid = ExtensionOID.NAME_CONSTRAINTS def __init__( self, - permitted_subtrees: typing.Iterable[GeneralName] | None, - excluded_subtrees: typing.Iterable[GeneralName] | None, + permitted_subtrees: Iterable[GeneralName] | None, + excluded_subtrees: Iterable[GeneralName] | None, ) -> None: if permitted_subtrees is not None: permitted_subtrees = list(permitted_subtrees) @@ -1327,11 +1385,11 @@ class NameConstraints(ExtensionType): and self.permitted_subtrees == other.permitted_subtrees ) - def _validate_tree(self, tree: typing.Iterable[GeneralName]) -> None: + def _validate_tree(self, tree: Iterable[GeneralName]) -> None: self._validate_ip_name(tree) self._validate_dns_name(tree) - def _validate_ip_name(self, tree: typing.Iterable[GeneralName]) -> None: + def _validate_ip_name(self, tree: Iterable[GeneralName]) -> None: if any( isinstance(name, IPAddress) and not isinstance( @@ -1344,7 +1402,7 @@ class NameConstraints(ExtensionType): " IPv6Network object" ) - def _validate_dns_name(self, tree: typing.Iterable[GeneralName]) -> None: + def _validate_dns_name(self, tree: Iterable[GeneralName]) -> None: if any( isinstance(name, DNSName) and "*" in name.value for name in tree ): @@ -1437,7 +1495,7 @@ class Extension(typing.Generic[ExtensionTypeVar]): class GeneralNames: - def __init__(self, general_names: typing.Iterable[GeneralName]) -> None: + def __init__(self, general_names: Iterable[GeneralName]) -> None: general_names = list(general_names) if not all(isinstance(x, GeneralName) for x in general_names): raise TypeError( @@ -1519,7 +1577,7 @@ class GeneralNames: class SubjectAlternativeName(ExtensionType): oid = ExtensionOID.SUBJECT_ALTERNATIVE_NAME - def __init__(self, general_names: typing.Iterable[GeneralName]) -> None: + def __init__(self, general_names: Iterable[GeneralName]) -> None: self._general_names = GeneralNames(general_names) __len__, __iter__, __getitem__ = _make_sequence_methods("_general_names") @@ -1591,7 +1649,7 @@ class SubjectAlternativeName(ExtensionType): class IssuerAlternativeName(ExtensionType): oid = ExtensionOID.ISSUER_ALTERNATIVE_NAME - def __init__(self, general_names: typing.Iterable[GeneralName]) -> None: + def __init__(self, general_names: Iterable[GeneralName]) -> None: self._general_names = GeneralNames(general_names) __len__, __iter__, __getitem__ = _make_sequence_methods("_general_names") @@ -1663,7 +1721,7 @@ class IssuerAlternativeName(ExtensionType): class CertificateIssuer(ExtensionType): oid = CRLEntryExtensionOID.CERTIFICATE_ISSUER - def __init__(self, general_names: typing.Iterable[GeneralName]) -> None: + def __init__(self, general_names: Iterable[GeneralName]) -> None: self._general_names = GeneralNames(general_names) __len__, __iter__, __getitem__ = _make_sequence_methods("_general_names") @@ -1802,9 +1860,7 @@ class PrecertificateSignedCertificateTimestamps(ExtensionType): def __init__( self, - signed_certificate_timestamps: typing.Iterable[ - SignedCertificateTimestamp - ], + signed_certificate_timestamps: Iterable[SignedCertificateTimestamp], ) -> None: signed_certificate_timestamps = list(signed_certificate_timestamps) if not all( @@ -1845,9 +1901,7 @@ class SignedCertificateTimestamps(ExtensionType): def __init__( self, - signed_certificate_timestamps: typing.Iterable[ - SignedCertificateTimestamp - ], + signed_certificate_timestamps: Iterable[SignedCertificateTimestamp], ) -> None: signed_certificate_timestamps = list(signed_certificate_timestamps) if not all( @@ -1915,7 +1969,7 @@ class OCSPNonce(ExtensionType): class OCSPAcceptableResponses(ExtensionType): oid = OCSPExtensionOID.ACCEPTABLE_RESPONSES - def __init__(self, responses: typing.Iterable[ObjectIdentifier]) -> None: + def __init__(self, responses: Iterable[ObjectIdentifier]) -> None: responses = list(responses) if any(not isinstance(r, ObjectIdentifier) for r in responses): raise TypeError("All responses must be ObjectIdentifiers") @@ -1934,7 +1988,7 @@ class OCSPAcceptableResponses(ExtensionType): def __repr__(self) -> str: return f"" - def __iter__(self) -> typing.Iterator[ObjectIdentifier]: + def __iter__(self) -> Iterator[ObjectIdentifier]: return iter(self._responses) def public_bytes(self) -> bytes: @@ -1946,7 +2000,7 @@ class IssuingDistributionPoint(ExtensionType): def __init__( self, - full_name: typing.Iterable[GeneralName] | None, + full_name: Iterable[GeneralName] | None, relative_name: RelativeDistinguishedName | None, only_contains_user_certs: bool, only_contains_ca_certs: bool, @@ -2224,8 +2278,8 @@ class ProfessionInfo: def __init__( self, naming_authority: NamingAuthority | None, - profession_items: typing.Iterable[str], - profession_oids: typing.Iterable[ObjectIdentifier] | None, + profession_items: Iterable[str], + profession_oids: Iterable[ObjectIdentifier] | None, registration_number: str | None, add_profession_info: bytes | None, ) -> None: @@ -2328,7 +2382,7 @@ class Admission: self, admission_authority: GeneralName | None, naming_authority: NamingAuthority | None, - profession_infos: typing.Iterable[ProfessionInfo], + profession_infos: Iterable[ProfessionInfo], ) -> None: if admission_authority is not None and not isinstance( admission_authority, GeneralName @@ -2398,7 +2452,7 @@ class Admissions(ExtensionType): def __init__( self, authority: GeneralName | None, - admissions: typing.Iterable[Admission], + admissions: Iterable[Admission], ) -> None: if authority is not None and not isinstance(authority, GeneralName): raise TypeError("authority must be a GeneralName") @@ -2459,10 +2513,7 @@ class UnrecognizedExtension(ExtensionType): return self._value def __repr__(self) -> str: - return ( - f"" - ) + return f"" def __eq__(self, other: object) -> bool: if not isinstance(other, UnrecognizedExtension): diff --git a/venv/Lib/site-packages/cryptography/x509/name.py b/venv/Lib/site-packages/cryptography/x509/name.py index 1b6b89d..685f921 100644 --- a/venv/Lib/site-packages/cryptography/x509/name.py +++ b/venv/Lib/site-packages/cryptography/x509/name.py @@ -9,6 +9,7 @@ import re import sys import typing import warnings +from collections.abc import Iterable, Iterator from cryptography import utils from cryptography.hazmat.bindings._rust import x509 as rust_x509 @@ -114,11 +115,20 @@ def _unescape_dn_value(val: str) -> str: return _RFC4514NameParser._PAIR_RE.sub(sub, val) -class NameAttribute: +NameAttributeValueType = typing.TypeVar( + "NameAttributeValueType", + typing.Union[str, bytes], + str, + bytes, + covariant=True, +) + + +class NameAttribute(typing.Generic[NameAttributeValueType]): def __init__( self, oid: ObjectIdentifier, - value: str | bytes, + value: NameAttributeValueType, _type: _ASN1Type | None = None, *, _validate: bool = True, @@ -134,9 +144,8 @@ class NameAttribute: ) if not isinstance(value, bytes): raise TypeError("value must be bytes for BitString") - else: - if not isinstance(value, str): - raise TypeError("value argument must be a str") + elif not isinstance(value, str): + raise TypeError("value argument must be a str") length_limits = _NAMEOID_LENGTH_LIMIT.get(oid) if length_limits is not None: @@ -166,15 +175,15 @@ class NameAttribute: raise TypeError("_type must be from the _ASN1Type enum") self._oid = oid - self._value = value - self._type = _type + self._value: NameAttributeValueType = value + self._type: _ASN1Type = _type @property def oid(self) -> ObjectIdentifier: return self._oid @property - def value(self) -> str | bytes: + def value(self) -> NameAttributeValueType: return self._value @property @@ -216,7 +225,7 @@ class NameAttribute: class RelativeDistinguishedName: - def __init__(self, attributes: typing.Iterable[NameAttribute]): + def __init__(self, attributes: Iterable[NameAttribute]): attributes = list(attributes) if not attributes: raise ValueError("a relative distinguished name cannot be empty") @@ -231,8 +240,9 @@ class RelativeDistinguishedName: raise ValueError("duplicate attributes are not allowed") def get_attributes_for_oid( - self, oid: ObjectIdentifier - ) -> list[NameAttribute]: + self, + oid: ObjectIdentifier, + ) -> list[NameAttribute[str | bytes]]: return [i for i in self if i.oid == oid] def rfc4514_string( @@ -258,7 +268,7 @@ class RelativeDistinguishedName: def __hash__(self) -> int: return hash(self._attribute_set) - def __iter__(self) -> typing.Iterator[NameAttribute]: + def __iter__(self) -> Iterator[NameAttribute]: return iter(self._attributes) def __len__(self) -> int: @@ -270,16 +280,16 @@ class RelativeDistinguishedName: class Name: @typing.overload - def __init__(self, attributes: typing.Iterable[NameAttribute]) -> None: ... + def __init__(self, attributes: Iterable[NameAttribute]) -> None: ... @typing.overload def __init__( - self, attributes: typing.Iterable[RelativeDistinguishedName] + self, attributes: Iterable[RelativeDistinguishedName] ) -> None: ... def __init__( self, - attributes: typing.Iterable[NameAttribute | RelativeDistinguishedName], + attributes: Iterable[NameAttribute | RelativeDistinguishedName], ) -> None: attributes = list(attributes) if all(isinstance(x, NameAttribute) for x in attributes): @@ -324,8 +334,9 @@ class Name: ) def get_attributes_for_oid( - self, oid: ObjectIdentifier - ) -> list[NameAttribute]: + self, + oid: ObjectIdentifier, + ) -> list[NameAttribute[str | bytes]]: return [i for i in self if i.oid == oid] @property @@ -346,7 +357,7 @@ class Name: # for you, consider optimizing! return hash(tuple(self._attributes)) - def __iter__(self) -> typing.Iterator[NameAttribute]: + def __iter__(self) -> Iterator[NameAttribute]: for rdn in self._attributes: yield from rdn diff --git a/venv/Lib/site-packages/cryptography/x509/ocsp.py b/venv/Lib/site-packages/cryptography/x509/ocsp.py index 5a011c4..f61ed80 100644 --- a/venv/Lib/site-packages/cryptography/x509/ocsp.py +++ b/venv/Lib/site-packages/cryptography/x509/ocsp.py @@ -5,7 +5,7 @@ from __future__ import annotations import datetime -import typing +from collections.abc import Iterable from cryptography import utils, x509 from cryptography.hazmat.bindings._rust import ocsp @@ -13,11 +13,7 @@ from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives.asymmetric.types import ( CertificateIssuerPrivateKeyTypes, ) -from cryptography.x509.base import ( - _EARLIEST_UTC_TIME, - _convert_to_naive_utc_time, - _reject_duplicate_extension, -) +from cryptography.x509.base import _reject_duplicate_extension class OCSPResponderEncoding(utils.Enum): @@ -59,8 +55,8 @@ class OCSPCertStatus(utils.Enum): class _SingleResponse: def __init__( self, - cert: x509.Certificate, - issuer: x509.Certificate, + resp: tuple[x509.Certificate, x509.Certificate] | None, + resp_hash: tuple[bytes, bytes, int] | None, algorithm: hashes.HashAlgorithm, cert_status: OCSPCertStatus, this_update: datetime.datetime, @@ -68,11 +64,6 @@ class _SingleResponse: revocation_time: datetime.datetime | None, revocation_reason: x509.ReasonFlags | None, ): - if not isinstance(cert, x509.Certificate) or not isinstance( - issuer, x509.Certificate - ): - raise TypeError("cert and issuer must be a Certificate") - _verify_algorithm(algorithm) if not isinstance(this_update, datetime.datetime): raise TypeError("this_update must be a datetime object") @@ -81,8 +72,8 @@ class _SingleResponse: ): raise TypeError("next_update must be a datetime object or None") - self._cert = cert - self._issuer = issuer + self._resp = resp + self._resp_hash = resp_hash self._algorithm = algorithm self._this_update = this_update self._next_update = next_update @@ -106,13 +97,6 @@ class _SingleResponse: if not isinstance(revocation_time, datetime.datetime): raise TypeError("revocation_time must be a datetime object") - revocation_time = _convert_to_naive_utc_time(revocation_time) - if revocation_time < _EARLIEST_UTC_TIME: - raise ValueError( - "The revocation_time must be on or after" - " 1950 January 1." - ) - if revocation_reason is not None and not isinstance( revocation_reason, x509.ReasonFlags ): @@ -243,9 +227,60 @@ class OCSPResponseBuilder: if self._response is not None: raise ValueError("Only one response per OCSPResponse.") + if not isinstance(cert, x509.Certificate) or not isinstance( + issuer, x509.Certificate + ): + raise TypeError("cert and issuer must be a Certificate") + singleresp = _SingleResponse( - cert, - issuer, + (cert, issuer), + None, + algorithm, + cert_status, + this_update, + next_update, + revocation_time, + revocation_reason, + ) + return OCSPResponseBuilder( + singleresp, + self._responder_id, + self._certs, + self._extensions, + ) + + def add_response_by_hash( + self, + issuer_name_hash: bytes, + issuer_key_hash: bytes, + serial_number: int, + algorithm: hashes.HashAlgorithm, + cert_status: OCSPCertStatus, + this_update: datetime.datetime, + next_update: datetime.datetime | None, + revocation_time: datetime.datetime | None, + revocation_reason: x509.ReasonFlags | None, + ) -> OCSPResponseBuilder: + if self._response is not None: + raise ValueError("Only one response per OCSPResponse.") + + if not isinstance(serial_number, int): + raise TypeError("serial_number must be an integer") + + utils._check_bytes("issuer_name_hash", issuer_name_hash) + utils._check_bytes("issuer_key_hash", issuer_key_hash) + _verify_algorithm(algorithm) + if algorithm.digest_size != len( + issuer_name_hash + ) or algorithm.digest_size != len(issuer_key_hash): + raise ValueError( + "issuer_name_hash and issuer_key_hash must be the same length " + "as the digest size of the algorithm" + ) + + singleresp = _SingleResponse( + None, + (issuer_name_hash, issuer_key_hash, serial_number), algorithm, cert_status, this_update, @@ -280,7 +315,7 @@ class OCSPResponseBuilder: ) def certificates( - self, certs: typing.Iterable[x509.Certificate] + self, certs: Iterable[x509.Certificate] ) -> OCSPResponseBuilder: if self._certs is not None: raise ValueError("certificates may only be set once") diff --git a/venv/Lib/site-packages/cryptography/x509/oid.py b/venv/Lib/site-packages/cryptography/x509/oid.py index d4e409e..520fc7a 100644 --- a/venv/Lib/site-packages/cryptography/x509/oid.py +++ b/venv/Lib/site-packages/cryptography/x509/oid.py @@ -14,6 +14,7 @@ from cryptography.hazmat._oid import ( NameOID, ObjectIdentifier, OCSPExtensionOID, + OtherNameFormOID, PublicKeyAlgorithmOID, SignatureAlgorithmOID, SubjectInformationAccessOID, @@ -29,6 +30,7 @@ __all__ = [ "NameOID", "OCSPExtensionOID", "ObjectIdentifier", + "OtherNameFormOID", "PublicKeyAlgorithmOID", "SignatureAlgorithmOID", "SubjectInformationAccessOID", diff --git a/venv/Lib/site-packages/cryptography/x509/verification.py b/venv/Lib/site-packages/cryptography/x509/verification.py index b836506..2db4324 100644 --- a/venv/Lib/site-packages/cryptography/x509/verification.py +++ b/venv/Lib/site-packages/cryptography/x509/verification.py @@ -11,6 +11,9 @@ from cryptography.x509.general_name import DNSName, IPAddress __all__ = [ "ClientVerifier", + "Criticality", + "ExtensionPolicy", + "Policy", "PolicyBuilder", "ServerVerifier", "Store", @@ -25,4 +28,7 @@ VerifiedClient = rust_x509.VerifiedClient ClientVerifier = rust_x509.ClientVerifier ServerVerifier = rust_x509.ServerVerifier PolicyBuilder = rust_x509.PolicyBuilder +Policy = rust_x509.Policy +ExtensionPolicy = rust_x509.ExtensionPolicy +Criticality = rust_x509.Criticality VerificationError = rust_x509.VerificationError diff --git a/venv/Lib/site-packages/darabonba/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/darabonba/__pycache__/__init__.cpython-312.pyc index 610ee10..6741a45 100644 Binary files a/venv/Lib/site-packages/darabonba/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/darabonba/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/darabonba/__pycache__/core.cpython-312.pyc b/venv/Lib/site-packages/darabonba/__pycache__/core.cpython-312.pyc index 7222902..41067f0 100644 Binary files a/venv/Lib/site-packages/darabonba/__pycache__/core.cpython-312.pyc and b/venv/Lib/site-packages/darabonba/__pycache__/core.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/darabonba/__pycache__/date.cpython-312.pyc b/venv/Lib/site-packages/darabonba/__pycache__/date.cpython-312.pyc index e43a79f..4f5bd0b 100644 Binary files a/venv/Lib/site-packages/darabonba/__pycache__/date.cpython-312.pyc and b/venv/Lib/site-packages/darabonba/__pycache__/date.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/darabonba/__pycache__/decorators.cpython-312.pyc b/venv/Lib/site-packages/darabonba/__pycache__/decorators.cpython-312.pyc index 81ad399..0b2570e 100644 Binary files a/venv/Lib/site-packages/darabonba/__pycache__/decorators.cpython-312.pyc and b/venv/Lib/site-packages/darabonba/__pycache__/decorators.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/darabonba/__pycache__/event.cpython-312.pyc b/venv/Lib/site-packages/darabonba/__pycache__/event.cpython-312.pyc index 45e965c..3eece2a 100644 Binary files a/venv/Lib/site-packages/darabonba/__pycache__/event.cpython-312.pyc and b/venv/Lib/site-packages/darabonba/__pycache__/event.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/darabonba/__pycache__/exceptions.cpython-312.pyc b/venv/Lib/site-packages/darabonba/__pycache__/exceptions.cpython-312.pyc index 465bdba..81ca003 100644 Binary files a/venv/Lib/site-packages/darabonba/__pycache__/exceptions.cpython-312.pyc and b/venv/Lib/site-packages/darabonba/__pycache__/exceptions.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/darabonba/__pycache__/file.cpython-312.pyc b/venv/Lib/site-packages/darabonba/__pycache__/file.cpython-312.pyc index ecee470..8711c1e 100644 Binary files a/venv/Lib/site-packages/darabonba/__pycache__/file.cpython-312.pyc and b/venv/Lib/site-packages/darabonba/__pycache__/file.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/darabonba/__pycache__/model.cpython-312.pyc b/venv/Lib/site-packages/darabonba/__pycache__/model.cpython-312.pyc index 26c6b5c..fc6d5c5 100644 Binary files a/venv/Lib/site-packages/darabonba/__pycache__/model.cpython-312.pyc and b/venv/Lib/site-packages/darabonba/__pycache__/model.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/darabonba/__pycache__/number.cpython-312.pyc b/venv/Lib/site-packages/darabonba/__pycache__/number.cpython-312.pyc index 34454d9..5e7ea3c 100644 Binary files a/venv/Lib/site-packages/darabonba/__pycache__/number.cpython-312.pyc and b/venv/Lib/site-packages/darabonba/__pycache__/number.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/darabonba/__pycache__/request.cpython-312.pyc b/venv/Lib/site-packages/darabonba/__pycache__/request.cpython-312.pyc index 65292fd..eb6b6e2 100644 Binary files a/venv/Lib/site-packages/darabonba/__pycache__/request.cpython-312.pyc and b/venv/Lib/site-packages/darabonba/__pycache__/request.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/darabonba/__pycache__/response.cpython-312.pyc b/venv/Lib/site-packages/darabonba/__pycache__/response.cpython-312.pyc index 6ccdf35..07ff61a 100644 Binary files a/venv/Lib/site-packages/darabonba/__pycache__/response.cpython-312.pyc and b/venv/Lib/site-packages/darabonba/__pycache__/response.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/darabonba/__pycache__/runtime.cpython-312.pyc b/venv/Lib/site-packages/darabonba/__pycache__/runtime.cpython-312.pyc index ecd14ef..0fdd475 100644 Binary files a/venv/Lib/site-packages/darabonba/__pycache__/runtime.cpython-312.pyc and b/venv/Lib/site-packages/darabonba/__pycache__/runtime.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/darabonba/__pycache__/url.cpython-312.pyc b/venv/Lib/site-packages/darabonba/__pycache__/url.cpython-312.pyc index de241e8..9c1fc43 100644 Binary files a/venv/Lib/site-packages/darabonba/__pycache__/url.cpython-312.pyc and b/venv/Lib/site-packages/darabonba/__pycache__/url.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/darabonba/policy/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/darabonba/policy/__pycache__/__init__.cpython-312.pyc index e7c73f1..7d90cc6 100644 Binary files a/venv/Lib/site-packages/darabonba/policy/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/darabonba/policy/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/darabonba/policy/__pycache__/retry.cpython-312.pyc b/venv/Lib/site-packages/darabonba/policy/__pycache__/retry.cpython-312.pyc index 7890da7..8a397a1 100644 Binary files a/venv/Lib/site-packages/darabonba/policy/__pycache__/retry.cpython-312.pyc and b/venv/Lib/site-packages/darabonba/policy/__pycache__/retry.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/darabonba/utils/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/darabonba/utils/__pycache__/__init__.cpython-312.pyc index e861627..37ca02f 100644 Binary files a/venv/Lib/site-packages/darabonba/utils/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/darabonba/utils/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/darabonba/utils/__pycache__/bytes.cpython-312.pyc b/venv/Lib/site-packages/darabonba/utils/__pycache__/bytes.cpython-312.pyc index efaebd4..9fca355 100644 Binary files a/venv/Lib/site-packages/darabonba/utils/__pycache__/bytes.cpython-312.pyc and b/venv/Lib/site-packages/darabonba/utils/__pycache__/bytes.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/darabonba/utils/__pycache__/form.cpython-312.pyc b/venv/Lib/site-packages/darabonba/utils/__pycache__/form.cpython-312.pyc index 570544a..dcc0290 100644 Binary files a/venv/Lib/site-packages/darabonba/utils/__pycache__/form.cpython-312.pyc and b/venv/Lib/site-packages/darabonba/utils/__pycache__/form.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/darabonba/utils/__pycache__/logger.cpython-312.pyc b/venv/Lib/site-packages/darabonba/utils/__pycache__/logger.cpython-312.pyc index 4b4a6b5..ff950ce 100644 Binary files a/venv/Lib/site-packages/darabonba/utils/__pycache__/logger.cpython-312.pyc and b/venv/Lib/site-packages/darabonba/utils/__pycache__/logger.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/darabonba/utils/__pycache__/map.cpython-312.pyc b/venv/Lib/site-packages/darabonba/utils/__pycache__/map.cpython-312.pyc index a0123d7..cb17864 100644 Binary files a/venv/Lib/site-packages/darabonba/utils/__pycache__/map.cpython-312.pyc and b/venv/Lib/site-packages/darabonba/utils/__pycache__/map.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/darabonba/utils/__pycache__/stream.cpython-312.pyc b/venv/Lib/site-packages/darabonba/utils/__pycache__/stream.cpython-312.pyc index 1de8cea..9835e07 100644 Binary files a/venv/Lib/site-packages/darabonba/utils/__pycache__/stream.cpython-312.pyc and b/venv/Lib/site-packages/darabonba/utils/__pycache__/stream.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/darabonba/utils/__pycache__/validation.cpython-312.pyc b/venv/Lib/site-packages/darabonba/utils/__pycache__/validation.cpython-312.pyc index ff628e0..020c21a 100644 Binary files a/venv/Lib/site-packages/darabonba/utils/__pycache__/validation.cpython-312.pyc and b/venv/Lib/site-packages/darabonba/utils/__pycache__/validation.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/darabonba/utils/__pycache__/xml.cpython-312.pyc b/venv/Lib/site-packages/darabonba/utils/__pycache__/xml.cpython-312.pyc index 9d056b7..aa4950b 100644 Binary files a/venv/Lib/site-packages/darabonba/utils/__pycache__/xml.cpython-312.pyc and b/venv/Lib/site-packages/darabonba/utils/__pycache__/xml.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/darabonba_core-1.0.5.dist-info/RECORD b/venv/Lib/site-packages/darabonba_core-1.0.5.dist-info/RECORD index 3cedad4..32aa197 100644 --- a/venv/Lib/site-packages/darabonba_core-1.0.5.dist-info/RECORD +++ b/venv/Lib/site-packages/darabonba_core-1.0.5.dist-info/RECORD @@ -47,5 +47,6 @@ darabonba/utils/xml.py,sha256=C52bYFKyI8Z9f8AvwX4Z6oReQSQdi0TthO7IrRsQMFE,2981 darabonba_core-1.0.5.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 darabonba_core-1.0.5.dist-info/METADATA,sha256=5mGgaKCGJrsKZmSfIxIhkjK95cBgJdZdMgQLhR79hck,2582 darabonba_core-1.0.5.dist-info/RECORD,, +darabonba_core-1.0.5.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 darabonba_core-1.0.5.dist-info/WHEEL,sha256=2wepM1nk4DS4eFpYrW1TTqPcoGNfHhhO_i5m4cOimbo,92 darabonba_core-1.0.5.dist-info/top_level.txt,sha256=-8IXmruGn3drNiPfZzTCkCtMzX6bGr10RkqwTLsRMzY,10 diff --git a/venv/Lib/site-packages/darabonba_core-1.0.5.dist-info/REQUESTED b/venv/Lib/site-packages/darabonba_core-1.0.5.dist-info/REQUESTED new file mode 100644 index 0000000..e69de29 diff --git a/venv/Lib/site-packages/dateutil/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/dateutil/__pycache__/__init__.cpython-312.pyc index 443acfe..becffbd 100644 Binary files a/venv/Lib/site-packages/dateutil/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/dateutil/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/dateutil/__pycache__/_common.cpython-312.pyc b/venv/Lib/site-packages/dateutil/__pycache__/_common.cpython-312.pyc index 34d22a6..925290f 100644 Binary files a/venv/Lib/site-packages/dateutil/__pycache__/_common.cpython-312.pyc and b/venv/Lib/site-packages/dateutil/__pycache__/_common.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/dateutil/__pycache__/_version.cpython-312.pyc b/venv/Lib/site-packages/dateutil/__pycache__/_version.cpython-312.pyc index bf5975b..b549c13 100644 Binary files a/venv/Lib/site-packages/dateutil/__pycache__/_version.cpython-312.pyc and b/venv/Lib/site-packages/dateutil/__pycache__/_version.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/dateutil/__pycache__/easter.cpython-312.pyc b/venv/Lib/site-packages/dateutil/__pycache__/easter.cpython-312.pyc index 72c22a5..1dbace7 100644 Binary files a/venv/Lib/site-packages/dateutil/__pycache__/easter.cpython-312.pyc and b/venv/Lib/site-packages/dateutil/__pycache__/easter.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/dateutil/__pycache__/relativedelta.cpython-312.pyc b/venv/Lib/site-packages/dateutil/__pycache__/relativedelta.cpython-312.pyc index a0df8a0..674db30 100644 Binary files a/venv/Lib/site-packages/dateutil/__pycache__/relativedelta.cpython-312.pyc and b/venv/Lib/site-packages/dateutil/__pycache__/relativedelta.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/dateutil/__pycache__/rrule.cpython-312.pyc b/venv/Lib/site-packages/dateutil/__pycache__/rrule.cpython-312.pyc index 7efeee2..e1a3054 100644 Binary files a/venv/Lib/site-packages/dateutil/__pycache__/rrule.cpython-312.pyc and b/venv/Lib/site-packages/dateutil/__pycache__/rrule.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/dateutil/__pycache__/tzwin.cpython-312.pyc b/venv/Lib/site-packages/dateutil/__pycache__/tzwin.cpython-312.pyc index 0a60a4a..97e2204 100644 Binary files a/venv/Lib/site-packages/dateutil/__pycache__/tzwin.cpython-312.pyc and b/venv/Lib/site-packages/dateutil/__pycache__/tzwin.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/dateutil/__pycache__/utils.cpython-312.pyc b/venv/Lib/site-packages/dateutil/__pycache__/utils.cpython-312.pyc index 1946db7..3721d09 100644 Binary files a/venv/Lib/site-packages/dateutil/__pycache__/utils.cpython-312.pyc and b/venv/Lib/site-packages/dateutil/__pycache__/utils.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/dateutil/parser/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/dateutil/parser/__pycache__/__init__.cpython-312.pyc index 5971120..f1cf0df 100644 Binary files a/venv/Lib/site-packages/dateutil/parser/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/dateutil/parser/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/dateutil/parser/__pycache__/_parser.cpython-312.pyc b/venv/Lib/site-packages/dateutil/parser/__pycache__/_parser.cpython-312.pyc index db30d27..da8b9a8 100644 Binary files a/venv/Lib/site-packages/dateutil/parser/__pycache__/_parser.cpython-312.pyc and b/venv/Lib/site-packages/dateutil/parser/__pycache__/_parser.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/dateutil/parser/__pycache__/isoparser.cpython-312.pyc b/venv/Lib/site-packages/dateutil/parser/__pycache__/isoparser.cpython-312.pyc index 33b0e5e..b08df8e 100644 Binary files a/venv/Lib/site-packages/dateutil/parser/__pycache__/isoparser.cpython-312.pyc and b/venv/Lib/site-packages/dateutil/parser/__pycache__/isoparser.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/dateutil/tz/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/dateutil/tz/__pycache__/__init__.cpython-312.pyc index 6a2e1c5..a80bb07 100644 Binary files a/venv/Lib/site-packages/dateutil/tz/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/dateutil/tz/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/dateutil/tz/__pycache__/_common.cpython-312.pyc b/venv/Lib/site-packages/dateutil/tz/__pycache__/_common.cpython-312.pyc index 4412be3..b15484f 100644 Binary files a/venv/Lib/site-packages/dateutil/tz/__pycache__/_common.cpython-312.pyc and b/venv/Lib/site-packages/dateutil/tz/__pycache__/_common.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/dateutil/tz/__pycache__/_factories.cpython-312.pyc b/venv/Lib/site-packages/dateutil/tz/__pycache__/_factories.cpython-312.pyc index 2be1185..2305d08 100644 Binary files a/venv/Lib/site-packages/dateutil/tz/__pycache__/_factories.cpython-312.pyc and b/venv/Lib/site-packages/dateutil/tz/__pycache__/_factories.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/dateutil/tz/__pycache__/tz.cpython-312.pyc b/venv/Lib/site-packages/dateutil/tz/__pycache__/tz.cpython-312.pyc index 51314fa..54bfdf3 100644 Binary files a/venv/Lib/site-packages/dateutil/tz/__pycache__/tz.cpython-312.pyc and b/venv/Lib/site-packages/dateutil/tz/__pycache__/tz.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/dateutil/tz/__pycache__/win.cpython-312.pyc b/venv/Lib/site-packages/dateutil/tz/__pycache__/win.cpython-312.pyc index f4423ab..1ec6e9b 100644 Binary files a/venv/Lib/site-packages/dateutil/tz/__pycache__/win.cpython-312.pyc and b/venv/Lib/site-packages/dateutil/tz/__pycache__/win.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/dateutil/zoneinfo/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/dateutil/zoneinfo/__pycache__/__init__.cpython-312.pyc index 3354134..063d31a 100644 Binary files a/venv/Lib/site-packages/dateutil/zoneinfo/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/dateutil/zoneinfo/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/dateutil/zoneinfo/__pycache__/rebuild.cpython-312.pyc b/venv/Lib/site-packages/dateutil/zoneinfo/__pycache__/rebuild.cpython-312.pyc index 46c4ab9..e147063 100644 Binary files a/venv/Lib/site-packages/dateutil/zoneinfo/__pycache__/rebuild.cpython-312.pyc and b/venv/Lib/site-packages/dateutil/zoneinfo/__pycache__/rebuild.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/flask-3.1.2.dist-info/RECORD b/venv/Lib/site-packages/flask-3.1.2.dist-info/RECORD index b171831..44a89bf 100644 --- a/venv/Lib/site-packages/flask-3.1.2.dist-info/RECORD +++ b/venv/Lib/site-packages/flask-3.1.2.dist-info/RECORD @@ -1,4 +1,4 @@ -../../Scripts/flask.exe,sha256=uQq0sCuAjmaFT1pWUQ2VtxHk1TZ42QBwRyGjEI5IGqQ,108379 +../../Scripts/flask.exe,sha256=bl6ElShgvgn105GNrL8RWXvilQzkYpRu6NIp-lFVmbg,108377 flask-3.1.2.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 flask-3.1.2.dist-info/METADATA,sha256=oRg63DAAIcoLAr7kzTgIEKfm8_4HMTRpmWmIptdY_js,3167 flask-3.1.2.dist-info/RECORD,, diff --git a/venv/Lib/site-packages/flask/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/flask/__pycache__/__init__.cpython-312.pyc index 52c8c56..eba0b43 100644 Binary files a/venv/Lib/site-packages/flask/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/flask/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/flask/__pycache__/__main__.cpython-312.pyc b/venv/Lib/site-packages/flask/__pycache__/__main__.cpython-312.pyc index 3476a2f..de64eea 100644 Binary files a/venv/Lib/site-packages/flask/__pycache__/__main__.cpython-312.pyc and b/venv/Lib/site-packages/flask/__pycache__/__main__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/flask/__pycache__/app.cpython-312.pyc b/venv/Lib/site-packages/flask/__pycache__/app.cpython-312.pyc index 934ab97..a5cdbf5 100644 Binary files a/venv/Lib/site-packages/flask/__pycache__/app.cpython-312.pyc and b/venv/Lib/site-packages/flask/__pycache__/app.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/flask/__pycache__/blueprints.cpython-312.pyc b/venv/Lib/site-packages/flask/__pycache__/blueprints.cpython-312.pyc index 7606f1e..be16b67 100644 Binary files a/venv/Lib/site-packages/flask/__pycache__/blueprints.cpython-312.pyc and b/venv/Lib/site-packages/flask/__pycache__/blueprints.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/flask/__pycache__/cli.cpython-312.pyc b/venv/Lib/site-packages/flask/__pycache__/cli.cpython-312.pyc index 3b64b9e..9db2b91 100644 Binary files a/venv/Lib/site-packages/flask/__pycache__/cli.cpython-312.pyc and b/venv/Lib/site-packages/flask/__pycache__/cli.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/flask/__pycache__/config.cpython-312.pyc b/venv/Lib/site-packages/flask/__pycache__/config.cpython-312.pyc index 52817f8..81d7f52 100644 Binary files a/venv/Lib/site-packages/flask/__pycache__/config.cpython-312.pyc and b/venv/Lib/site-packages/flask/__pycache__/config.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/flask/__pycache__/ctx.cpython-312.pyc b/venv/Lib/site-packages/flask/__pycache__/ctx.cpython-312.pyc index 635d80c..e898b71 100644 Binary files a/venv/Lib/site-packages/flask/__pycache__/ctx.cpython-312.pyc and b/venv/Lib/site-packages/flask/__pycache__/ctx.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/flask/__pycache__/debughelpers.cpython-312.pyc b/venv/Lib/site-packages/flask/__pycache__/debughelpers.cpython-312.pyc index c341b16..8eda525 100644 Binary files a/venv/Lib/site-packages/flask/__pycache__/debughelpers.cpython-312.pyc and b/venv/Lib/site-packages/flask/__pycache__/debughelpers.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/flask/__pycache__/globals.cpython-312.pyc b/venv/Lib/site-packages/flask/__pycache__/globals.cpython-312.pyc index 0156916..6e5efdc 100644 Binary files a/venv/Lib/site-packages/flask/__pycache__/globals.cpython-312.pyc and b/venv/Lib/site-packages/flask/__pycache__/globals.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/flask/__pycache__/helpers.cpython-312.pyc b/venv/Lib/site-packages/flask/__pycache__/helpers.cpython-312.pyc index 024c513..8176897 100644 Binary files a/venv/Lib/site-packages/flask/__pycache__/helpers.cpython-312.pyc and b/venv/Lib/site-packages/flask/__pycache__/helpers.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/flask/__pycache__/logging.cpython-312.pyc b/venv/Lib/site-packages/flask/__pycache__/logging.cpython-312.pyc index 94352d5..2a4fa6e 100644 Binary files a/venv/Lib/site-packages/flask/__pycache__/logging.cpython-312.pyc and b/venv/Lib/site-packages/flask/__pycache__/logging.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/flask/__pycache__/sessions.cpython-312.pyc b/venv/Lib/site-packages/flask/__pycache__/sessions.cpython-312.pyc index 982abf5..339afbc 100644 Binary files a/venv/Lib/site-packages/flask/__pycache__/sessions.cpython-312.pyc and b/venv/Lib/site-packages/flask/__pycache__/sessions.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/flask/__pycache__/signals.cpython-312.pyc b/venv/Lib/site-packages/flask/__pycache__/signals.cpython-312.pyc index 45af002..83c5373 100644 Binary files a/venv/Lib/site-packages/flask/__pycache__/signals.cpython-312.pyc and b/venv/Lib/site-packages/flask/__pycache__/signals.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/flask/__pycache__/templating.cpython-312.pyc b/venv/Lib/site-packages/flask/__pycache__/templating.cpython-312.pyc index eb9a60a..92cf938 100644 Binary files a/venv/Lib/site-packages/flask/__pycache__/templating.cpython-312.pyc and b/venv/Lib/site-packages/flask/__pycache__/templating.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/flask/__pycache__/testing.cpython-312.pyc b/venv/Lib/site-packages/flask/__pycache__/testing.cpython-312.pyc index 6affe3c..01e3f1a 100644 Binary files a/venv/Lib/site-packages/flask/__pycache__/testing.cpython-312.pyc and b/venv/Lib/site-packages/flask/__pycache__/testing.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/flask/__pycache__/typing.cpython-312.pyc b/venv/Lib/site-packages/flask/__pycache__/typing.cpython-312.pyc index 5da5fa4..86db35c 100644 Binary files a/venv/Lib/site-packages/flask/__pycache__/typing.cpython-312.pyc and b/venv/Lib/site-packages/flask/__pycache__/typing.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/flask/__pycache__/views.cpython-312.pyc b/venv/Lib/site-packages/flask/__pycache__/views.cpython-312.pyc index 5bfea82..b082f93 100644 Binary files a/venv/Lib/site-packages/flask/__pycache__/views.cpython-312.pyc and b/venv/Lib/site-packages/flask/__pycache__/views.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/flask/__pycache__/wrappers.cpython-312.pyc b/venv/Lib/site-packages/flask/__pycache__/wrappers.cpython-312.pyc index a113e62..6a94156 100644 Binary files a/venv/Lib/site-packages/flask/__pycache__/wrappers.cpython-312.pyc and b/venv/Lib/site-packages/flask/__pycache__/wrappers.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/flask/json/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/flask/json/__pycache__/__init__.cpython-312.pyc index 86cd47f..f6d654d 100644 Binary files a/venv/Lib/site-packages/flask/json/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/flask/json/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/flask/json/__pycache__/provider.cpython-312.pyc b/venv/Lib/site-packages/flask/json/__pycache__/provider.cpython-312.pyc index 11e1469..3aabc4e 100644 Binary files a/venv/Lib/site-packages/flask/json/__pycache__/provider.cpython-312.pyc and b/venv/Lib/site-packages/flask/json/__pycache__/provider.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/flask/json/__pycache__/tag.cpython-312.pyc b/venv/Lib/site-packages/flask/json/__pycache__/tag.cpython-312.pyc index e33fff5..b027af0 100644 Binary files a/venv/Lib/site-packages/flask/json/__pycache__/tag.cpython-312.pyc and b/venv/Lib/site-packages/flask/json/__pycache__/tag.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/flask/sansio/__pycache__/app.cpython-312.pyc b/venv/Lib/site-packages/flask/sansio/__pycache__/app.cpython-312.pyc index 1053087..dfe6571 100644 Binary files a/venv/Lib/site-packages/flask/sansio/__pycache__/app.cpython-312.pyc and b/venv/Lib/site-packages/flask/sansio/__pycache__/app.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/flask/sansio/__pycache__/blueprints.cpython-312.pyc b/venv/Lib/site-packages/flask/sansio/__pycache__/blueprints.cpython-312.pyc index 9ac255e..2763161 100644 Binary files a/venv/Lib/site-packages/flask/sansio/__pycache__/blueprints.cpython-312.pyc and b/venv/Lib/site-packages/flask/sansio/__pycache__/blueprints.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/flask/sansio/__pycache__/scaffold.cpython-312.pyc b/venv/Lib/site-packages/flask/sansio/__pycache__/scaffold.cpython-312.pyc index dfe6a9b..c478ec5 100644 Binary files a/venv/Lib/site-packages/flask/sansio/__pycache__/scaffold.cpython-312.pyc and b/venv/Lib/site-packages/flask/sansio/__pycache__/scaffold.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/flask_redis/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/flask_redis/__pycache__/__init__.cpython-312.pyc index 2dda5d6..4b4a805 100644 Binary files a/venv/Lib/site-packages/flask_redis/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/flask_redis/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/flask_redis/__pycache__/client.cpython-312.pyc b/venv/Lib/site-packages/flask_redis/__pycache__/client.cpython-312.pyc index 7197702..ca8e933 100644 Binary files a/venv/Lib/site-packages/flask_redis/__pycache__/client.cpython-312.pyc and b/venv/Lib/site-packages/flask_redis/__pycache__/client.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/flask_sqlalchemy/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/flask_sqlalchemy/__pycache__/__init__.cpython-312.pyc index 9858298..5e3f543 100644 Binary files a/venv/Lib/site-packages/flask_sqlalchemy/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/flask_sqlalchemy/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/flask_sqlalchemy/__pycache__/cli.cpython-312.pyc b/venv/Lib/site-packages/flask_sqlalchemy/__pycache__/cli.cpython-312.pyc index 6c495e8..796dd70 100644 Binary files a/venv/Lib/site-packages/flask_sqlalchemy/__pycache__/cli.cpython-312.pyc and b/venv/Lib/site-packages/flask_sqlalchemy/__pycache__/cli.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/flask_sqlalchemy/__pycache__/extension.cpython-312.pyc b/venv/Lib/site-packages/flask_sqlalchemy/__pycache__/extension.cpython-312.pyc index 729954b..62084f7 100644 Binary files a/venv/Lib/site-packages/flask_sqlalchemy/__pycache__/extension.cpython-312.pyc and b/venv/Lib/site-packages/flask_sqlalchemy/__pycache__/extension.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/flask_sqlalchemy/__pycache__/model.cpython-312.pyc b/venv/Lib/site-packages/flask_sqlalchemy/__pycache__/model.cpython-312.pyc index b5182b9..8321403 100644 Binary files a/venv/Lib/site-packages/flask_sqlalchemy/__pycache__/model.cpython-312.pyc and b/venv/Lib/site-packages/flask_sqlalchemy/__pycache__/model.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/flask_sqlalchemy/__pycache__/pagination.cpython-312.pyc b/venv/Lib/site-packages/flask_sqlalchemy/__pycache__/pagination.cpython-312.pyc index c3e62d0..cfdcb87 100644 Binary files a/venv/Lib/site-packages/flask_sqlalchemy/__pycache__/pagination.cpython-312.pyc and b/venv/Lib/site-packages/flask_sqlalchemy/__pycache__/pagination.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/flask_sqlalchemy/__pycache__/query.cpython-312.pyc b/venv/Lib/site-packages/flask_sqlalchemy/__pycache__/query.cpython-312.pyc index aa24473..73a79ee 100644 Binary files a/venv/Lib/site-packages/flask_sqlalchemy/__pycache__/query.cpython-312.pyc and b/venv/Lib/site-packages/flask_sqlalchemy/__pycache__/query.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/flask_sqlalchemy/__pycache__/record_queries.cpython-312.pyc b/venv/Lib/site-packages/flask_sqlalchemy/__pycache__/record_queries.cpython-312.pyc index d22086e..ed89bfe 100644 Binary files a/venv/Lib/site-packages/flask_sqlalchemy/__pycache__/record_queries.cpython-312.pyc and b/venv/Lib/site-packages/flask_sqlalchemy/__pycache__/record_queries.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/flask_sqlalchemy/__pycache__/session.cpython-312.pyc b/venv/Lib/site-packages/flask_sqlalchemy/__pycache__/session.cpython-312.pyc index cfd6e4c..586345e 100644 Binary files a/venv/Lib/site-packages/flask_sqlalchemy/__pycache__/session.cpython-312.pyc and b/venv/Lib/site-packages/flask_sqlalchemy/__pycache__/session.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/flask_sqlalchemy/__pycache__/table.cpython-312.pyc b/venv/Lib/site-packages/flask_sqlalchemy/__pycache__/table.cpython-312.pyc index 794ce08..1582efa 100644 Binary files a/venv/Lib/site-packages/flask_sqlalchemy/__pycache__/table.cpython-312.pyc and b/venv/Lib/site-packages/flask_sqlalchemy/__pycache__/table.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/flask_sqlalchemy/__pycache__/track_modifications.cpython-312.pyc b/venv/Lib/site-packages/flask_sqlalchemy/__pycache__/track_modifications.cpython-312.pyc index e62fd63..6d63fae 100644 Binary files a/venv/Lib/site-packages/flask_sqlalchemy/__pycache__/track_modifications.cpython-312.pyc and b/venv/Lib/site-packages/flask_sqlalchemy/__pycache__/track_modifications.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/frozenlist-1.8.0.dist-info/RECORD b/venv/Lib/site-packages/frozenlist-1.8.0.dist-info/RECORD index 8db1e82..86e098c 100644 --- a/venv/Lib/site-packages/frozenlist-1.8.0.dist-info/RECORD +++ b/venv/Lib/site-packages/frozenlist-1.8.0.dist-info/RECORD @@ -1,6 +1,7 @@ frozenlist-1.8.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 frozenlist-1.8.0.dist-info/METADATA,sha256=Qnius9GPH4t-avW2dxupqPMnASpC1kUJ-dQIe1X3GpQ,21005 frozenlist-1.8.0.dist-info/RECORD,, +frozenlist-1.8.0.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 frozenlist-1.8.0.dist-info/WHEEL,sha256=8UP9x9puWI0P1V_d7K2oMTBqfeLNm21CTzZ_Ptr0NXU,101 frozenlist-1.8.0.dist-info/licenses/LICENSE,sha256=b9UkPpLdf5jsacesN3co50kFcJ_1J6W_mNbQJjwE9bY,11332 frozenlist-1.8.0.dist-info/top_level.txt,sha256=jivtxsPXA3nK3WBWW2LW5Mtu_GHt8UZA13NeCs2cKuA,11 diff --git a/venv/Lib/site-packages/frozenlist-1.8.0.dist-info/REQUESTED b/venv/Lib/site-packages/frozenlist-1.8.0.dist-info/REQUESTED new file mode 100644 index 0000000..e69de29 diff --git a/venv/Lib/site-packages/frozenlist/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/frozenlist/__pycache__/__init__.cpython-312.pyc index 8a4dc9f..16be6ce 100644 Binary files a/venv/Lib/site-packages/frozenlist/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/frozenlist/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/greenlet-3.3.0.dist-info/RECORD b/venv/Lib/site-packages/greenlet-3.3.0.dist-info/RECORD index a53d889..309aebd 100644 --- a/venv/Lib/site-packages/greenlet-3.3.0.dist-info/RECORD +++ b/venv/Lib/site-packages/greenlet-3.3.0.dist-info/RECORD @@ -2,6 +2,7 @@ greenlet-3.3.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 greenlet-3.3.0.dist-info/METADATA,sha256=z34cVbU89R99TLnlubPWZOm7mz57d-J2zYknh8orBdE,4239 greenlet-3.3.0.dist-info/RECORD,, +greenlet-3.3.0.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 greenlet-3.3.0.dist-info/WHEEL,sha256=8UP9x9puWI0P1V_d7K2oMTBqfeLNm21CTzZ_Ptr0NXU,101 greenlet-3.3.0.dist-info/licenses/LICENSE,sha256=dpgx1uXfrywggC-sz_H6-0wgJd2PYlPfpH_K1Z1NCXk,1434 greenlet-3.3.0.dist-info/licenses/LICENSE.PSF,sha256=5f88I8EQ5JTNfXNsEP2W1GJFe6_soxCEDbZScpjH1Gs,2424 diff --git a/venv/Lib/site-packages/greenlet-3.3.0.dist-info/REQUESTED b/venv/Lib/site-packages/greenlet-3.3.0.dist-info/REQUESTED new file mode 100644 index 0000000..e69de29 diff --git a/venv/Lib/site-packages/greenlet/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/greenlet/__pycache__/__init__.cpython-312.pyc index 23878bf..2fabdc6 100644 Binary files a/venv/Lib/site-packages/greenlet/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/greenlet/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/greenlet/platform/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/greenlet/platform/__pycache__/__init__.cpython-312.pyc index 7262f21..6dc56af 100644 Binary files a/venv/Lib/site-packages/greenlet/platform/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/greenlet/platform/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/greenlet/tests/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/greenlet/tests/__pycache__/__init__.cpython-312.pyc index ef72956..a6a69a7 100644 Binary files a/venv/Lib/site-packages/greenlet/tests/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/greenlet/tests/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/greenlet/tests/__pycache__/fail_clearing_run_switches.cpython-312.pyc b/venv/Lib/site-packages/greenlet/tests/__pycache__/fail_clearing_run_switches.cpython-312.pyc index 2faae17..8f1a5cc 100644 Binary files a/venv/Lib/site-packages/greenlet/tests/__pycache__/fail_clearing_run_switches.cpython-312.pyc and b/venv/Lib/site-packages/greenlet/tests/__pycache__/fail_clearing_run_switches.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/greenlet/tests/__pycache__/fail_cpp_exception.cpython-312.pyc b/venv/Lib/site-packages/greenlet/tests/__pycache__/fail_cpp_exception.cpython-312.pyc index 8aa0d00..69ea980 100644 Binary files a/venv/Lib/site-packages/greenlet/tests/__pycache__/fail_cpp_exception.cpython-312.pyc and b/venv/Lib/site-packages/greenlet/tests/__pycache__/fail_cpp_exception.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/greenlet/tests/__pycache__/fail_initialstub_already_started.cpython-312.pyc b/venv/Lib/site-packages/greenlet/tests/__pycache__/fail_initialstub_already_started.cpython-312.pyc index ee43a95..de35f7d 100644 Binary files a/venv/Lib/site-packages/greenlet/tests/__pycache__/fail_initialstub_already_started.cpython-312.pyc and b/venv/Lib/site-packages/greenlet/tests/__pycache__/fail_initialstub_already_started.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/greenlet/tests/__pycache__/fail_slp_switch.cpython-312.pyc b/venv/Lib/site-packages/greenlet/tests/__pycache__/fail_slp_switch.cpython-312.pyc index 7452616..74b7850 100644 Binary files a/venv/Lib/site-packages/greenlet/tests/__pycache__/fail_slp_switch.cpython-312.pyc and b/venv/Lib/site-packages/greenlet/tests/__pycache__/fail_slp_switch.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/greenlet/tests/__pycache__/fail_switch_three_greenlets.cpython-312.pyc b/venv/Lib/site-packages/greenlet/tests/__pycache__/fail_switch_three_greenlets.cpython-312.pyc index 1aa65d2..575467f 100644 Binary files a/venv/Lib/site-packages/greenlet/tests/__pycache__/fail_switch_three_greenlets.cpython-312.pyc and b/venv/Lib/site-packages/greenlet/tests/__pycache__/fail_switch_three_greenlets.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/greenlet/tests/__pycache__/fail_switch_three_greenlets2.cpython-312.pyc b/venv/Lib/site-packages/greenlet/tests/__pycache__/fail_switch_three_greenlets2.cpython-312.pyc index 68f2d1d..2597e12 100644 Binary files a/venv/Lib/site-packages/greenlet/tests/__pycache__/fail_switch_three_greenlets2.cpython-312.pyc and b/venv/Lib/site-packages/greenlet/tests/__pycache__/fail_switch_three_greenlets2.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/greenlet/tests/__pycache__/fail_switch_two_greenlets.cpython-312.pyc b/venv/Lib/site-packages/greenlet/tests/__pycache__/fail_switch_two_greenlets.cpython-312.pyc index 462be63..2c95f59 100644 Binary files a/venv/Lib/site-packages/greenlet/tests/__pycache__/fail_switch_two_greenlets.cpython-312.pyc and b/venv/Lib/site-packages/greenlet/tests/__pycache__/fail_switch_two_greenlets.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/greenlet/tests/__pycache__/leakcheck.cpython-312.pyc b/venv/Lib/site-packages/greenlet/tests/__pycache__/leakcheck.cpython-312.pyc index 35fdb57..3517424 100644 Binary files a/venv/Lib/site-packages/greenlet/tests/__pycache__/leakcheck.cpython-312.pyc and b/venv/Lib/site-packages/greenlet/tests/__pycache__/leakcheck.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/greenlet/tests/__pycache__/test_contextvars.cpython-312.pyc b/venv/Lib/site-packages/greenlet/tests/__pycache__/test_contextvars.cpython-312.pyc index 9278b20..9b15055 100644 Binary files a/venv/Lib/site-packages/greenlet/tests/__pycache__/test_contextvars.cpython-312.pyc and b/venv/Lib/site-packages/greenlet/tests/__pycache__/test_contextvars.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/greenlet/tests/__pycache__/test_cpp.cpython-312.pyc b/venv/Lib/site-packages/greenlet/tests/__pycache__/test_cpp.cpython-312.pyc index 7e25549..6d8bc69 100644 Binary files a/venv/Lib/site-packages/greenlet/tests/__pycache__/test_cpp.cpython-312.pyc and b/venv/Lib/site-packages/greenlet/tests/__pycache__/test_cpp.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/greenlet/tests/__pycache__/test_extension_interface.cpython-312.pyc b/venv/Lib/site-packages/greenlet/tests/__pycache__/test_extension_interface.cpython-312.pyc index 3ac5d59..eae2519 100644 Binary files a/venv/Lib/site-packages/greenlet/tests/__pycache__/test_extension_interface.cpython-312.pyc and b/venv/Lib/site-packages/greenlet/tests/__pycache__/test_extension_interface.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/greenlet/tests/__pycache__/test_gc.cpython-312.pyc b/venv/Lib/site-packages/greenlet/tests/__pycache__/test_gc.cpython-312.pyc index 288fedd..622e837 100644 Binary files a/venv/Lib/site-packages/greenlet/tests/__pycache__/test_gc.cpython-312.pyc and b/venv/Lib/site-packages/greenlet/tests/__pycache__/test_gc.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/greenlet/tests/__pycache__/test_generator.cpython-312.pyc b/venv/Lib/site-packages/greenlet/tests/__pycache__/test_generator.cpython-312.pyc index 5fd58b5..5b92a11 100644 Binary files a/venv/Lib/site-packages/greenlet/tests/__pycache__/test_generator.cpython-312.pyc and b/venv/Lib/site-packages/greenlet/tests/__pycache__/test_generator.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/greenlet/tests/__pycache__/test_generator_nested.cpython-312.pyc b/venv/Lib/site-packages/greenlet/tests/__pycache__/test_generator_nested.cpython-312.pyc index a1903f9..76621e7 100644 Binary files a/venv/Lib/site-packages/greenlet/tests/__pycache__/test_generator_nested.cpython-312.pyc and b/venv/Lib/site-packages/greenlet/tests/__pycache__/test_generator_nested.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/greenlet/tests/__pycache__/test_greenlet.cpython-312.pyc b/venv/Lib/site-packages/greenlet/tests/__pycache__/test_greenlet.cpython-312.pyc index 5458329..4f0a611 100644 Binary files a/venv/Lib/site-packages/greenlet/tests/__pycache__/test_greenlet.cpython-312.pyc and b/venv/Lib/site-packages/greenlet/tests/__pycache__/test_greenlet.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/greenlet/tests/__pycache__/test_greenlet_trash.cpython-312.pyc b/venv/Lib/site-packages/greenlet/tests/__pycache__/test_greenlet_trash.cpython-312.pyc index 8b398a7..b50be4c 100644 Binary files a/venv/Lib/site-packages/greenlet/tests/__pycache__/test_greenlet_trash.cpython-312.pyc and b/venv/Lib/site-packages/greenlet/tests/__pycache__/test_greenlet_trash.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/greenlet/tests/__pycache__/test_leaks.cpython-312.pyc b/venv/Lib/site-packages/greenlet/tests/__pycache__/test_leaks.cpython-312.pyc index 992024e..a81e234 100644 Binary files a/venv/Lib/site-packages/greenlet/tests/__pycache__/test_leaks.cpython-312.pyc and b/venv/Lib/site-packages/greenlet/tests/__pycache__/test_leaks.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/greenlet/tests/__pycache__/test_stack_saved.cpython-312.pyc b/venv/Lib/site-packages/greenlet/tests/__pycache__/test_stack_saved.cpython-312.pyc index 94755ec..9831ce4 100644 Binary files a/venv/Lib/site-packages/greenlet/tests/__pycache__/test_stack_saved.cpython-312.pyc and b/venv/Lib/site-packages/greenlet/tests/__pycache__/test_stack_saved.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/greenlet/tests/__pycache__/test_throw.cpython-312.pyc b/venv/Lib/site-packages/greenlet/tests/__pycache__/test_throw.cpython-312.pyc index 7c11f00..a66e1c3 100644 Binary files a/venv/Lib/site-packages/greenlet/tests/__pycache__/test_throw.cpython-312.pyc and b/venv/Lib/site-packages/greenlet/tests/__pycache__/test_throw.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/greenlet/tests/__pycache__/test_tracing.cpython-312.pyc b/venv/Lib/site-packages/greenlet/tests/__pycache__/test_tracing.cpython-312.pyc index 6874bc6..7b8ee54 100644 Binary files a/venv/Lib/site-packages/greenlet/tests/__pycache__/test_tracing.cpython-312.pyc and b/venv/Lib/site-packages/greenlet/tests/__pycache__/test_tracing.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/greenlet/tests/__pycache__/test_version.cpython-312.pyc b/venv/Lib/site-packages/greenlet/tests/__pycache__/test_version.cpython-312.pyc index 003904d..0a313ee 100644 Binary files a/venv/Lib/site-packages/greenlet/tests/__pycache__/test_version.cpython-312.pyc and b/venv/Lib/site-packages/greenlet/tests/__pycache__/test_version.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/greenlet/tests/__pycache__/test_weakref.cpython-312.pyc b/venv/Lib/site-packages/greenlet/tests/__pycache__/test_weakref.cpython-312.pyc index 7c6ce5d..aa68bbd 100644 Binary files a/venv/Lib/site-packages/greenlet/tests/__pycache__/test_weakref.cpython-312.pyc and b/venv/Lib/site-packages/greenlet/tests/__pycache__/test_weakref.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/idna-3.11.dist-info/RECORD b/venv/Lib/site-packages/idna-3.11.dist-info/RECORD index 1203f10..6019b09 100644 --- a/venv/Lib/site-packages/idna-3.11.dist-info/RECORD +++ b/venv/Lib/site-packages/idna-3.11.dist-info/RECORD @@ -1,6 +1,7 @@ idna-3.11.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 idna-3.11.dist-info/METADATA,sha256=fCwSww9SuiN8TIHllFSASUQCW55hAs8dzKnr9RaEEbA,8378 idna-3.11.dist-info/RECORD,, +idna-3.11.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 idna-3.11.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82 idna-3.11.dist-info/licenses/LICENSE.md,sha256=t6M2q_OwThgOwGXN0W5wXQeeHMehT5EKpukYfza5zYc,1541 idna/__init__.py,sha256=MPqNDLZbXqGaNdXxAFhiqFPKEQXju2jNQhCey6-5eJM,868 diff --git a/venv/Lib/site-packages/idna-3.11.dist-info/REQUESTED b/venv/Lib/site-packages/idna-3.11.dist-info/REQUESTED new file mode 100644 index 0000000..e69de29 diff --git a/venv/Lib/site-packages/idna/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/idna/__pycache__/__init__.cpython-312.pyc index 86ed7d4..f877ce7 100644 Binary files a/venv/Lib/site-packages/idna/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/idna/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/idna/__pycache__/codec.cpython-312.pyc b/venv/Lib/site-packages/idna/__pycache__/codec.cpython-312.pyc index 6107217..3a7df1c 100644 Binary files a/venv/Lib/site-packages/idna/__pycache__/codec.cpython-312.pyc and b/venv/Lib/site-packages/idna/__pycache__/codec.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/idna/__pycache__/compat.cpython-312.pyc b/venv/Lib/site-packages/idna/__pycache__/compat.cpython-312.pyc index 8275a8a..1b2a045 100644 Binary files a/venv/Lib/site-packages/idna/__pycache__/compat.cpython-312.pyc and b/venv/Lib/site-packages/idna/__pycache__/compat.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/idna/__pycache__/core.cpython-312.pyc b/venv/Lib/site-packages/idna/__pycache__/core.cpython-312.pyc index 5fe5912..ed5a4ec 100644 Binary files a/venv/Lib/site-packages/idna/__pycache__/core.cpython-312.pyc and b/venv/Lib/site-packages/idna/__pycache__/core.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/idna/__pycache__/idnadata.cpython-312.pyc b/venv/Lib/site-packages/idna/__pycache__/idnadata.cpython-312.pyc index 133b803..d96fd7b 100644 Binary files a/venv/Lib/site-packages/idna/__pycache__/idnadata.cpython-312.pyc and b/venv/Lib/site-packages/idna/__pycache__/idnadata.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/idna/__pycache__/intranges.cpython-312.pyc b/venv/Lib/site-packages/idna/__pycache__/intranges.cpython-312.pyc index 3481320..4557b6e 100644 Binary files a/venv/Lib/site-packages/idna/__pycache__/intranges.cpython-312.pyc and b/venv/Lib/site-packages/idna/__pycache__/intranges.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/idna/__pycache__/package_data.cpython-312.pyc b/venv/Lib/site-packages/idna/__pycache__/package_data.cpython-312.pyc index 8f0af7a..87fbc8a 100644 Binary files a/venv/Lib/site-packages/idna/__pycache__/package_data.cpython-312.pyc and b/venv/Lib/site-packages/idna/__pycache__/package_data.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/idna/__pycache__/uts46data.cpython-312.pyc b/venv/Lib/site-packages/idna/__pycache__/uts46data.cpython-312.pyc index a7a362b..1f98bb9 100644 Binary files a/venv/Lib/site-packages/idna/__pycache__/uts46data.cpython-312.pyc and b/venv/Lib/site-packages/idna/__pycache__/uts46data.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/itsdangerous-2.2.0.dist-info/RECORD b/venv/Lib/site-packages/itsdangerous-2.2.0.dist-info/RECORD index 1394876..b73b08a 100644 --- a/venv/Lib/site-packages/itsdangerous-2.2.0.dist-info/RECORD +++ b/venv/Lib/site-packages/itsdangerous-2.2.0.dist-info/RECORD @@ -2,6 +2,7 @@ itsdangerous-2.2.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7 itsdangerous-2.2.0.dist-info/LICENSE.txt,sha256=Y68JiRtr6K0aQlLtQ68PTvun_JSOIoNnvtfzxa4LCdc,1475 itsdangerous-2.2.0.dist-info/METADATA,sha256=0rk0-1ZwihuU5DnwJVwPWoEI4yWOyCexih3JyZHblhE,1924 itsdangerous-2.2.0.dist-info/RECORD,, +itsdangerous-2.2.0.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 itsdangerous-2.2.0.dist-info/WHEEL,sha256=EZbGkh7Ie4PoZfRQ8I0ZuP9VklN_TvcZ6DSE5Uar4z4,81 itsdangerous/__init__.py,sha256=4SK75sCe29xbRgQE1ZQtMHnKUuZYAf3bSpZOrff1IAY,1427 itsdangerous/__pycache__/__init__.cpython-312.pyc,, diff --git a/venv/Lib/site-packages/itsdangerous-2.2.0.dist-info/REQUESTED b/venv/Lib/site-packages/itsdangerous-2.2.0.dist-info/REQUESTED new file mode 100644 index 0000000..e69de29 diff --git a/venv/Lib/site-packages/itsdangerous/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/itsdangerous/__pycache__/__init__.cpython-312.pyc index 8a569f8..4186732 100644 Binary files a/venv/Lib/site-packages/itsdangerous/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/itsdangerous/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/itsdangerous/__pycache__/_json.cpython-312.pyc b/venv/Lib/site-packages/itsdangerous/__pycache__/_json.cpython-312.pyc index c5fff90..a072c6b 100644 Binary files a/venv/Lib/site-packages/itsdangerous/__pycache__/_json.cpython-312.pyc and b/venv/Lib/site-packages/itsdangerous/__pycache__/_json.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/itsdangerous/__pycache__/encoding.cpython-312.pyc b/venv/Lib/site-packages/itsdangerous/__pycache__/encoding.cpython-312.pyc index a98e345..eaa6596 100644 Binary files a/venv/Lib/site-packages/itsdangerous/__pycache__/encoding.cpython-312.pyc and b/venv/Lib/site-packages/itsdangerous/__pycache__/encoding.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/itsdangerous/__pycache__/exc.cpython-312.pyc b/venv/Lib/site-packages/itsdangerous/__pycache__/exc.cpython-312.pyc index f7e5fdf..b042a13 100644 Binary files a/venv/Lib/site-packages/itsdangerous/__pycache__/exc.cpython-312.pyc and b/venv/Lib/site-packages/itsdangerous/__pycache__/exc.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/itsdangerous/__pycache__/serializer.cpython-312.pyc b/venv/Lib/site-packages/itsdangerous/__pycache__/serializer.cpython-312.pyc index 76f5962..5fc796d 100644 Binary files a/venv/Lib/site-packages/itsdangerous/__pycache__/serializer.cpython-312.pyc and b/venv/Lib/site-packages/itsdangerous/__pycache__/serializer.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/itsdangerous/__pycache__/signer.cpython-312.pyc b/venv/Lib/site-packages/itsdangerous/__pycache__/signer.cpython-312.pyc index b1c3611..5ab6ff4 100644 Binary files a/venv/Lib/site-packages/itsdangerous/__pycache__/signer.cpython-312.pyc and b/venv/Lib/site-packages/itsdangerous/__pycache__/signer.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/itsdangerous/__pycache__/timed.cpython-312.pyc b/venv/Lib/site-packages/itsdangerous/__pycache__/timed.cpython-312.pyc index 76e79d5..eee0036 100644 Binary files a/venv/Lib/site-packages/itsdangerous/__pycache__/timed.cpython-312.pyc and b/venv/Lib/site-packages/itsdangerous/__pycache__/timed.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/itsdangerous/__pycache__/url_safe.cpython-312.pyc b/venv/Lib/site-packages/itsdangerous/__pycache__/url_safe.cpython-312.pyc index 3cd4648..1f565b7 100644 Binary files a/venv/Lib/site-packages/itsdangerous/__pycache__/url_safe.cpython-312.pyc and b/venv/Lib/site-packages/itsdangerous/__pycache__/url_safe.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/jinja2-3.1.6.dist-info/RECORD b/venv/Lib/site-packages/jinja2-3.1.6.dist-info/RECORD index 0ca35a7..b035d60 100644 --- a/venv/Lib/site-packages/jinja2-3.1.6.dist-info/RECORD +++ b/venv/Lib/site-packages/jinja2-3.1.6.dist-info/RECORD @@ -1,6 +1,7 @@ jinja2-3.1.6.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 jinja2-3.1.6.dist-info/METADATA,sha256=aMVUj7Z8QTKhOJjZsx7FDGvqKr3ZFdkh8hQ1XDpkmcg,2871 jinja2-3.1.6.dist-info/RECORD,, +jinja2-3.1.6.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 jinja2-3.1.6.dist-info/WHEEL,sha256=_2ozNFCLWc93bK4WKHCO-eDUENDlo-dgc9cU3qokYO4,82 jinja2-3.1.6.dist-info/entry_points.txt,sha256=OL85gYU1eD8cuPlikifFngXpeBjaxl6rIJ8KkC_3r-I,58 jinja2-3.1.6.dist-info/licenses/LICENSE.txt,sha256=O0nc7kEF6ze6wQ-vG-JgQI_oXSUrjp3y4JefweCUQ3s,1475 diff --git a/venv/Lib/site-packages/jinja2-3.1.6.dist-info/REQUESTED b/venv/Lib/site-packages/jinja2-3.1.6.dist-info/REQUESTED new file mode 100644 index 0000000..e69de29 diff --git a/venv/Lib/site-packages/jinja2/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/jinja2/__pycache__/__init__.cpython-312.pyc index 7075f7d..d6cc2c6 100644 Binary files a/venv/Lib/site-packages/jinja2/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/jinja2/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/jinja2/__pycache__/_identifier.cpython-312.pyc b/venv/Lib/site-packages/jinja2/__pycache__/_identifier.cpython-312.pyc index 93f4ce9..3c0de03 100644 Binary files a/venv/Lib/site-packages/jinja2/__pycache__/_identifier.cpython-312.pyc and b/venv/Lib/site-packages/jinja2/__pycache__/_identifier.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/jinja2/__pycache__/async_utils.cpython-312.pyc b/venv/Lib/site-packages/jinja2/__pycache__/async_utils.cpython-312.pyc index fd1f70b..c415b2f 100644 Binary files a/venv/Lib/site-packages/jinja2/__pycache__/async_utils.cpython-312.pyc and b/venv/Lib/site-packages/jinja2/__pycache__/async_utils.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/jinja2/__pycache__/bccache.cpython-312.pyc b/venv/Lib/site-packages/jinja2/__pycache__/bccache.cpython-312.pyc index 1267163..c63ff86 100644 Binary files a/venv/Lib/site-packages/jinja2/__pycache__/bccache.cpython-312.pyc and b/venv/Lib/site-packages/jinja2/__pycache__/bccache.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/jinja2/__pycache__/compiler.cpython-312.pyc b/venv/Lib/site-packages/jinja2/__pycache__/compiler.cpython-312.pyc index 1d92eb3..0f06507 100644 Binary files a/venv/Lib/site-packages/jinja2/__pycache__/compiler.cpython-312.pyc and b/venv/Lib/site-packages/jinja2/__pycache__/compiler.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/jinja2/__pycache__/constants.cpython-312.pyc b/venv/Lib/site-packages/jinja2/__pycache__/constants.cpython-312.pyc index 4a6d0af..708854a 100644 Binary files a/venv/Lib/site-packages/jinja2/__pycache__/constants.cpython-312.pyc and b/venv/Lib/site-packages/jinja2/__pycache__/constants.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/jinja2/__pycache__/debug.cpython-312.pyc b/venv/Lib/site-packages/jinja2/__pycache__/debug.cpython-312.pyc index 518faca..4401413 100644 Binary files a/venv/Lib/site-packages/jinja2/__pycache__/debug.cpython-312.pyc and b/venv/Lib/site-packages/jinja2/__pycache__/debug.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/jinja2/__pycache__/defaults.cpython-312.pyc b/venv/Lib/site-packages/jinja2/__pycache__/defaults.cpython-312.pyc index 6f6063e..4dc8f93 100644 Binary files a/venv/Lib/site-packages/jinja2/__pycache__/defaults.cpython-312.pyc and b/venv/Lib/site-packages/jinja2/__pycache__/defaults.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/jinja2/__pycache__/environment.cpython-312.pyc b/venv/Lib/site-packages/jinja2/__pycache__/environment.cpython-312.pyc index 2404353..b91187c 100644 Binary files a/venv/Lib/site-packages/jinja2/__pycache__/environment.cpython-312.pyc and b/venv/Lib/site-packages/jinja2/__pycache__/environment.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/jinja2/__pycache__/exceptions.cpython-312.pyc b/venv/Lib/site-packages/jinja2/__pycache__/exceptions.cpython-312.pyc index 0fa4a4f..70195a4 100644 Binary files a/venv/Lib/site-packages/jinja2/__pycache__/exceptions.cpython-312.pyc and b/venv/Lib/site-packages/jinja2/__pycache__/exceptions.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/jinja2/__pycache__/ext.cpython-312.pyc b/venv/Lib/site-packages/jinja2/__pycache__/ext.cpython-312.pyc index 4014b2d..446b97b 100644 Binary files a/venv/Lib/site-packages/jinja2/__pycache__/ext.cpython-312.pyc and b/venv/Lib/site-packages/jinja2/__pycache__/ext.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/jinja2/__pycache__/filters.cpython-312.pyc b/venv/Lib/site-packages/jinja2/__pycache__/filters.cpython-312.pyc index 793533c..2c5ca01 100644 Binary files a/venv/Lib/site-packages/jinja2/__pycache__/filters.cpython-312.pyc and b/venv/Lib/site-packages/jinja2/__pycache__/filters.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/jinja2/__pycache__/idtracking.cpython-312.pyc b/venv/Lib/site-packages/jinja2/__pycache__/idtracking.cpython-312.pyc index 5fd9142..6a81ece 100644 Binary files a/venv/Lib/site-packages/jinja2/__pycache__/idtracking.cpython-312.pyc and b/venv/Lib/site-packages/jinja2/__pycache__/idtracking.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/jinja2/__pycache__/lexer.cpython-312.pyc b/venv/Lib/site-packages/jinja2/__pycache__/lexer.cpython-312.pyc index f048300..ac02d8b 100644 Binary files a/venv/Lib/site-packages/jinja2/__pycache__/lexer.cpython-312.pyc and b/venv/Lib/site-packages/jinja2/__pycache__/lexer.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/jinja2/__pycache__/loaders.cpython-312.pyc b/venv/Lib/site-packages/jinja2/__pycache__/loaders.cpython-312.pyc index 4be6da5..4928608 100644 Binary files a/venv/Lib/site-packages/jinja2/__pycache__/loaders.cpython-312.pyc and b/venv/Lib/site-packages/jinja2/__pycache__/loaders.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/jinja2/__pycache__/meta.cpython-312.pyc b/venv/Lib/site-packages/jinja2/__pycache__/meta.cpython-312.pyc index cd76d3d..88080c6 100644 Binary files a/venv/Lib/site-packages/jinja2/__pycache__/meta.cpython-312.pyc and b/venv/Lib/site-packages/jinja2/__pycache__/meta.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/jinja2/__pycache__/nativetypes.cpython-312.pyc b/venv/Lib/site-packages/jinja2/__pycache__/nativetypes.cpython-312.pyc index 58bf180..4ff574d 100644 Binary files a/venv/Lib/site-packages/jinja2/__pycache__/nativetypes.cpython-312.pyc and b/venv/Lib/site-packages/jinja2/__pycache__/nativetypes.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/jinja2/__pycache__/nodes.cpython-312.pyc b/venv/Lib/site-packages/jinja2/__pycache__/nodes.cpython-312.pyc index 5034e54..bdfc42e 100644 Binary files a/venv/Lib/site-packages/jinja2/__pycache__/nodes.cpython-312.pyc and b/venv/Lib/site-packages/jinja2/__pycache__/nodes.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/jinja2/__pycache__/optimizer.cpython-312.pyc b/venv/Lib/site-packages/jinja2/__pycache__/optimizer.cpython-312.pyc index 09daddd..6780429 100644 Binary files a/venv/Lib/site-packages/jinja2/__pycache__/optimizer.cpython-312.pyc and b/venv/Lib/site-packages/jinja2/__pycache__/optimizer.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/jinja2/__pycache__/parser.cpython-312.pyc b/venv/Lib/site-packages/jinja2/__pycache__/parser.cpython-312.pyc index eef920a..55c9ab5 100644 Binary files a/venv/Lib/site-packages/jinja2/__pycache__/parser.cpython-312.pyc and b/venv/Lib/site-packages/jinja2/__pycache__/parser.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/jinja2/__pycache__/runtime.cpython-312.pyc b/venv/Lib/site-packages/jinja2/__pycache__/runtime.cpython-312.pyc index bbdfa41..33e7add 100644 Binary files a/venv/Lib/site-packages/jinja2/__pycache__/runtime.cpython-312.pyc and b/venv/Lib/site-packages/jinja2/__pycache__/runtime.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/jinja2/__pycache__/sandbox.cpython-312.pyc b/venv/Lib/site-packages/jinja2/__pycache__/sandbox.cpython-312.pyc index 5dc56e2..1d4ee5d 100644 Binary files a/venv/Lib/site-packages/jinja2/__pycache__/sandbox.cpython-312.pyc and b/venv/Lib/site-packages/jinja2/__pycache__/sandbox.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/jinja2/__pycache__/tests.cpython-312.pyc b/venv/Lib/site-packages/jinja2/__pycache__/tests.cpython-312.pyc index c056ae9..19efa6a 100644 Binary files a/venv/Lib/site-packages/jinja2/__pycache__/tests.cpython-312.pyc and b/venv/Lib/site-packages/jinja2/__pycache__/tests.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/jinja2/__pycache__/utils.cpython-312.pyc b/venv/Lib/site-packages/jinja2/__pycache__/utils.cpython-312.pyc index b88609c..e0d7936 100644 Binary files a/venv/Lib/site-packages/jinja2/__pycache__/utils.cpython-312.pyc and b/venv/Lib/site-packages/jinja2/__pycache__/utils.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/jinja2/__pycache__/visitor.cpython-312.pyc b/venv/Lib/site-packages/jinja2/__pycache__/visitor.cpython-312.pyc index 75cd7c5..bb29a50 100644 Binary files a/venv/Lib/site-packages/jinja2/__pycache__/visitor.cpython-312.pyc and b/venv/Lib/site-packages/jinja2/__pycache__/visitor.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/jmespath-1.0.1.dist-info/RECORD b/venv/Lib/site-packages/jmespath-1.0.1.dist-info/RECORD index 6cc88fb..2d3ed6e 100644 --- a/venv/Lib/site-packages/jmespath-1.0.1.dist-info/RECORD +++ b/venv/Lib/site-packages/jmespath-1.0.1.dist-info/RECORD @@ -1,9 +1,10 @@ ../../Scripts/__pycache__/jp.cpython-312.pyc,, -../../Scripts/jp.py,sha256=2I5iN2MCp07c1h5C-HRoVVfS5pPKRtGmX7RjwZp6I1k,1713 +../../Scripts/jp.py,sha256=sprMFywWQ1D9WkjehVCZcqjKVgyulQzc5hC--rAtj78,1711 jmespath-1.0.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 jmespath-1.0.1.dist-info/LICENSE.txt,sha256=ZrMTzOgO0GI_x9s_JIY6DID9g-s0Gka1eGQViudPqlY,1084 jmespath-1.0.1.dist-info/METADATA,sha256=gJiDKN4nzYpDr4qYCl88FqJlaKenmN5w0xZctn4L4RA,7555 jmespath-1.0.1.dist-info/RECORD,, +jmespath-1.0.1.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 jmespath-1.0.1.dist-info/WHEEL,sha256=G16H4A3IeoQmnOrYV4ueZGKSjhipXx8zc8nu9FGlvMA,92 jmespath-1.0.1.dist-info/top_level.txt,sha256=vuy_oZ1ckpeSNrAi8JK8-yIGO6bduO3qvW2cCMQmPH8,9 jmespath/__init__.py,sha256=WNf8QdWqpRhG6wwQZoFI_GCM_b8u2BzREN0egQsPq1w,281 diff --git a/venv/Lib/site-packages/jmespath-1.0.1.dist-info/REQUESTED b/venv/Lib/site-packages/jmespath-1.0.1.dist-info/REQUESTED new file mode 100644 index 0000000..e69de29 diff --git a/venv/Lib/site-packages/jmespath/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/jmespath/__pycache__/__init__.cpython-312.pyc index b044692..d287d68 100644 Binary files a/venv/Lib/site-packages/jmespath/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/jmespath/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/jmespath/__pycache__/ast.cpython-312.pyc b/venv/Lib/site-packages/jmespath/__pycache__/ast.cpython-312.pyc index 605b8b5..7dfa92f 100644 Binary files a/venv/Lib/site-packages/jmespath/__pycache__/ast.cpython-312.pyc and b/venv/Lib/site-packages/jmespath/__pycache__/ast.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/jmespath/__pycache__/compat.cpython-312.pyc b/venv/Lib/site-packages/jmespath/__pycache__/compat.cpython-312.pyc index abbeed2..168cb08 100644 Binary files a/venv/Lib/site-packages/jmespath/__pycache__/compat.cpython-312.pyc and b/venv/Lib/site-packages/jmespath/__pycache__/compat.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/jmespath/__pycache__/exceptions.cpython-312.pyc b/venv/Lib/site-packages/jmespath/__pycache__/exceptions.cpython-312.pyc index 3046f61..aaf7f43 100644 Binary files a/venv/Lib/site-packages/jmespath/__pycache__/exceptions.cpython-312.pyc and b/venv/Lib/site-packages/jmespath/__pycache__/exceptions.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/jmespath/__pycache__/functions.cpython-312.pyc b/venv/Lib/site-packages/jmespath/__pycache__/functions.cpython-312.pyc index f9833c1..f7319ad 100644 Binary files a/venv/Lib/site-packages/jmespath/__pycache__/functions.cpython-312.pyc and b/venv/Lib/site-packages/jmespath/__pycache__/functions.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/jmespath/__pycache__/lexer.cpython-312.pyc b/venv/Lib/site-packages/jmespath/__pycache__/lexer.cpython-312.pyc index 8db195d..e426f96 100644 Binary files a/venv/Lib/site-packages/jmespath/__pycache__/lexer.cpython-312.pyc and b/venv/Lib/site-packages/jmespath/__pycache__/lexer.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/jmespath/__pycache__/parser.cpython-312.pyc b/venv/Lib/site-packages/jmespath/__pycache__/parser.cpython-312.pyc index 0705811..08802de 100644 Binary files a/venv/Lib/site-packages/jmespath/__pycache__/parser.cpython-312.pyc and b/venv/Lib/site-packages/jmespath/__pycache__/parser.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/jmespath/__pycache__/visitor.cpython-312.pyc b/venv/Lib/site-packages/jmespath/__pycache__/visitor.cpython-312.pyc index 2b0e243..2abec80 100644 Binary files a/venv/Lib/site-packages/jmespath/__pycache__/visitor.cpython-312.pyc and b/venv/Lib/site-packages/jmespath/__pycache__/visitor.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/markupsafe-3.0.3.dist-info/RECORD b/venv/Lib/site-packages/markupsafe-3.0.3.dist-info/RECORD index a8c5bbb..2ff188d 100644 --- a/venv/Lib/site-packages/markupsafe-3.0.3.dist-info/RECORD +++ b/venv/Lib/site-packages/markupsafe-3.0.3.dist-info/RECORD @@ -1,6 +1,7 @@ markupsafe-3.0.3.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 markupsafe-3.0.3.dist-info/METADATA,sha256=8K5duwnVD7X3Yyw9U_AiCZXvdgGeWJLgpUV0ATak48s,2764 markupsafe-3.0.3.dist-info/RECORD,, +markupsafe-3.0.3.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 markupsafe-3.0.3.dist-info/WHEEL,sha256=8UP9x9puWI0P1V_d7K2oMTBqfeLNm21CTzZ_Ptr0NXU,101 markupsafe-3.0.3.dist-info/licenses/LICENSE.txt,sha256=RjHsDbX9kKVH4zaBcmTGeYIUM4FG-KyUtKV_lu6MnsQ,1503 markupsafe-3.0.3.dist-info/top_level.txt,sha256=qy0Plje5IJuvsCBjejJyhDCjEAdcDLK_2agVcex8Z6U,11 diff --git a/venv/Lib/site-packages/markupsafe-3.0.3.dist-info/REQUESTED b/venv/Lib/site-packages/markupsafe-3.0.3.dist-info/REQUESTED new file mode 100644 index 0000000..e69de29 diff --git a/venv/Lib/site-packages/markupsafe/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/markupsafe/__pycache__/__init__.cpython-312.pyc index 47402fe..3b3c765 100644 Binary files a/venv/Lib/site-packages/markupsafe/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/markupsafe/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/markupsafe/__pycache__/_native.cpython-312.pyc b/venv/Lib/site-packages/markupsafe/__pycache__/_native.cpython-312.pyc index 8b16598..908bc14 100644 Binary files a/venv/Lib/site-packages/markupsafe/__pycache__/_native.cpython-312.pyc and b/venv/Lib/site-packages/markupsafe/__pycache__/_native.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/multidict-6.7.0.dist-info/RECORD b/venv/Lib/site-packages/multidict-6.7.0.dist-info/RECORD index c695fca..5100f51 100644 --- a/venv/Lib/site-packages/multidict-6.7.0.dist-info/RECORD +++ b/venv/Lib/site-packages/multidict-6.7.0.dist-info/RECORD @@ -1,6 +1,7 @@ multidict-6.7.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 multidict-6.7.0.dist-info/METADATA,sha256=Xw8Ehw9kFzGLwsuOXDXIEO2VNqyHmIldPFNMfTgPn7k,5470 multidict-6.7.0.dist-info/RECORD,, +multidict-6.7.0.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 multidict-6.7.0.dist-info/WHEEL,sha256=8UP9x9puWI0P1V_d7K2oMTBqfeLNm21CTzZ_Ptr0NXU,101 multidict-6.7.0.dist-info/licenses/LICENSE,sha256=k9Ealo4vDzY3PECBH_bSDhc_WMPKtYhM1mF7v9eVSSo,611 multidict-6.7.0.dist-info/top_level.txt,sha256=-euDElkk5_qkmfIJ7WiqCab02ZlSFZWynejKg59qZQQ,10 diff --git a/venv/Lib/site-packages/multidict-6.7.0.dist-info/REQUESTED b/venv/Lib/site-packages/multidict-6.7.0.dist-info/REQUESTED new file mode 100644 index 0000000..e69de29 diff --git a/venv/Lib/site-packages/multidict/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/multidict/__pycache__/__init__.cpython-312.pyc index 69f5df8..4c8ad23 100644 Binary files a/venv/Lib/site-packages/multidict/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/multidict/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/multidict/__pycache__/_abc.cpython-312.pyc b/venv/Lib/site-packages/multidict/__pycache__/_abc.cpython-312.pyc index 115a86a..614f579 100644 Binary files a/venv/Lib/site-packages/multidict/__pycache__/_abc.cpython-312.pyc and b/venv/Lib/site-packages/multidict/__pycache__/_abc.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/multidict/__pycache__/_compat.cpython-312.pyc b/venv/Lib/site-packages/multidict/__pycache__/_compat.cpython-312.pyc index 6107338..b713e55 100644 Binary files a/venv/Lib/site-packages/multidict/__pycache__/_compat.cpython-312.pyc and b/venv/Lib/site-packages/multidict/__pycache__/_compat.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/multidict/__pycache__/_multidict_py.cpython-312.pyc b/venv/Lib/site-packages/multidict/__pycache__/_multidict_py.cpython-312.pyc index 67b6ec2..7091ce4 100644 Binary files a/venv/Lib/site-packages/multidict/__pycache__/_multidict_py.cpython-312.pyc and b/venv/Lib/site-packages/multidict/__pycache__/_multidict_py.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pillow-12.1.0.dist-info/INSTALLER b/venv/Lib/site-packages/pillow-10.4.0.dist-info/INSTALLER similarity index 100% rename from venv/Lib/site-packages/pillow-12.1.0.dist-info/INSTALLER rename to venv/Lib/site-packages/pillow-10.4.0.dist-info/INSTALLER diff --git a/venv/Lib/site-packages/pillow-12.1.0.dist-info/licenses/LICENSE b/venv/Lib/site-packages/pillow-10.4.0.dist-info/LICENSE similarity index 66% rename from venv/Lib/site-packages/pillow-12.1.0.dist-info/licenses/LICENSE rename to venv/Lib/site-packages/pillow-10.4.0.dist-info/LICENSE index 19bfa3c..ba1df4a 100644 --- a/venv/Lib/site-packages/pillow-12.1.0.dist-info/licenses/LICENSE +++ b/venv/Lib/site-packages/pillow-10.4.0.dist-info/LICENSE @@ -5,9 +5,9 @@ The Python Imaging Library (PIL) is Pillow is the friendly PIL fork. It is - Copyright © 2010 by Jeffrey A. Clark and contributors + Copyright © 2010-2024 by Jeffrey A. Clark and contributors -Like PIL, Pillow is licensed under the open source MIT-CMU License: +Like PIL, Pillow is licensed under the open source HPND License: By obtaining, using, and/or copying this software and/or its associated documentation, you agree that you have read, understood, and will comply @@ -29,7 +29,7 @@ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -===== brotli-1.2.0 ===== +===== brotli-1.1.0 ===== Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors. @@ -51,7 +51,7 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -===== freetype-2.14.1 ===== +===== freetype-2.13.2 ===== FREETYPE LICENSES ----------------- @@ -90,10 +90,9 @@ in earlier FreeType versions. The gzip module uses the zlib license (see `src/gzip/zlib.h`) which too is compatible to the above two licenses. -The files `src/autofit/ft-hb-ft.c`, `src/autofit/ft-hb-decls.h`, -`src/autofit/ft-hb-types.h`, and `src/autofit/hb-script-list.h` -contain code taken (almost) verbatim from the HarfBuzz library, which -uses the 'Old MIT' license compatible to the above two licenses. +The files `src/autofit/ft-hb.c` and `src/autofit/ft-hb.h` contain code +taken almost verbatim from the HarfBuzz file `hb-ft.cc`, which uses +the 'Old MIT' license, compatible to the above two licenses. The MD5 checksum support (only used for debugging in development builds) is in the public domain. @@ -151,7 +150,7 @@ Introduction """ Portions of this software are copyright © The FreeType - Project (https://freetype.org). All rights reserved. + Project (www.freetype.org). All rights reserved. """ Please replace with the value from the FreeType version you @@ -265,7 +264,7 @@ Legal Terms Our home page can be found at - https://freetype.org + https://www.freetype.org --- end of FTL.TXT --- @@ -610,7 +609,7 @@ consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. -===== harfbuzz-12.3.0 ===== +===== harfbuzz-8.5.0 ===== HarfBuzz is licensed under the so-called "Old MIT" license. Details follow. For parts of HarfBuzz that are licensed under different licenses see individual @@ -655,7 +654,7 @@ FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. -===== lcms2-2.17 ===== +===== lcms2-2.16 ===== MIT License @@ -680,397 +679,7 @@ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -===== libavif-1.3.0 ===== - -Copyright 2019 Joe Drago. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, this -list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright notice, -this list of conditions and the following disclaimer in the documentation -and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ------------------------------------------------------------------------------- - -Files: src/obu.c - -Copyright © 2018-2019, VideoLAN and dav1d authors -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ------------------------------------------------------------------------------- - -Files: third_party/iccjpeg/* - -In plain English: - -1. We don't promise that this software works. (But if you find any bugs, - please let us know!) -2. You can use this software for whatever you want. You don't have to pay us. -3. You may not pretend that you wrote this software. If you use it in a - program, you must acknowledge somewhere in your documentation that - you've used the IJG code. - -In legalese: - -The authors make NO WARRANTY or representation, either express or implied, -with respect to this software, its quality, accuracy, merchantability, or -fitness for a particular purpose. This software is provided "AS IS", and you, -its user, assume the entire risk as to its quality and accuracy. - -This software is copyright (C) 1991-2013, Thomas G. Lane, Guido Vollbeding. -All Rights Reserved except as specified below. - -Permission is hereby granted to use, copy, modify, and distribute this -software (or portions thereof) for any purpose, without fee, subject to these -conditions: -(1) If any part of the source code for this software is distributed, then this -README file must be included, with this copyright and no-warranty notice -unaltered; and any additions, deletions, or changes to the original files -must be clearly indicated in accompanying documentation. -(2) If only executable code is distributed, then the accompanying -documentation must state that "this software is based in part on the work of -the Independent JPEG Group". -(3) Permission for use of this software is granted only if the user accepts -full responsibility for any undesirable consequences; the authors accept -NO LIABILITY for damages of any kind. - -These conditions apply to any software derived from or based on the IJG code, -not just to the unmodified library. If you use our work, you ought to -acknowledge us. - -Permission is NOT granted for the use of any IJG author's name or company name -in advertising or publicity relating to this software or products derived from -it. This software may be referred to only as "the Independent JPEG Group's -software". - -We specifically permit and encourage the use of this software as the basis of -commercial products, provided that all warranty or liability claims are -assumed by the product vendor. - - -The Unix configuration script "configure" was produced with GNU Autoconf. -It is copyright by the Free Software Foundation but is freely distributable. -The same holds for its supporting scripts (config.guess, config.sub, -ltmain.sh). Another support script, install-sh, is copyright by X Consortium -but is also freely distributable. - -The IJG distribution formerly included code to read and write GIF files. -To avoid entanglement with the Unisys LZW patent, GIF reading support has -been removed altogether, and the GIF writer has been simplified to produce -"uncompressed GIFs". This technique does not use the LZW algorithm; the -resulting GIF files are larger than usual, but are readable by all standard -GIF decoders. - -We are required to state that - "The Graphics Interchange Format(c) is the Copyright property of - CompuServe Incorporated. GIF(sm) is a Service Mark property of - CompuServe Incorporated." - ------------------------------------------------------------------------------- - -Files: contrib/gdk-pixbuf/* - -Copyright 2020 Emmanuel Gil Peyrot. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, this -list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright notice, -this list of conditions and the following disclaimer in the documentation -and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ------------------------------------------------------------------------------- - -Files: android_jni/gradlew* - - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - ------------------------------------------------------------------------------- - -Files: third_party/libyuv/* - -Copyright 2011 The LibYuv Project Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - - * Neither the name of Google nor the names of its contributors may - be used to endorse or promote products derived from this software - without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -===== libjpeg-turbo-3.1.3 ===== +===== libjpeg-turbo-3.0.3 ===== LEGAL ISSUES ============ @@ -1217,7 +826,7 @@ intended solely for clarification. The Modified (3-clause) BSD License =================================== -Copyright (C)2009-2025 D. R. Commander. All Rights Reserved.
+Copyright (C)2009-2023 D. R. Commander. All Rights Reserved.
Copyright (C)2015 Viktor Szathmáry. All Rights Reserved. Redistribution and use in source and binary forms, with or without @@ -1257,7 +866,40 @@ attribution and endorsement protections to other entities. Thus, it was desirable to choose a license that granted us the same protections for new code that were granted to the IJG for code derived from their software. -===== libpng-1.6.53 ===== +===== libwebp-1.4.0 ===== + +Copyright (c) 2010, Google Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + * Neither the name of Google nor the names of its contributors may + be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +===== lpng1643 ===== COPYRIGHT NOTICE, DISCLAIMER, and LICENSE ========================================= @@ -1265,8 +907,8 @@ COPYRIGHT NOTICE, DISCLAIMER, and LICENSE PNG Reference Library License version 2 --------------------------------------- - * Copyright (c) 1995-2025 The PNG Reference Library Authors. - * Copyright (c) 2018-2025 Cosmin Truta. + * Copyright (c) 1995-2024 The PNG Reference Library Authors. + * Copyright (c) 2018-2024 Cosmin Truta. * Copyright (c) 2000-2002, 2004, 2006-2018 Glenn Randers-Pehrson. * Copyright (c) 1996-1997 Andreas Dilger. * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. @@ -1394,40 +1036,7 @@ to supporting the PNG file format in commercial products. If you use this source code in a product, acknowledgment is not required but would be appreciated. -===== libwebp-1.6.0 ===== - -Copyright (c) 2010, Google Inc. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - - * Neither the name of Google nor the names of its contributors may - be used to endorse or promote products derived from this software - without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - -===== openjpeg-2.5.4 ===== +===== openjpeg-2.5.2 ===== /* * The copyright in this software is being made available under the 2-clauses @@ -1469,7 +1078,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * POSSIBILITY OF SUCH DAMAGE. */ -===== tiff-4.7.1 ===== +===== tiff-4.6.0 ===== # LibTIFF license @@ -1494,124 +1103,117 @@ OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -# Lempel-Ziv & Welch Compression (tif_lzw.c) license -The code of tif_lzw.c is derived from the compress program whose code is -derived from software contributed to Berkeley by James A. Woods, -derived from original work by Spencer Thomas and Joseph Orost. - -The original Berkeley copyright notice appears below in its entirety: - -Copyright (c) 1985, 1986 The Regents of the University of California. -All rights reserved. - -This code is derived from software contributed to Berkeley by -James A. Woods, derived from original work by Spencer Thomas -and Joseph Orost. - -Redistribution and use in source and binary forms are permitted -provided that the above copyright notice and this paragraph are -duplicated in all such forms and that any documentation, -advertising materials, and other materials related to such -distribution and use acknowledge that the software was developed -by the University of California, Berkeley. The name of the -University may not be used to endorse or promote products derived -from this software without specific prior written permission. -THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR -IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED -WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. -===== xz-5.8.2 ===== +===== xz-5.4.5 ===== XZ Utils Licensing ================== Different licenses apply to different files in this package. Here - is a summary of which licenses apply to which parts of this package: + is a rough summary of which licenses apply to which parts of this + package (but check the individual files to be sure!): - - liblzma is under the BSD Zero Clause License (0BSD). + - liblzma is in the public domain. - - The command line tools xz, xzdec, lzmadec, and lzmainfo are - under 0BSD except that, on systems that don't have a usable - getopt_long, GNU getopt_long is compiled and linked in from the - 'lib' directory. The getopt_long code is under GNU LGPLv2.1+. + - xz, xzdec, and lzmadec command line tools are in the public + domain unless GNU getopt_long had to be compiled and linked + in from the lib directory. The getopt_long code is under + GNU LGPLv2.1+. - The scripts to grep, diff, and view compressed files have been - adapted from GNU gzip. These scripts (xzgrep, xzdiff, xzless, - and xzmore) are under GNU GPLv2+. The man pages of the scripts - are under 0BSD; they aren't based on the man pages of GNU gzip. + adapted from gzip. These scripts and their documentation are + under GNU GPLv2+. - - Most of the XZ Utils specific documentation that is in - plain text files (like README, INSTALL, PACKAGERS, NEWS, - and ChangeLog) are under 0BSD unless stated otherwise in - the file itself. The files xz-file-format.txt and - lzma-file-format.xt are in the public domain but may - be distributed under the terms of 0BSD too. + - All the documentation in the doc directory and most of the + XZ Utils specific documentation files in other directories + are in the public domain. - - Translated messages and man pages are under 0BSD except that - some old translations are in the public domain. + Note: The JavaScript files (under the MIT license) have + been removed from the Doxygen-generated HTML version of the + liblzma API documentation. Doxygen itself is under the GNU GPL + but the remaining files generated by Doxygen are not affected + by the licenses used in Doxygen because Doxygen licensing has + the following exception: - - Test files and test code in the 'tests' directory, and - debugging utilities in the 'debug' directory are under - the BSD Zero Clause License (0BSD). + "Documents produced by doxygen are derivative works + derived from the input used in their production; + they are not affected by this license." - - The GNU Autotools based build system contains files that are - under GNU GPLv2+, GNU GPLv3+, and a few permissive licenses. - These files don't affect the licensing of the binaries being - built. + - Translated messages are in the public domain. - - The 'extra' directory contains files that are under various - free software licenses. These aren't built or installed as - part of XZ Utils. + - The build system contains public domain files, and files that + are under GNU GPLv2+ or GNU GPLv3+. None of these files end up + in the binaries being built. - The following command may be helpful in finding per-file license - information. It works on xz.git and on a clean file tree extracted - from a release tarball. + - Test files and test code in the tests directory, and debugging + utilities in the debug directory are in the public domain. - sh build-aux/license-check.sh -v + - The extra directory may contain public domain files, and files + that are under various free software licenses. - For the files under the BSD Zero Clause License (0BSD), if - a copyright notice is needed, the following is sufficient: + You can do whatever you want with the files that have been put into + the public domain. If you find public domain legally problematic, + take the previous sentence as a license grant. If you still find + the lack of copyright legally problematic, you have too many + lawyers. - Copyright (C) The XZ Utils authors and contributors + As usual, this software is provided "as is", without any warranty. - If you copy significant amounts of 0BSD-licensed code from XZ Utils + If you copy significant amounts of public domain code from XZ Utils into your project, acknowledging this somewhere in your software is polite (especially if it is proprietary, non-free software), but - it is not legally required by the license terms. Here is an example - of a good notice to put into "about box" or into documentation: + naturally it is not legally required. Here is an example of a good + notice to put into "about box" or into documentation: This software includes code from XZ Utils . The following license texts are included in the following files: - - COPYING.0BSD: BSD Zero Clause License - COPYING.LGPLv2.1: GNU Lesser General Public License version 2.1 - COPYING.GPLv2: GNU General Public License version 2 - COPYING.GPLv3: GNU General Public License version 3 - If you have questions, don't hesitate to ask for more information. - The contact information is in the README file. + Note that the toolchain (compiler, linker etc.) may add some code + pieces that are copyrighted. Thus, it is possible that e.g. liblzma + binary wouldn't actually be in the public domain in its entirety + even though it contains no copyrighted code from the XZ Utils source + package. + + If you have questions, don't hesitate to ask the author(s) for more + information. -===== zlib-ng-2.3.2 ===== +===== zlib-1.3.1 ===== -(C) 1995-2024 Jean-loup Gailly and Mark Adler + (C) 1995-2024 Jean-loup Gailly and Mark Adler -This software is provided 'as-is', without any express or implied -warranty. In no event will the authors be held liable for any damages -arising from the use of this software. + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute it -freely, subject to the following restrictions: + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: -1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. -2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu -3. This notice may not be removed or altered from any source distribution. +If you use the zlib library in a product, we would appreciate *not* receiving +lengthy legal documents to sign. The sources are provided for free but without +warranty of any kind. The library has been entirely written by Jean-loup +Gailly and Mark Adler; it does not include third-party code. We make all +contributions to and distributions of this project solely in our personal +capacity, and are not conveying any rights to any intellectual property of +any third parties. + +If you redistribute modified sources, we would appreciate that you include in +the file ChangeLog history information documenting your changes. Please read +the FAQ for more information on the distribution of modified source versions. diff --git a/venv/Lib/site-packages/pillow-12.1.0.dist-info/METADATA b/venv/Lib/site-packages/pillow-10.4.0.dist-info/METADATA similarity index 77% rename from venv/Lib/site-packages/pillow-12.1.0.dist-info/METADATA rename to venv/Lib/site-packages/pillow-10.4.0.dist-info/METADATA index c147a64..79dc8f1 100644 --- a/venv/Lib/site-packages/pillow-12.1.0.dist-info/METADATA +++ b/venv/Lib/site-packages/pillow-10.4.0.dist-info/METADATA @@ -1,24 +1,25 @@ -Metadata-Version: 2.4 +Metadata-Version: 2.1 Name: pillow -Version: 12.1.0 -Summary: Python Imaging Library (fork) +Version: 10.4.0 +Summary: Python Imaging Library (Fork) Author-email: "Jeffrey A. Clark" -License-Expression: MIT-CMU -Project-URL: Changelog, https://github.com/python-pillow/Pillow/releases +License: HPND +Project-URL: Changelog, https://github.com/python-pillow/Pillow/blob/main/CHANGES.rst Project-URL: Documentation, https://pillow.readthedocs.io Project-URL: Funding, https://tidelift.com/subscription/pkg/pypi-pillow?utm_source=pypi-pillow&utm_medium=pypi -Project-URL: Homepage, https://python-pillow.github.io +Project-URL: Homepage, https://python-pillow.org Project-URL: Mastodon, https://fosstodon.org/@pillow Project-URL: Release notes, https://pillow.readthedocs.io/en/stable/releasenotes/index.html Project-URL: Source, https://github.com/python-pillow/Pillow Keywords: Imaging Classifier: Development Status :: 6 - Mature +Classifier: License :: OSI Approved :: Historical Permission Notice and Disclaimer (HPND) Classifier: Programming Language :: Python :: 3 :: Only +Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: 3.9 Classifier: Programming Language :: Python :: 3.10 Classifier: Programming Language :: Python :: 3.11 Classifier: Programming Language :: Python :: 3.12 -Classifier: Programming Language :: Python :: 3.13 -Classifier: Programming Language :: Python :: 3.14 Classifier: Programming Language :: Python :: Implementation :: CPython Classifier: Programming Language :: Python :: Implementation :: PyPy Classifier: Topic :: Multimedia :: Graphics @@ -27,42 +28,35 @@ Classifier: Topic :: Multimedia :: Graphics :: Capture :: Screen Capture Classifier: Topic :: Multimedia :: Graphics :: Graphics Conversion Classifier: Topic :: Multimedia :: Graphics :: Viewers Classifier: Typing :: Typed -Requires-Python: >=3.10 +Requires-Python: >=3.8 Description-Content-Type: text/markdown License-File: LICENSE Provides-Extra: docs -Requires-Dist: furo; extra == "docs" -Requires-Dist: olefile; extra == "docs" -Requires-Dist: sphinx>=8.2; extra == "docs" -Requires-Dist: sphinx-autobuild; extra == "docs" -Requires-Dist: sphinx-copybutton; extra == "docs" -Requires-Dist: sphinx-inline-tabs; extra == "docs" -Requires-Dist: sphinxext-opengraph; extra == "docs" +Requires-Dist: furo ; extra == 'docs' +Requires-Dist: olefile ; extra == 'docs' +Requires-Dist: sphinx >=7.3 ; extra == 'docs' +Requires-Dist: sphinx-copybutton ; extra == 'docs' +Requires-Dist: sphinx-inline-tabs ; extra == 'docs' +Requires-Dist: sphinxext-opengraph ; extra == 'docs' Provides-Extra: fpx -Requires-Dist: olefile; extra == "fpx" +Requires-Dist: olefile ; extra == 'fpx' Provides-Extra: mic -Requires-Dist: olefile; extra == "mic" -Provides-Extra: test-arrow -Requires-Dist: arro3-compute; extra == "test-arrow" -Requires-Dist: arro3-core; extra == "test-arrow" -Requires-Dist: nanoarrow; extra == "test-arrow" -Requires-Dist: pyarrow; extra == "test-arrow" +Requires-Dist: olefile ; extra == 'mic' Provides-Extra: tests -Requires-Dist: check-manifest; extra == "tests" -Requires-Dist: coverage>=7.4.2; extra == "tests" -Requires-Dist: defusedxml; extra == "tests" -Requires-Dist: markdown2; extra == "tests" -Requires-Dist: olefile; extra == "tests" -Requires-Dist: packaging; extra == "tests" -Requires-Dist: pyroma>=5; extra == "tests" -Requires-Dist: pytest; extra == "tests" -Requires-Dist: pytest-cov; extra == "tests" -Requires-Dist: pytest-timeout; extra == "tests" -Requires-Dist: pytest-xdist; extra == "tests" -Requires-Dist: trove-classifiers>=2024.10.12; extra == "tests" +Requires-Dist: check-manifest ; extra == 'tests' +Requires-Dist: coverage ; extra == 'tests' +Requires-Dist: defusedxml ; extra == 'tests' +Requires-Dist: markdown2 ; extra == 'tests' +Requires-Dist: olefile ; extra == 'tests' +Requires-Dist: packaging ; extra == 'tests' +Requires-Dist: pyroma ; extra == 'tests' +Requires-Dist: pytest ; extra == 'tests' +Requires-Dist: pytest-cov ; extra == 'tests' +Requires-Dist: pytest-timeout ; extra == 'tests' +Provides-Extra: typing +Requires-Dist: typing-extensions ; (python_version < "3.10") and extra == 'typing' Provides-Extra: xmp -Requires-Dist: defusedxml; extra == "xmp" -Dynamic: license-file +Requires-Dist: defusedxml ; extra == 'xmp'

Pillow logo @@ -102,16 +96,22 @@ As of 2019, Pillow development is GitHub Actions build status (Test MinGW) + GitHub Actions build status (Test Cygwin) GitHub Actions build status (Test Docker) + AppVeyor CI build status (Windows) GitHub Actions build status (Wheels) Code coverage - Fuzzing Status @@ -158,7 +158,7 @@ This library provides extensive file format support, an efficient internal repre The core image library is designed for fast access to data stored in a few basic pixel formats. It should provide a solid foundation for a general image processing tool. -## More information +## More Information - [Documentation](https://pillow.readthedocs.io/) - [Installation](https://pillow.readthedocs.io/en/latest/installation/basic-installation.html) @@ -167,9 +167,9 @@ The core image library is designed for fast access to data stored in a few basic - [Issues](https://github.com/python-pillow/Pillow/issues) - [Pull requests](https://github.com/python-pillow/Pillow/pulls) - [Release notes](https://pillow.readthedocs.io/en/stable/releasenotes/index.html) -- [Changelog](https://github.com/python-pillow/Pillow/releases) +- [Changelog](https://github.com/python-pillow/Pillow/blob/main/CHANGES.rst) - [Pre-fork](https://github.com/python-pillow/Pillow/blob/main/CHANGES.rst#pre-fork) -## Report a vulnerability +## Report a Vulnerability To report a security vulnerability, please follow the procedure described in the [Tidelift security policy](https://tidelift.com/docs/security). diff --git a/venv/Lib/site-packages/pillow-10.4.0.dist-info/RECORD b/venv/Lib/site-packages/pillow-10.4.0.dist-info/RECORD new file mode 100644 index 0000000..a0cef2d --- /dev/null +++ b/venv/Lib/site-packages/pillow-10.4.0.dist-info/RECORD @@ -0,0 +1,214 @@ +PIL/BdfFontFile.py,sha256=JJLBb0JZwTmSIIkqQoe2vzus-XTczN_O47DQneXKM1o,3610 +PIL/BlpImagePlugin.py,sha256=n7Eghktvwb6WVWouvrLMGzB66PiP6aPZaKwOzx_5ux0,16854 +PIL/BmpImagePlugin.py,sha256=CbsPOXskQNx7ZoIlloRNntrmBo0UkYkwlWrvwEhCSks,19054 +PIL/BufrStubImagePlugin.py,sha256=sY28XJU_Fu-UsbPpAoN-fN63FemmhCMi8rW5Kf9JioE,1829 +PIL/ContainerIO.py,sha256=BTz6Qlz-VyDmurXnWpQU-lAevLxgcsOcEGZP0CtvSKc,3302 +PIL/CurImagePlugin.py,sha256=3e6_djFaRvGO2PMP_E0HwbHx4SjqTlmlvPraNUFeLkQ,1839 +PIL/DcxImagePlugin.py,sha256=iaVs9updbtEstQKPLKKIlJVhfxFarbgCPoO8j96BmDA,2114 +PIL/DdsImagePlugin.py,sha256=dwlTfJcpUA9NAcWW6WoRjsexu_5xFTDYJhYuQnSLUJ4,17489 +PIL/EpsImagePlugin.py,sha256=I7DstQ6ZijJMglp6qEi1xljwY2bY4MkwWPWs0WPWM4Y,16614 +PIL/ExifTags.py,sha256=LA3OxhNImajSkIRnCMXDTJw4MprMEeFq_Sqf-sjn20w,10134 +PIL/FitsImagePlugin.py,sha256=ngEk16Ljz2K1f-Jz-KConyALGxVzFcVTEpWW1-VjVgw,4745 +PIL/FliImagePlugin.py,sha256=l8awoi3gN9gWsBonvjwDY-StXLSGnN6h5ZZg1S09Pjs,4785 +PIL/FontFile.py,sha256=iLSV32yQetLnE4SgG8HnHb2FdqkqFBjY9n--E6u5UE0,3711 +PIL/FpxImagePlugin.py,sha256=uecjqTuKyZHle3cg2VYpCthkIlfzVFnvDKBI3T6EdrA,7315 +PIL/FtexImagePlugin.py,sha256=KQwb4dvvnBxE4WOiuAjdougODgm67AsbYGWapChmDwU,3617 +PIL/GbrImagePlugin.py,sha256=KbLlo2oVhIbkzP7zQW0vARTE6aMjX6DpJEkghUny6Gk,3071 +PIL/GdImageFile.py,sha256=5SZA0952NckwJYsproC-ykj_UfVUjiGxNiohzRYf2fE,2897 +PIL/GifImagePlugin.py,sha256=eubRq9j9MVgEbJt0A4ARRBdIIoFjAkh5dheNJ0J27IA,40904 +PIL/GimpGradientFile.py,sha256=AFEEGWtylUg7tIYK0MgBC4hZHq3WxSzIvdq_MAEAUq8,4047 +PIL/GimpPaletteFile.py,sha256=EmKLnuvsHx0GLhWh8YnfidiTEhUm51-ZNKgQbAX1zcU,1485 +PIL/GribStubImagePlugin.py,sha256=Vf_VvZltyP3QqTuz-gUfCT6I2g3F5Rh8BYMGjxwpAoM,1823 +PIL/Hdf5StubImagePlugin.py,sha256=70vlB50QgPYYH2b8kE8U_QN5Q8TlmjmN8vk0FrhLkJ4,1826 +PIL/IcnsImagePlugin.py,sha256=U8sXlLVueqXHOVfzKS9ELsIZeH0cE5miFKMjAagK5fI,12405 +PIL/IcoImagePlugin.py,sha256=4OLIfifidVCQbA7VJpxH-VD-Ar0mzhIj8bFYP5rRO0o,12147 +PIL/ImImagePlugin.py,sha256=uI_xoDFxGetvSkcgER5IHtmebcQcQXV_1wRu4ztOS-A,11494 +PIL/Image.py,sha256=_J1nF9SELAzg188weTM0ozhnHj2WOPHJqXpyu56w5Ks,146669 +PIL/ImageChops.py,sha256=hZ8EPUPlQIzugsEedV8trkKX0jBCDGb6Cszma6ZeMZQ,8257 +PIL/ImageCms.py,sha256=W4juhbdt9eV_Zvf8WNO0oede2iCvUPZMtuFYy4cx9lA,43151 +PIL/ImageColor.py,sha256=KV-u7HnZWrrL3zuBAOLqerI-7vFcXTxdLeoaYVjsnwI,9761 +PIL/ImageDraw.py,sha256=QESkqodXPEg2Ao5-ZabcMkXLButss7h671RQPHV32ME,42528 +PIL/ImageDraw2.py,sha256=aRmS6VPTFa4vpnHMLb3oOowjYt1W8ij81x5HOi5kotE,6229 +PIL/ImageEnhance.py,sha256=xwj3y_MBWUJICjYc_l_8uIe7ZEtqUDyl9kQ0HQSQMTQ,3490 +PIL/ImageFile.py,sha256=HiDum7mPIxlp_bB80wIw8mhYbmatDhMQYysI44rHrNQ,25847 +PIL/ImageFilter.py,sha256=b-4kwg9GDMep01eRgwLlkWehHDioRHB-V3-pzpOZJ7g,19274 +PIL/ImageFont.py,sha256=5TWH1kzlMp0Ru5hsIEZQXoMOHLyQvvkQD_cFPwObQHc,63357 +PIL/ImageGrab.py,sha256=CJP_aZNA1mXU5dI77eElm4_Au198Uf7yVZ7Xw0BJ53s,6552 +PIL/ImageMath.py,sha256=Ib655EKVOMeVJ2x_yVt0xaM2D9kfpCv2dX9CsCwizCM,11835 +PIL/ImageMode.py,sha256=n4-2kSolyB7v2u6dXyIf3_vDL_LMvSNwhJvd9Do8cc8,2773 +PIL/ImageMorph.py,sha256=5hHeZAmow6sFHRQ9wocxVcS4CmYcOCl5KUkPYxhOb9g,8820 +PIL/ImageOps.py,sha256=RbcKwMwRLAv_UBwkmYfHRyv5aEKlcbTGsWMqcCgM0ek,25740 +PIL/ImagePalette.py,sha256=jpyVO1j7nty9pUiB2f3i0Ds6U9ED6rwTuGWwaYAQRzk,9254 +PIL/ImagePath.py,sha256=ZnnJuvQNtbKRhCmr61TEmEh1vVV5_90WMEPL8Opy5l8,391 +PIL/ImageQt.py,sha256=tAl3NtwgTofzQnUc6F9TUQRD2u2HQOeRDqG-PadVzMg,6111 +PIL/ImageSequence.py,sha256=jyVU7FmpmrvkBASsZIN-fI21g9DUcCzmSmj0FxS4Fng,2278 +PIL/ImageShow.py,sha256=m-XAcuWPFoz8Dv_JfaqrI5ZEvNIxMbDKa4Po5PcAZ9A,10391 +PIL/ImageStat.py,sha256=iA5KJrQeEpbwk-FhczGD8L4TaLWUt4VT_mp4drvMhv8,5485 +PIL/ImageTk.py,sha256=rRGvldzlOvqgiseGvMH-jgiMmY5wri4SJzkvXOb9uJ4,8893 +PIL/ImageTransform.py,sha256=xvHSE9-TtXtm_MilxVVf4dvB2-r7fJHhUFMJHFIs2PY,3994 +PIL/ImageWin.py,sha256=jz_6kBZWKyJsUhYKvdMsQUsCn7ZJZPIYqaZOBE3mD1E,7761 +PIL/ImtImagePlugin.py,sha256=TFLgRU0ko5gAxrsKUqGkK_Y8o233OVKLNJKE4IeOac8,2761 +PIL/IptcImagePlugin.py,sha256=I2H6QXywjOeGpDo-LOEgJ7vYhhjbGEJgFjN6bcY0sSU,6370 +PIL/Jpeg2KImagePlugin.py,sha256=P-2gvXFhjlDlKaWul8MXvQgQ19XzyeFHVh1fR_MgeLM,12809 +PIL/JpegImagePlugin.py,sha256=5wcd77uSne-bEFHqPW6psgXnKw7spmR3gjZh_LYdvbI,30720 +PIL/JpegPresets.py,sha256=0XoRcIdU_U1szfxfQEt_YgarmdB1INfTpbEgCanBbns,12664 +PIL/McIdasImagePlugin.py,sha256=KNmMyMzyaBz_pjUhtxi0Fjtj6MdjzrT-b1P_LgC10gg,1979 +PIL/MicImagePlugin.py,sha256=1mCwO0p5CJi_CXl3jFumdMxwd6vL11y0ckGjLayqPH8,2774 +PIL/MpegImagePlugin.py,sha256=SR-JGne4xNIrHTc1vKdEbuW61oI-TIar2oIP-MeRuiI,2188 +PIL/MpoImagePlugin.py,sha256=8jfsGFWqSx8D_ao9tPavMi45EWN7r080WnlZzyP7_2M,6027 +PIL/MspImagePlugin.py,sha256=widjELAylDoYtS2Dc-JPePA7AiBo0uakagOptWkPD20,6036 +PIL/PSDraw.py,sha256=L7W05HCqBKtZ271aEIPUheBzf0ZWcDgsXCvJUSMw3zc,7220 +PIL/PaletteFile.py,sha256=lNPfuBTHraW6i1v1b9thNoFyIG2MRMMzFHxVTaxcwj8,1265 +PIL/PalmImagePlugin.py,sha256=pxIMXUSRmuKUfbseT1K5dv7IqZTg_z5bphqC5PayF8E,9513 +PIL/PcdImagePlugin.py,sha256=F_8URHMLJxGt_MhONZzako6F3qYcC6RkUZrKgr0FjTM,1689 +PIL/PcfFontFile.py,sha256=RkM5wUp3SgRpQhpsTBEtk8uuFrQPnBSYBryOmcoRphQ,7401 +PIL/PcxImagePlugin.py,sha256=Rq_7JaTH7MqWfC8ZxBExYAPCAeJwOaZwh7Iarg1TGfM,6444 +PIL/PdfImagePlugin.py,sha256=Rk1HmJE0I2exdOuhK8nBe5CXaLkmllAeSnjajdXUq5c,9220 +PIL/PdfParser.py,sha256=89DQp0TI7XA3EXw0mWrJADD_9ySWb8yldRRWN4i2SwY,35872 +PIL/PixarImagePlugin.py,sha256=90zIgbzb8-bACCrJtQD2ubQmp_x5jGBOoWpjsS7Y038,1818 +PIL/PngImagePlugin.py,sha256=4NibeAP8zvqFQzPvNsP6stiHUXo5VnIFq5I0LRt6MCQ,50055 +PIL/PpmImagePlugin.py,sha256=bOOvSHAZHQ35WBSEYOW7YBFuIAkJuK2l5k5Geon_nF4,12587 +PIL/PsdImagePlugin.py,sha256=bfF5u2gW4shYgSmIhAx8Qyn03YaYOY8KoQtFtSeEWA0,8615 +PIL/PyAccess.py,sha256=vowudnRMgj8F9JvwHUsRzDV_szOtNommpH6SFH_bbzE,11224 +PIL/QoiImagePlugin.py,sha256=vm98aN1PTbNv192gN6onYmbgSgT5f0V_AY4fr3VLySw,4261 +PIL/SgiImagePlugin.py,sha256=RU265Sg7bEZN-TmU0M5E6ODfc4twjORx9oAD2fDsDQI,6683 +PIL/SpiderImagePlugin.py,sha256=aCERP7JRSeUDuzLfm9jnhxVNKEyehM_p-1xSLZLDG5o,10379 +PIL/SunImagePlugin.py,sha256=JT8IrJC7JIDBgdfIBzC-HSzxnoD4-W1aybpBDW0L0aU,4640 +PIL/TarIO.py,sha256=LzQZ1ZRCVxXQREFRodRn9J_d25zxnSklBKdVikjzMGw,1651 +PIL/TgaImagePlugin.py,sha256=Y48o5LSAAnNqthiC8nIBvOxyhPRemQfSZHKJMfiowT0,7204 +PIL/TiffImagePlugin.py,sha256=w1drQBgBaCo3ElhzWesV9TXrZHw9x8KiuKq6XE4d5hA,80428 +PIL/TiffTags.py,sha256=3sFYZ3VTzJcnCguPr_AIPYm7kT_sSdwqq5h10EKy0Ow,17270 +PIL/WalImageFile.py,sha256=emYeZjisXBBE_RhK-hh6XVuC9N94pua3mwVXKwQ3rYw,5687 +PIL/WebPImagePlugin.py,sha256=uHUch0U7vVAuCB9QSCHkPc6fZfdZRVdKe1vd8nbIsYY,11891 +PIL/WmfImagePlugin.py,sha256=Lj7genL51Fu3YXcSce0xmaWNiKwzB3NUsCa-iMrvs0Q,5164 +PIL/XVThumbImagePlugin.py,sha256=nlqdy2bGDbqG9Sl-62YQcfN0x8JAUgUQDo5a3CrNPQU,2162 +PIL/XbmImagePlugin.py,sha256=g7Q5A_2yV4U293ygm_1SoIbYHnie3vajkMbqHrPgR6A,2747 +PIL/XpmImagePlugin.py,sha256=1o0NGFfUTTvR7m8qDx1MAPeL22sJceEo5cdglBJzQYc,3344 +PIL/__init__.py,sha256=98abxVfn8od1jJaTIr65YrYrIb7zMKbOJ5o68ryE2O0,2094 +PIL/__main__.py,sha256=X8eIpGlmHfnp7zazp5mdav228Itcf2lkiMP0tLU6X9c,140 +PIL/__pycache__/BdfFontFile.cpython-312.pyc,, +PIL/__pycache__/BlpImagePlugin.cpython-312.pyc,, +PIL/__pycache__/BmpImagePlugin.cpython-312.pyc,, +PIL/__pycache__/BufrStubImagePlugin.cpython-312.pyc,, +PIL/__pycache__/ContainerIO.cpython-312.pyc,, +PIL/__pycache__/CurImagePlugin.cpython-312.pyc,, +PIL/__pycache__/DcxImagePlugin.cpython-312.pyc,, +PIL/__pycache__/DdsImagePlugin.cpython-312.pyc,, +PIL/__pycache__/EpsImagePlugin.cpython-312.pyc,, +PIL/__pycache__/ExifTags.cpython-312.pyc,, +PIL/__pycache__/FitsImagePlugin.cpython-312.pyc,, +PIL/__pycache__/FliImagePlugin.cpython-312.pyc,, +PIL/__pycache__/FontFile.cpython-312.pyc,, +PIL/__pycache__/FpxImagePlugin.cpython-312.pyc,, +PIL/__pycache__/FtexImagePlugin.cpython-312.pyc,, +PIL/__pycache__/GbrImagePlugin.cpython-312.pyc,, +PIL/__pycache__/GdImageFile.cpython-312.pyc,, +PIL/__pycache__/GifImagePlugin.cpython-312.pyc,, +PIL/__pycache__/GimpGradientFile.cpython-312.pyc,, +PIL/__pycache__/GimpPaletteFile.cpython-312.pyc,, +PIL/__pycache__/GribStubImagePlugin.cpython-312.pyc,, +PIL/__pycache__/Hdf5StubImagePlugin.cpython-312.pyc,, +PIL/__pycache__/IcnsImagePlugin.cpython-312.pyc,, +PIL/__pycache__/IcoImagePlugin.cpython-312.pyc,, +PIL/__pycache__/ImImagePlugin.cpython-312.pyc,, +PIL/__pycache__/Image.cpython-312.pyc,, +PIL/__pycache__/ImageChops.cpython-312.pyc,, +PIL/__pycache__/ImageCms.cpython-312.pyc,, +PIL/__pycache__/ImageColor.cpython-312.pyc,, +PIL/__pycache__/ImageDraw.cpython-312.pyc,, +PIL/__pycache__/ImageDraw2.cpython-312.pyc,, +PIL/__pycache__/ImageEnhance.cpython-312.pyc,, +PIL/__pycache__/ImageFile.cpython-312.pyc,, +PIL/__pycache__/ImageFilter.cpython-312.pyc,, +PIL/__pycache__/ImageFont.cpython-312.pyc,, +PIL/__pycache__/ImageGrab.cpython-312.pyc,, +PIL/__pycache__/ImageMath.cpython-312.pyc,, +PIL/__pycache__/ImageMode.cpython-312.pyc,, +PIL/__pycache__/ImageMorph.cpython-312.pyc,, +PIL/__pycache__/ImageOps.cpython-312.pyc,, +PIL/__pycache__/ImagePalette.cpython-312.pyc,, +PIL/__pycache__/ImagePath.cpython-312.pyc,, +PIL/__pycache__/ImageQt.cpython-312.pyc,, +PIL/__pycache__/ImageSequence.cpython-312.pyc,, +PIL/__pycache__/ImageShow.cpython-312.pyc,, +PIL/__pycache__/ImageStat.cpython-312.pyc,, +PIL/__pycache__/ImageTk.cpython-312.pyc,, +PIL/__pycache__/ImageTransform.cpython-312.pyc,, +PIL/__pycache__/ImageWin.cpython-312.pyc,, +PIL/__pycache__/ImtImagePlugin.cpython-312.pyc,, +PIL/__pycache__/IptcImagePlugin.cpython-312.pyc,, +PIL/__pycache__/Jpeg2KImagePlugin.cpython-312.pyc,, +PIL/__pycache__/JpegImagePlugin.cpython-312.pyc,, +PIL/__pycache__/JpegPresets.cpython-312.pyc,, +PIL/__pycache__/McIdasImagePlugin.cpython-312.pyc,, +PIL/__pycache__/MicImagePlugin.cpython-312.pyc,, +PIL/__pycache__/MpegImagePlugin.cpython-312.pyc,, +PIL/__pycache__/MpoImagePlugin.cpython-312.pyc,, +PIL/__pycache__/MspImagePlugin.cpython-312.pyc,, +PIL/__pycache__/PSDraw.cpython-312.pyc,, +PIL/__pycache__/PaletteFile.cpython-312.pyc,, +PIL/__pycache__/PalmImagePlugin.cpython-312.pyc,, +PIL/__pycache__/PcdImagePlugin.cpython-312.pyc,, +PIL/__pycache__/PcfFontFile.cpython-312.pyc,, +PIL/__pycache__/PcxImagePlugin.cpython-312.pyc,, +PIL/__pycache__/PdfImagePlugin.cpython-312.pyc,, +PIL/__pycache__/PdfParser.cpython-312.pyc,, +PIL/__pycache__/PixarImagePlugin.cpython-312.pyc,, +PIL/__pycache__/PngImagePlugin.cpython-312.pyc,, +PIL/__pycache__/PpmImagePlugin.cpython-312.pyc,, +PIL/__pycache__/PsdImagePlugin.cpython-312.pyc,, +PIL/__pycache__/PyAccess.cpython-312.pyc,, +PIL/__pycache__/QoiImagePlugin.cpython-312.pyc,, +PIL/__pycache__/SgiImagePlugin.cpython-312.pyc,, +PIL/__pycache__/SpiderImagePlugin.cpython-312.pyc,, +PIL/__pycache__/SunImagePlugin.cpython-312.pyc,, +PIL/__pycache__/TarIO.cpython-312.pyc,, +PIL/__pycache__/TgaImagePlugin.cpython-312.pyc,, +PIL/__pycache__/TiffImagePlugin.cpython-312.pyc,, +PIL/__pycache__/TiffTags.cpython-312.pyc,, +PIL/__pycache__/WalImageFile.cpython-312.pyc,, +PIL/__pycache__/WebPImagePlugin.cpython-312.pyc,, +PIL/__pycache__/WmfImagePlugin.cpython-312.pyc,, +PIL/__pycache__/XVThumbImagePlugin.cpython-312.pyc,, +PIL/__pycache__/XbmImagePlugin.cpython-312.pyc,, +PIL/__pycache__/XpmImagePlugin.cpython-312.pyc,, +PIL/__pycache__/__init__.cpython-312.pyc,, +PIL/__pycache__/__main__.cpython-312.pyc,, +PIL/__pycache__/_binary.cpython-312.pyc,, +PIL/__pycache__/_deprecate.cpython-312.pyc,, +PIL/__pycache__/_tkinter_finder.cpython-312.pyc,, +PIL/__pycache__/_typing.cpython-312.pyc,, +PIL/__pycache__/_util.cpython-312.pyc,, +PIL/__pycache__/_version.cpython-312.pyc,, +PIL/__pycache__/features.cpython-312.pyc,, +PIL/__pycache__/report.cpython-312.pyc,, +PIL/_binary.py,sha256=cb9p-_mwzBYumlVsWbnoTWsrLo59towA6atLOZvjO3w,2662 +PIL/_deprecate.py,sha256=5WrrZE3Q65nRF3pwwRN9wsmY4lqFOJayT6Uxt-i9tf0,2071 +PIL/_imaging.cp312-win_amd64.pyd,sha256=_63GKSKqx_k9Tsby60HNg2EE-I2GtF6fwpUIf619Ji4,2343424 +PIL/_imaging.pyi,sha256=wjkxIX-PkUYnjQCdcvR3wcrZG9KEUL5m_L33Zw4W79A,846 +PIL/_imagingcms.cp312-win_amd64.pyd,sha256=kdDUccUM_Mn9hoiuI1BHdAi7mH5nocX1CNF8XdAhMU8,262656 +PIL/_imagingcms.pyi,sha256=-1QgyLqhW56OLsu8Kgn9wc8IifLldpOuCRILf8SBfsE,4480 +PIL/_imagingft.cp312-win_amd64.pyd,sha256=7WK4kCjDEn_HsW4283_8_4jhVwdEL94BjUC76glvW4Y,1819648 +PIL/_imagingft.pyi,sha256=SpEugAoNqOCdmR-bAghPf0AWfBpMfziUnXkJ65jY4dc,1748 +PIL/_imagingmath.cp312-win_amd64.pyd,sha256=xIDtxOvVdXuS9UOwWJrwxv6_EVOZK5SDIrfmnyoOr2E,24064 +PIL/_imagingmath.pyi,sha256=zD8vAoPC8aEIVjfckLtFskRW5saiVel3-sJUA2pHaGc,66 +PIL/_imagingmorph.cp312-win_amd64.pyd,sha256=hLY-Sk96yrJgmeWywyG0OrRODEvrEQDk6YMi7QMxQgc,13824 +PIL/_imagingmorph.pyi,sha256=zD8vAoPC8aEIVjfckLtFskRW5saiVel3-sJUA2pHaGc,66 +PIL/_imagingtk.cp312-win_amd64.pyd,sha256=MX5CGd4SLwWMhvhY8RuVELbRlv2AJ901NS53hOaWhQA,14848 +PIL/_tkinter_finder.py,sha256=jKydPAxnrytggsZQHB6kAQep6A9kzRNyx_nToT4ClKY,561 +PIL/_typing.py,sha256=ZEXNlEU-TV_Dl1RPO7Nx74CQQbrI6BGP-cDnRKWIrRQ,890 +PIL/_util.py,sha256=ifUUlojtqTnWOxQFrwNCpqO1gjzkFIWovj7uBnq6DrY,844 +PIL/_version.py,sha256=h4GziQDuM-Mtj--2-J-vf3al0vVtouQhTpAQOKexxWA,91 +PIL/_webp.cp312-win_amd64.pyd,sha256=eIlmcuLNg0Zxfwbv7VUTR7MVjcEKrsL8YQccF5HAZDc,412160 +PIL/_webp.pyi,sha256=zD8vAoPC8aEIVjfckLtFskRW5saiVel3-sJUA2pHaGc,66 +PIL/features.py,sha256=UD4iRB2Hs4mR0odVOLJ1aLz_5YbGsBkL01-RO3oyrDk,10853 +PIL/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +PIL/report.py,sha256=6m7NOv1a24577ZiJoxX89ip5JeOgf2O1F95f6-1K5aM,105 +pillow-10.4.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +pillow-10.4.0.dist-info/LICENSE,sha256=PFOBLi0mO1BbpKT2CpPZY3wmU-ISYDhlFccrXMtYqJ4,56937 +pillow-10.4.0.dist-info/METADATA,sha256=EfTKW2FZO1afRRUC0aehHiVIUjsDtNAOIqNbPn_0Bac,9342 +pillow-10.4.0.dist-info/RECORD,, +pillow-10.4.0.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +pillow-10.4.0.dist-info/WHEEL,sha256=3x_bcW68bUAcconjAL7QQrdN9TajBLCHyHJA2sbOuIc,101 +pillow-10.4.0.dist-info/top_level.txt,sha256=riZqrk-hyZqh5f1Z0Zwii3dKfxEsByhu9cU9IODF-NY,4 +pillow-10.4.0.dist-info/zip-safe,sha256=frcCV1k9oG9oKj3dpUqdJg1PxRT2RSN_XKdLCPjaYaY,2 diff --git a/venv/Lib/site-packages/pillow-10.4.0.dist-info/REQUESTED b/venv/Lib/site-packages/pillow-10.4.0.dist-info/REQUESTED new file mode 100644 index 0000000..e69de29 diff --git a/venv/Lib/site-packages/pillow-12.1.0.dist-info/WHEEL b/venv/Lib/site-packages/pillow-10.4.0.dist-info/WHEEL similarity index 69% rename from venv/Lib/site-packages/pillow-12.1.0.dist-info/WHEEL rename to venv/Lib/site-packages/pillow-10.4.0.dist-info/WHEEL index 10ac2c2..3e8d5a5 100644 --- a/venv/Lib/site-packages/pillow-12.1.0.dist-info/WHEEL +++ b/venv/Lib/site-packages/pillow-10.4.0.dist-info/WHEEL @@ -1,5 +1,5 @@ Wheel-Version: 1.0 -Generator: setuptools (80.9.0) +Generator: setuptools (70.1.1) Root-Is-Purelib: false Tag: cp312-cp312-win_amd64 diff --git a/venv/Lib/site-packages/pillow-12.1.0.dist-info/top_level.txt b/venv/Lib/site-packages/pillow-10.4.0.dist-info/top_level.txt similarity index 100% rename from venv/Lib/site-packages/pillow-12.1.0.dist-info/top_level.txt rename to venv/Lib/site-packages/pillow-10.4.0.dist-info/top_level.txt diff --git a/venv/Lib/site-packages/pillow-12.1.0.dist-info/zip-safe b/venv/Lib/site-packages/pillow-10.4.0.dist-info/zip-safe similarity index 100% rename from venv/Lib/site-packages/pillow-12.1.0.dist-info/zip-safe rename to venv/Lib/site-packages/pillow-10.4.0.dist-info/zip-safe diff --git a/venv/Lib/site-packages/pillow-12.1.0.dist-info/RECORD b/venv/Lib/site-packages/pillow-12.1.0.dist-info/RECORD deleted file mode 100644 index f66bbc7..0000000 --- a/venv/Lib/site-packages/pillow-12.1.0.dist-info/RECORD +++ /dev/null @@ -1,219 +0,0 @@ -PIL/AvifImagePlugin.py,sha256=YCw3mGsZiu8LDpu8eUZuf4o-7nuPTOW6CFA6FIPkWTM,9323 -PIL/BdfFontFile.py,sha256=bApbMl2vYRceQKIkSDFa002Ywr9laVrp2NGK9xzlS_8,3407 -PIL/BlpImagePlugin.py,sha256=EpHoVShYXypqxnEoiSShngD7CPhCeY8efwSH1G5lnXk,17066 -PIL/BmpImagePlugin.py,sha256=NMzi6fiFZSUxIuYQRIoOWUotdPXpXZS8zWBybS3Kd-w,20442 -PIL/BufrStubImagePlugin.py,sha256=uU9nG6QHnuKeqZKd8nARlWPU6oa215Y1DXlmdqKbnMI,1841 -PIL/ContainerIO.py,sha256=I6yO_YFEEqMKA1ckgEEzF2r_Ik5p_GjM-RrWOJYjSlY,4777 -PIL/CurImagePlugin.py,sha256=O_bFtW82YhAM8_F8tpr3O5UrzKPPyiV9S2zjV9QwqaI,1866 -PIL/DcxImagePlugin.py,sha256=L21c3gVX6IPmk4zuf_ltt3mAeRfcuCCcXhkCVpued2U,2264 -PIL/DdsImagePlugin.py,sha256=2JxzvTsnaiaE5xWE-bUjNjuuN6HjhCaVuozY74Ml9YU,19556 -PIL/EpsImagePlugin.py,sha256=5cHzzxj1vUffcLYr-MEO5Tk1zTeLY4M_tMN8bwDUxpo,17107 -PIL/ExifTags.py,sha256=xG6PuZIJSXk7bfkBfXh11YgKlWVkF1HWQ_I7XywFBMs,10313 -PIL/FitsImagePlugin.py,sha256=v4peLA6wIdySjHBzDMzVI5UWx8zr0jI2A3qYZSaMixs,4796 -PIL/FliImagePlugin.py,sha256=L1vf4QjsaMV0eRQTmfy1wnqJ9l9hGV5lvTILW7znzD8,5113 -PIL/FontFile.py,sha256=iLSV32yQetLnE4SgG8HnHb2FdqkqFBjY9n--E6u5UE0,3711 -PIL/FpxImagePlugin.py,sha256=4NAdiIuZ_VF6OXraYCt12vzQqEhEJSu7s3aaMlxDFpQ,7622 -PIL/FtexImagePlugin.py,sha256=-zKvvhMTczUe3o0f4HpDC9_DK6lKHT5LABf0r5-3l-4,3685 -PIL/GbrImagePlugin.py,sha256=Ib_y35ZzNOmMqG2SuOyjxRh3Oxt42QpcEcgLa6BhmtA,3156 -PIL/GdImageFile.py,sha256=LjMalK77Vw9U5pBH4KQlbi2PaIr73u9DqtxN58O1rBs,2890 -PIL/GifImagePlugin.py,sha256=1RCh0bWIxh_VcF8ztTlzfBHthuzEoLylrWE9QRpnDSU,43521 -PIL/GimpGradientFile.py,sha256=kbXZojJsokKBAgd_KOX9LAk2aabIIWJpdwZ16eKvxTc,4135 -PIL/GimpPaletteFile.py,sha256=EmBHcQ9ExC4f47taD7S7G6VaMkr9HjynlV8NdTXV5iQ,1935 -PIL/GribStubImagePlugin.py,sha256=Nyp5h5l-fwgBg6KBYXB6wqxZWAIz6Q-2e2sTelDbfu0,1870 -PIL/Hdf5StubImagePlugin.py,sha256=oCnXpfLPCRzc5vra6YcbH9vHLXy_iQWbja1d0Pl-SgM,1852 -PIL/IcnsImagePlugin.py,sha256=WW6GT0jcYcG_M7t-ab2xSb9SMJCvjsp51lIvfgSSvGE,12842 -PIL/IcoImagePlugin.py,sha256=DZoBj2zKv76Sk96PKq8el9aZAM2J3wULVqPeono_0z0,13499 -PIL/ImImagePlugin.py,sha256=X9iBSQ4x7rauxbOIn72j7v6TAUgZldpYD5cAc6Z1MNA,11992 -PIL/Image.py,sha256=Ry-wtI-imqrosqofZIAHl5-ORJC5eY0bjIdwlWUCP-w,153145 -PIL/ImageChops.py,sha256=hZ8EPUPlQIzugsEedV8trkKX0jBCDGb6Cszma6ZeMZQ,8257 -PIL/ImageCms.py,sha256=5rDN-FiLHebKlWP2kN6jbvDEF9jcb3somkBaDX8dFbs,41752 -PIL/ImageColor.py,sha256=KV-u7HnZWrrL3zuBAOLqerI-7vFcXTxdLeoaYVjsnwI,9761 -PIL/ImageDraw.py,sha256=-CJ7HMpnvaj2WynZ8OaUoN5jC2Qz_RiGeoV4YgIESeE,37323 -PIL/ImageDraw2.py,sha256=_e6I2nPxeiZwjOjBEJzUvxoyAklzmc-xF6R8z8ieOAA,7470 -PIL/ImageEnhance.py,sha256=ugDU0sljaR_zaTibtumlTvf-qFH1x1W6l2QMpc386XU,3740 -PIL/ImageFile.py,sha256=E8DXKovcC9h3lhATOkteYTsvz4_2uw0eWz4PlgVsFCE,30910 -PIL/ImageFilter.py,sha256=n3aT1MkbKrqGPeoSuqxmWliVqhkhOgLZ3ixjLn8vqK8,19336 -PIL/ImageFont.py,sha256=GnOo5yNj0DDRdIpyXEI-0lHktGvpgAzF7W9sEwKZiiI,64573 -PIL/ImageGrab.py,sha256=VKmorGPVfWYGNOIcYSEzLsAiOFvAhNN2EQULC4loomY,7974 -PIL/ImageMath.py,sha256=xhGBhvet2v7bgyLRl_adzVWnmZ7zVcbT8d1q1cpJHFI,10683 -PIL/ImageMode.py,sha256=ULkA-jsCgGwxVjr2LPSP42dDmj6nWaQk9L4UKj7KfSg,2480 -PIL/ImageMorph.py,sha256=Vr1QQB5vGYpGVffRGJQod4H7_AlQmO3l-BlhpaYeDyI,10673 -PIL/ImageOps.py,sha256=0Qc0PTg5r8t8JSgaKkzd-cjYMGtMUUMSBkXmmaJm-JU,26313 -PIL/ImagePalette.py,sha256=twVKqJFi6SEys_r7bVuhaaoPTdi3Kmjc2lHAQcCAZNs,9379 -PIL/ImagePath.py,sha256=ZnnJuvQNtbKRhCmr61TEmEh1vVV5_90WMEPL8Opy5l8,391 -PIL/ImageQt.py,sha256=SpxHePgWh5gdjVIGNC4GG5v9V3smQm_nPiJDcrhnHXc,6903 -PIL/ImageSequence.py,sha256=guZHUdpWrznzZkcY0OYpDzuF0uFXlCEu260oP-7e_fI,2341 -PIL/ImageShow.py,sha256=TqO6nzj5EMwp5dExag3jhBJXdHojccnFx59LOnMQao0,10468 -PIL/ImageStat.py,sha256=W0uUa8YNC6vhowlerSzZIwE7Ru-Kp2rWuqGNLBFLZyo,5662 -PIL/ImageText.py,sha256=YhgNTRumUFlkkklHZqLl58TyRCY2BkFRPewQXmL3yDQ,12440 -PIL/ImageTk.py,sha256=Tx0zf9kTaBuAGvZuo0JAHrNbk3n6ewr4ZndWnWxZK0Q,8398 -PIL/ImageTransform.py,sha256=Zu6oySXENtq712-nkqFLqafYPviRAgsgkzfLWG0K3V8,4052 -PIL/ImageWin.py,sha256=b-fO6kn4icHpy-zk-Xg-nO382zPXl-MKjZcs3vAXl1Q,8332 -PIL/ImtImagePlugin.py,sha256=r-ZDz3Xji6EBF8eUnK6iuCEZEtllp0xLRSIQ0_h14UE,2768 -PIL/IptcImagePlugin.py,sha256=Agv0WZN3tQWP5X9f_tkoFFKgv7BTdnkQ_AK328VxdGM,6812 -PIL/Jpeg2KImagePlugin.py,sha256=Lji_F42Lk5gIiKSnkDbyI11mp38aVg8uImFIWuaMSgk,14450 -PIL/JpegImagePlugin.py,sha256=Bv1zgkVZCBUzmEYMJaGZsT60Imrr62eZ8zrKrW6zLf0,32438 -PIL/JpegPresets.py,sha256=UUIsKzvyzdPzsndODd90eu_luMqauG1PJh10UOuQvmg,12621 -PIL/McIdasImagePlugin.py,sha256=P9d1kr4Ste0QVkxfqix31sfGD8sWn-eVmYK0wg6DvIw,1955 -PIL/MicImagePlugin.py,sha256=uCxGM4llIFPjfu2Kji-zSnPacnqiGUZGqs_Dtb3JktI,2702 -PIL/MpegImagePlugin.py,sha256=kem9zofsBtIq6xlMJcsFkOXTcJCPEICk9lchTfR9pDI,2094 -PIL/MpoImagePlugin.py,sha256=zec5axNlRwIWfX1-ZXzDi1u6AcSJUGbBPsPis54TXaU,6996 -PIL/MspImagePlugin.py,sha256=W8ruM60OZUbiPuUBQ7BBkFzkl1fiaPEvsvRMyNrg18A,6092 -PIL/PSDraw.py,sha256=uAr-Mg5j9_G3RLwWx4_J1wutJg_DVeDAE4qWd3Mvi9U,7155 -PIL/PaletteFile.py,sha256=QdEa99jLC-PPhEqGy6_4fDua8TzKSSUzkAeYcClFX7M,1270 -PIL/PalmImagePlugin.py,sha256=fNIhWH06V35uLgwIHUMMc_2xumelIEJsmCwhw2whBxI,8965 -PIL/PcdImagePlugin.py,sha256=gZsCcXDIqEVTK2z-GWKptT25pFU1AUOgpr3J06cjPCg,1842 -PIL/PcfFontFile.py,sha256=LaEuaKkGaahzjCkS7P7JbdoO4XQB9x7Njc3xdvAbokg,7481 -PIL/PcxImagePlugin.py,sha256=OiNiWX24k5atXZJNbS0XLxp-EiklJAwyuZKuk9jxqKE,6473 -PIL/PdfImagePlugin.py,sha256=gJMr0sSEWzyn7LnK5P5WQI995Cu_l-W3T8FX4jVgYf8,9632 -PIL/PdfParser.py,sha256=0jyauisa3VbAXxintmxjbSdw7m1xuaAQbit-9ytu_BM,39071 -PIL/PixarImagePlugin.py,sha256=-RnuJSGhGF8MsUsiHZq3VzBxV-BNnK35kBjJfhYzwXs,1830 -PIL/PngImagePlugin.py,sha256=JDJQ7Efeqkgvg8Ye7ciq7PQxayguHDAxldkCADUr8ws,53285 -PIL/PpmImagePlugin.py,sha256=WhtClGFMAO8VZZU9mFBZfMj7DbkytZ8XP7nQbVtZN5U,12766 -PIL/PsdImagePlugin.py,sha256=fDKVzMolUjVlAgS9eZpBZg53D6nuQQWKCmYlEWThslc,9054 -PIL/QoiImagePlugin.py,sha256=XKWT6v5f7l_3WmTWxbmmNWsMkzl5j-Uh5pnJwV2ybFg,8842 -PIL/SgiImagePlugin.py,sha256=w1xV4-ELYBHKL_AaGf9oJSYJzBwTpdJ-rNPqiArKgGs,6620 -PIL/SpiderImagePlugin.py,sha256=J3VxtBF-SqeYieu87IWKO34JXRhnRcLodTmT5J_Qsck,10638 -PIL/SunImagePlugin.py,sha256=YKYEvuG4QUkies34OKtXWKTYSZ8U3qzcE_vdTrOuRsw,4734 -PIL/TarIO.py,sha256=K6tLkFDcaar3vb6EyYb7G4oVEB41x_LMuGJeUT9w5DQ,1503 -PIL/TgaImagePlugin.py,sha256=OMvZn_xKjB1dZ1_4MkOquzJBHpSUIpAf5mUEJZiLBTI,7244 -PIL/TiffImagePlugin.py,sha256=lCVGTYQHxNxjcKcEmk2NmAgoheHroJ9NONncOXAeEU0,87340 -PIL/TiffTags.py,sha256=FsdqbIQJOI7ihG7MZ_K4YUQDZ4zo-raYbihVDe42U9E,17772 -PIL/WalImageFile.py,sha256=paHkgmmgW2_LXggPSTxhPiRxW-6B2wBKRW3GFO70Pck,5889 -PIL/WebPImagePlugin.py,sha256=mqdblF3URZ_V2dijWXtloM328_Ja-txMUervzEVI0Wk,10171 -PIL/WmfImagePlugin.py,sha256=i8w7nN1KC1TbGiz04PlN1hw3bERdK39dYkJ-xLQdCpY,5504 -PIL/XVThumbImagePlugin.py,sha256=OEtEhQgCLLgvx8J1iI911TMzjJ5iTlOOqQpLQx1bzQ4,2209 -PIL/XbmImagePlugin.py,sha256=wc0NpfTzlShx9Ymi0zwo0aVZjDa4_B7NEiG2TgCO65Q,2767 -PIL/XpmImagePlugin.py,sha256=wYf7Q7TGo4JL6n5ouQx8pbTMnMZVshgp-xwoAMZEUKg,4557 -PIL/__init__.py,sha256=Z-sXBmtIAVmDwqwBdI6L4RWjWxcgVvQ3v4SG0NxKeWU,2118 -PIL/__main__.py,sha256=X8eIpGlmHfnp7zazp5mdav228Itcf2lkiMP0tLU6X9c,140 -PIL/__pycache__/AvifImagePlugin.cpython-312.pyc,, -PIL/__pycache__/BdfFontFile.cpython-312.pyc,, -PIL/__pycache__/BlpImagePlugin.cpython-312.pyc,, -PIL/__pycache__/BmpImagePlugin.cpython-312.pyc,, -PIL/__pycache__/BufrStubImagePlugin.cpython-312.pyc,, -PIL/__pycache__/ContainerIO.cpython-312.pyc,, -PIL/__pycache__/CurImagePlugin.cpython-312.pyc,, -PIL/__pycache__/DcxImagePlugin.cpython-312.pyc,, -PIL/__pycache__/DdsImagePlugin.cpython-312.pyc,, -PIL/__pycache__/EpsImagePlugin.cpython-312.pyc,, -PIL/__pycache__/ExifTags.cpython-312.pyc,, -PIL/__pycache__/FitsImagePlugin.cpython-312.pyc,, -PIL/__pycache__/FliImagePlugin.cpython-312.pyc,, -PIL/__pycache__/FontFile.cpython-312.pyc,, -PIL/__pycache__/FpxImagePlugin.cpython-312.pyc,, -PIL/__pycache__/FtexImagePlugin.cpython-312.pyc,, -PIL/__pycache__/GbrImagePlugin.cpython-312.pyc,, -PIL/__pycache__/GdImageFile.cpython-312.pyc,, -PIL/__pycache__/GifImagePlugin.cpython-312.pyc,, -PIL/__pycache__/GimpGradientFile.cpython-312.pyc,, -PIL/__pycache__/GimpPaletteFile.cpython-312.pyc,, -PIL/__pycache__/GribStubImagePlugin.cpython-312.pyc,, -PIL/__pycache__/Hdf5StubImagePlugin.cpython-312.pyc,, -PIL/__pycache__/IcnsImagePlugin.cpython-312.pyc,, -PIL/__pycache__/IcoImagePlugin.cpython-312.pyc,, -PIL/__pycache__/ImImagePlugin.cpython-312.pyc,, -PIL/__pycache__/Image.cpython-312.pyc,, -PIL/__pycache__/ImageChops.cpython-312.pyc,, -PIL/__pycache__/ImageCms.cpython-312.pyc,, -PIL/__pycache__/ImageColor.cpython-312.pyc,, -PIL/__pycache__/ImageDraw.cpython-312.pyc,, -PIL/__pycache__/ImageDraw2.cpython-312.pyc,, -PIL/__pycache__/ImageEnhance.cpython-312.pyc,, -PIL/__pycache__/ImageFile.cpython-312.pyc,, -PIL/__pycache__/ImageFilter.cpython-312.pyc,, -PIL/__pycache__/ImageFont.cpython-312.pyc,, -PIL/__pycache__/ImageGrab.cpython-312.pyc,, -PIL/__pycache__/ImageMath.cpython-312.pyc,, -PIL/__pycache__/ImageMode.cpython-312.pyc,, -PIL/__pycache__/ImageMorph.cpython-312.pyc,, -PIL/__pycache__/ImageOps.cpython-312.pyc,, -PIL/__pycache__/ImagePalette.cpython-312.pyc,, -PIL/__pycache__/ImagePath.cpython-312.pyc,, -PIL/__pycache__/ImageQt.cpython-312.pyc,, -PIL/__pycache__/ImageSequence.cpython-312.pyc,, -PIL/__pycache__/ImageShow.cpython-312.pyc,, -PIL/__pycache__/ImageStat.cpython-312.pyc,, -PIL/__pycache__/ImageText.cpython-312.pyc,, -PIL/__pycache__/ImageTk.cpython-312.pyc,, -PIL/__pycache__/ImageTransform.cpython-312.pyc,, -PIL/__pycache__/ImageWin.cpython-312.pyc,, -PIL/__pycache__/ImtImagePlugin.cpython-312.pyc,, -PIL/__pycache__/IptcImagePlugin.cpython-312.pyc,, -PIL/__pycache__/Jpeg2KImagePlugin.cpython-312.pyc,, -PIL/__pycache__/JpegImagePlugin.cpython-312.pyc,, -PIL/__pycache__/JpegPresets.cpython-312.pyc,, -PIL/__pycache__/McIdasImagePlugin.cpython-312.pyc,, -PIL/__pycache__/MicImagePlugin.cpython-312.pyc,, -PIL/__pycache__/MpegImagePlugin.cpython-312.pyc,, -PIL/__pycache__/MpoImagePlugin.cpython-312.pyc,, -PIL/__pycache__/MspImagePlugin.cpython-312.pyc,, -PIL/__pycache__/PSDraw.cpython-312.pyc,, -PIL/__pycache__/PaletteFile.cpython-312.pyc,, -PIL/__pycache__/PalmImagePlugin.cpython-312.pyc,, -PIL/__pycache__/PcdImagePlugin.cpython-312.pyc,, -PIL/__pycache__/PcfFontFile.cpython-312.pyc,, -PIL/__pycache__/PcxImagePlugin.cpython-312.pyc,, -PIL/__pycache__/PdfImagePlugin.cpython-312.pyc,, -PIL/__pycache__/PdfParser.cpython-312.pyc,, -PIL/__pycache__/PixarImagePlugin.cpython-312.pyc,, -PIL/__pycache__/PngImagePlugin.cpython-312.pyc,, -PIL/__pycache__/PpmImagePlugin.cpython-312.pyc,, -PIL/__pycache__/PsdImagePlugin.cpython-312.pyc,, -PIL/__pycache__/QoiImagePlugin.cpython-312.pyc,, -PIL/__pycache__/SgiImagePlugin.cpython-312.pyc,, -PIL/__pycache__/SpiderImagePlugin.cpython-312.pyc,, -PIL/__pycache__/SunImagePlugin.cpython-312.pyc,, -PIL/__pycache__/TarIO.cpython-312.pyc,, -PIL/__pycache__/TgaImagePlugin.cpython-312.pyc,, -PIL/__pycache__/TiffImagePlugin.cpython-312.pyc,, -PIL/__pycache__/TiffTags.cpython-312.pyc,, -PIL/__pycache__/WalImageFile.cpython-312.pyc,, -PIL/__pycache__/WebPImagePlugin.cpython-312.pyc,, -PIL/__pycache__/WmfImagePlugin.cpython-312.pyc,, -PIL/__pycache__/XVThumbImagePlugin.cpython-312.pyc,, -PIL/__pycache__/XbmImagePlugin.cpython-312.pyc,, -PIL/__pycache__/XpmImagePlugin.cpython-312.pyc,, -PIL/__pycache__/__init__.cpython-312.pyc,, -PIL/__pycache__/__main__.cpython-312.pyc,, -PIL/__pycache__/_binary.cpython-312.pyc,, -PIL/__pycache__/_deprecate.cpython-312.pyc,, -PIL/__pycache__/_tkinter_finder.cpython-312.pyc,, -PIL/__pycache__/_typing.cpython-312.pyc,, -PIL/__pycache__/_util.cpython-312.pyc,, -PIL/__pycache__/_version.cpython-312.pyc,, -PIL/__pycache__/features.cpython-312.pyc,, -PIL/__pycache__/report.cpython-312.pyc,, -PIL/_avif.cp312-win_amd64.pyd,sha256=Vt65LbBJif7PyPWIebJOqQcNpVETUa7AWelQicRFv40,7834112 -PIL/_avif.pyi,sha256=zD8vAoPC8aEIVjfckLtFskRW5saiVel3-sJUA2pHaGc,66 -PIL/_binary.py,sha256=cb9p-_mwzBYumlVsWbnoTWsrLo59towA6atLOZvjO3w,2662 -PIL/_deprecate.py,sha256=UirDlwsyef6u6sL_rlE3mnKtRf1mavmnhkt_1PA7Q8A,2106 -PIL/_imaging.cp312-win_amd64.pyd,sha256=P6RIJRFtlzBIHA1f_TSOLYwDxWAC1HtfO9iaThK9bzQ,2588160 -PIL/_imaging.pyi,sha256=jSRG3q1dwiBMqOwIhLtTBe3LMKwsi3YkTcDfsKV32E0,924 -PIL/_imagingcms.cp312-win_amd64.pyd,sha256=g0K2LR6FYnL-Wezzy4JRk7VekR5LoR-rNGXJLS9EEFI,269824 -PIL/_imagingcms.pyi,sha256=5_SDKe7KwT9ab5EeG-wn6F5sv_fs0o212xoPBm3H-Io,4576 -PIL/_imagingft.cp312-win_amd64.pyd,sha256=L6MCmoS60xRT3UCpTULGjaNepakotTE62KrIcQZeYNQ,2170368 -PIL/_imagingft.pyi,sha256=U1rpwqQX1hULvTAo8fY0_IrXng-VPuCXVaWBUj2p1z0,1903 -PIL/_imagingmath.cp312-win_amd64.pyd,sha256=NTzbD5DGn3xWYoWX8mXdKOpuqY47MiMZJQYZnRI3CsI,25088 -PIL/_imagingmath.pyi,sha256=zD8vAoPC8aEIVjfckLtFskRW5saiVel3-sJUA2pHaGc,66 -PIL/_imagingmorph.cp312-win_amd64.pyd,sha256=TrI_4nK_Fvk3y2UGrdAaIUAenc_-qTDBCpJe3_G1SLM,13824 -PIL/_imagingmorph.pyi,sha256=zD8vAoPC8aEIVjfckLtFskRW5saiVel3-sJUA2pHaGc,66 -PIL/_imagingtk.cp312-win_amd64.pyd,sha256=L7gkiD6-Tdn3JwO-Wb5fFnnKrn_cgTBEn_kiLtAhpNg,14848 -PIL/_imagingtk.pyi,sha256=zD8vAoPC8aEIVjfckLtFskRW5saiVel3-sJUA2pHaGc,66 -PIL/_tkinter_finder.py,sha256=H1Uw3dV7gWHIj_osUnJFxWh1aRsQ2MdKpNP3vQwQcW0,558 -PIL/_typing.py,sha256=t-MVS5f_pRdL-M072YZqlXFB_D8z1KOl8EcKsT_d9s4,964 -PIL/_util.py,sha256=eP8IfmWJmbE_PqbUJb4qTqGNLi4zT0TTadrrqmykg7Y,713 -PIL/_version.py,sha256=c98gZU4emt6sNtCLY_9UhrF4HWnVoO6DZPkCV4k9Ik0,91 -PIL/_webp.cp312-win_amd64.pyd,sha256=vzGK_OwJkqyz6J0cjvIPWudQ0oCycZRsX42yPX2_UYQ,410112 -PIL/_webp.pyi,sha256=zD8vAoPC8aEIVjfckLtFskRW5saiVel3-sJUA2pHaGc,66 -PIL/features.py,sha256=y_elNCzgB6RgMP9AMf3CdOP3jdoN4ho4vxoSKzg6eWc,11118 -PIL/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -PIL/report.py,sha256=6m7NOv1a24577ZiJoxX89ip5JeOgf2O1F95f6-1K5aM,105 -pillow-12.1.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -pillow-12.1.0.dist-info/METADATA,sha256=w7MYfUpI2Mgk_IAgQJk4CP8nbcg8QKGUZoyP1gIVfu8,8983 -pillow-12.1.0.dist-info/RECORD,, -pillow-12.1.0.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -pillow-12.1.0.dist-info/WHEEL,sha256=8UP9x9puWI0P1V_d7K2oMTBqfeLNm21CTzZ_Ptr0NXU,101 -pillow-12.1.0.dist-info/licenses/LICENSE,sha256=km31-IinM3_UEmpDUgLt8oRzEr6BoWffkabXDPo_LtM,78078 -pillow-12.1.0.dist-info/top_level.txt,sha256=riZqrk-hyZqh5f1Z0Zwii3dKfxEsByhu9cU9IODF-NY,4 -pillow-12.1.0.dist-info/zip-safe,sha256=frcCV1k9oG9oKj3dpUqdJg1PxRT2RSN_XKdLCPjaYaY,2 diff --git a/venv/Lib/site-packages/pip-24.0.dist-info/RECORD b/venv/Lib/site-packages/pip-24.0.dist-info/RECORD index 8dcc25a..494aa16 100644 --- a/venv/Lib/site-packages/pip-24.0.dist-info/RECORD +++ b/venv/Lib/site-packages/pip-24.0.dist-info/RECORD @@ -1,6 +1,6 @@ -../../Scripts/pip.exe,sha256=TAuF7_4Zdq9WfnsiQkNnLye9Agpm7gBy3fvcZcC2s4g,108392 -../../Scripts/pip3.12.exe,sha256=TAuF7_4Zdq9WfnsiQkNnLye9Agpm7gBy3fvcZcC2s4g,108392 -../../Scripts/pip3.exe,sha256=TAuF7_4Zdq9WfnsiQkNnLye9Agpm7gBy3fvcZcC2s4g,108392 +../../Scripts/pip.exe,sha256=NQN3mv370tV1JymwRNrsBKzndJidFzay_dhrYtmQWNE,108390 +../../Scripts/pip3.12.exe,sha256=NQN3mv370tV1JymwRNrsBKzndJidFzay_dhrYtmQWNE,108390 +../../Scripts/pip3.exe,sha256=NQN3mv370tV1JymwRNrsBKzndJidFzay_dhrYtmQWNE,108390 pip-24.0.dist-info/AUTHORS.txt,sha256=SwXm4nkwRkmtnO1ZY-dLy7EPeoQNXMNLby5CN3GlNhY,10388 pip-24.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 pip-24.0.dist-info/LICENSE.txt,sha256=Y0MApmnUmurmWxLGxIySTFGkzfPR_whtw0VtyLyqIQQ,1093 diff --git a/venv/Lib/site-packages/pip/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/pip/__pycache__/__init__.cpython-312.pyc index 9512b1a..d0b6214 100644 Binary files a/venv/Lib/site-packages/pip/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/pip/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/__pycache__/__main__.cpython-312.pyc b/venv/Lib/site-packages/pip/__pycache__/__main__.cpython-312.pyc index 02f4b13..be1e075 100644 Binary files a/venv/Lib/site-packages/pip/__pycache__/__main__.cpython-312.pyc and b/venv/Lib/site-packages/pip/__pycache__/__main__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/__pycache__/__pip-runner__.cpython-312.pyc b/venv/Lib/site-packages/pip/__pycache__/__pip-runner__.cpython-312.pyc index 64f1725..b0fc1f7 100644 Binary files a/venv/Lib/site-packages/pip/__pycache__/__pip-runner__.cpython-312.pyc and b/venv/Lib/site-packages/pip/__pycache__/__pip-runner__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/__pycache__/__init__.cpython-312.pyc index 715ea22..36e310d 100644 Binary files a/venv/Lib/site-packages/pip/_internal/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/__pycache__/build_env.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/__pycache__/build_env.cpython-312.pyc index afe0d2e..7a9797a 100644 Binary files a/venv/Lib/site-packages/pip/_internal/__pycache__/build_env.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/__pycache__/build_env.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/__pycache__/cache.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/__pycache__/cache.cpython-312.pyc index 8064c1f..3910ead 100644 Binary files a/venv/Lib/site-packages/pip/_internal/__pycache__/cache.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/__pycache__/cache.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/__pycache__/configuration.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/__pycache__/configuration.cpython-312.pyc index f26e950..c819d38 100644 Binary files a/venv/Lib/site-packages/pip/_internal/__pycache__/configuration.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/__pycache__/configuration.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/__pycache__/exceptions.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/__pycache__/exceptions.cpython-312.pyc index 9301ffc..82c416a 100644 Binary files a/venv/Lib/site-packages/pip/_internal/__pycache__/exceptions.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/__pycache__/exceptions.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/__pycache__/main.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/__pycache__/main.cpython-312.pyc index 2a0b922..8a1fccb 100644 Binary files a/venv/Lib/site-packages/pip/_internal/__pycache__/main.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/__pycache__/main.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/__pycache__/pyproject.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/__pycache__/pyproject.cpython-312.pyc index 4878245..2968f4b 100644 Binary files a/venv/Lib/site-packages/pip/_internal/__pycache__/pyproject.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/__pycache__/pyproject.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/__pycache__/self_outdated_check.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/__pycache__/self_outdated_check.cpython-312.pyc index 70f649a..7544630 100644 Binary files a/venv/Lib/site-packages/pip/_internal/__pycache__/self_outdated_check.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/__pycache__/self_outdated_check.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/__pycache__/wheel_builder.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/__pycache__/wheel_builder.cpython-312.pyc index 9a58eb1..9e2032c 100644 Binary files a/venv/Lib/site-packages/pip/_internal/__pycache__/wheel_builder.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/__pycache__/wheel_builder.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/cli/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/cli/__pycache__/__init__.cpython-312.pyc index 12f6e1d..a9be1c2 100644 Binary files a/venv/Lib/site-packages/pip/_internal/cli/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/cli/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/cli/__pycache__/autocompletion.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/cli/__pycache__/autocompletion.cpython-312.pyc index ebf58b0..9b1417b 100644 Binary files a/venv/Lib/site-packages/pip/_internal/cli/__pycache__/autocompletion.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/cli/__pycache__/autocompletion.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/cli/__pycache__/base_command.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/cli/__pycache__/base_command.cpython-312.pyc index 8b9b77a..a28d45f 100644 Binary files a/venv/Lib/site-packages/pip/_internal/cli/__pycache__/base_command.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/cli/__pycache__/base_command.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/cli/__pycache__/cmdoptions.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/cli/__pycache__/cmdoptions.cpython-312.pyc index 400773b..0b51601 100644 Binary files a/venv/Lib/site-packages/pip/_internal/cli/__pycache__/cmdoptions.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/cli/__pycache__/cmdoptions.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/cli/__pycache__/command_context.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/cli/__pycache__/command_context.cpython-312.pyc index cfb1ad7..c86dc29 100644 Binary files a/venv/Lib/site-packages/pip/_internal/cli/__pycache__/command_context.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/cli/__pycache__/command_context.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/cli/__pycache__/main.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/cli/__pycache__/main.cpython-312.pyc index 8132f7c..fbc9cf2 100644 Binary files a/venv/Lib/site-packages/pip/_internal/cli/__pycache__/main.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/cli/__pycache__/main.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/cli/__pycache__/main_parser.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/cli/__pycache__/main_parser.cpython-312.pyc index 9452cc9..01d2998 100644 Binary files a/venv/Lib/site-packages/pip/_internal/cli/__pycache__/main_parser.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/cli/__pycache__/main_parser.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/cli/__pycache__/parser.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/cli/__pycache__/parser.cpython-312.pyc index 46a988c..1981e96 100644 Binary files a/venv/Lib/site-packages/pip/_internal/cli/__pycache__/parser.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/cli/__pycache__/parser.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/cli/__pycache__/progress_bars.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/cli/__pycache__/progress_bars.cpython-312.pyc index 3fbab10..69a7cb1 100644 Binary files a/venv/Lib/site-packages/pip/_internal/cli/__pycache__/progress_bars.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/cli/__pycache__/progress_bars.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/cli/__pycache__/req_command.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/cli/__pycache__/req_command.cpython-312.pyc index 4f5d3af..8265f90 100644 Binary files a/venv/Lib/site-packages/pip/_internal/cli/__pycache__/req_command.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/cli/__pycache__/req_command.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/cli/__pycache__/spinners.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/cli/__pycache__/spinners.cpython-312.pyc index aaf8d44..7ce97bb 100644 Binary files a/venv/Lib/site-packages/pip/_internal/cli/__pycache__/spinners.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/cli/__pycache__/spinners.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/cli/__pycache__/status_codes.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/cli/__pycache__/status_codes.cpython-312.pyc index da3927e..441fe15 100644 Binary files a/venv/Lib/site-packages/pip/_internal/cli/__pycache__/status_codes.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/cli/__pycache__/status_codes.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/commands/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/commands/__pycache__/__init__.cpython-312.pyc index c777041..7541644 100644 Binary files a/venv/Lib/site-packages/pip/_internal/commands/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/commands/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/commands/__pycache__/cache.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/commands/__pycache__/cache.cpython-312.pyc index ebc048e..4591fc4 100644 Binary files a/venv/Lib/site-packages/pip/_internal/commands/__pycache__/cache.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/commands/__pycache__/cache.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/commands/__pycache__/check.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/commands/__pycache__/check.cpython-312.pyc index 7f749f5..156334b 100644 Binary files a/venv/Lib/site-packages/pip/_internal/commands/__pycache__/check.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/commands/__pycache__/check.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/commands/__pycache__/completion.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/commands/__pycache__/completion.cpython-312.pyc index b88d1ce..ae76b72 100644 Binary files a/venv/Lib/site-packages/pip/_internal/commands/__pycache__/completion.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/commands/__pycache__/completion.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/commands/__pycache__/configuration.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/commands/__pycache__/configuration.cpython-312.pyc index 2ff74b4..fb3a98d 100644 Binary files a/venv/Lib/site-packages/pip/_internal/commands/__pycache__/configuration.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/commands/__pycache__/configuration.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/commands/__pycache__/debug.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/commands/__pycache__/debug.cpython-312.pyc index 6ad33df..915131f 100644 Binary files a/venv/Lib/site-packages/pip/_internal/commands/__pycache__/debug.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/commands/__pycache__/debug.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/commands/__pycache__/download.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/commands/__pycache__/download.cpython-312.pyc index 7807883..66bee89 100644 Binary files a/venv/Lib/site-packages/pip/_internal/commands/__pycache__/download.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/commands/__pycache__/download.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/commands/__pycache__/freeze.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/commands/__pycache__/freeze.cpython-312.pyc index 7326075..b5d9b66 100644 Binary files a/venv/Lib/site-packages/pip/_internal/commands/__pycache__/freeze.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/commands/__pycache__/freeze.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/commands/__pycache__/hash.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/commands/__pycache__/hash.cpython-312.pyc index d515533..8abb81f 100644 Binary files a/venv/Lib/site-packages/pip/_internal/commands/__pycache__/hash.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/commands/__pycache__/hash.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/commands/__pycache__/help.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/commands/__pycache__/help.cpython-312.pyc index 4295c36..6f89854 100644 Binary files a/venv/Lib/site-packages/pip/_internal/commands/__pycache__/help.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/commands/__pycache__/help.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/commands/__pycache__/index.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/commands/__pycache__/index.cpython-312.pyc index d96ff39..4c3faff 100644 Binary files a/venv/Lib/site-packages/pip/_internal/commands/__pycache__/index.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/commands/__pycache__/index.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/commands/__pycache__/inspect.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/commands/__pycache__/inspect.cpython-312.pyc index f7c8a6e..784590b 100644 Binary files a/venv/Lib/site-packages/pip/_internal/commands/__pycache__/inspect.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/commands/__pycache__/inspect.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/commands/__pycache__/install.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/commands/__pycache__/install.cpython-312.pyc index b6af27c..c9be418 100644 Binary files a/venv/Lib/site-packages/pip/_internal/commands/__pycache__/install.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/commands/__pycache__/install.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/commands/__pycache__/list.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/commands/__pycache__/list.cpython-312.pyc index 0666a1e..f984fb9 100644 Binary files a/venv/Lib/site-packages/pip/_internal/commands/__pycache__/list.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/commands/__pycache__/list.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/commands/__pycache__/search.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/commands/__pycache__/search.cpython-312.pyc index f5db00d..3dc116f 100644 Binary files a/venv/Lib/site-packages/pip/_internal/commands/__pycache__/search.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/commands/__pycache__/search.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/commands/__pycache__/show.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/commands/__pycache__/show.cpython-312.pyc index 675c24a..deb5141 100644 Binary files a/venv/Lib/site-packages/pip/_internal/commands/__pycache__/show.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/commands/__pycache__/show.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/commands/__pycache__/uninstall.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/commands/__pycache__/uninstall.cpython-312.pyc index 54d1bf3..ee83999 100644 Binary files a/venv/Lib/site-packages/pip/_internal/commands/__pycache__/uninstall.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/commands/__pycache__/uninstall.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/commands/__pycache__/wheel.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/commands/__pycache__/wheel.cpython-312.pyc index 6decc83..a8345c5 100644 Binary files a/venv/Lib/site-packages/pip/_internal/commands/__pycache__/wheel.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/commands/__pycache__/wheel.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/distributions/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/distributions/__pycache__/__init__.cpython-312.pyc index 426c09a..18f995d 100644 Binary files a/venv/Lib/site-packages/pip/_internal/distributions/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/distributions/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/distributions/__pycache__/base.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/distributions/__pycache__/base.cpython-312.pyc index 5679beb..44bf3c7 100644 Binary files a/venv/Lib/site-packages/pip/_internal/distributions/__pycache__/base.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/distributions/__pycache__/base.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/distributions/__pycache__/installed.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/distributions/__pycache__/installed.cpython-312.pyc index 9162144..1e45b64 100644 Binary files a/venv/Lib/site-packages/pip/_internal/distributions/__pycache__/installed.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/distributions/__pycache__/installed.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/distributions/__pycache__/sdist.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/distributions/__pycache__/sdist.cpython-312.pyc index 0ac7437..404b6e5 100644 Binary files a/venv/Lib/site-packages/pip/_internal/distributions/__pycache__/sdist.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/distributions/__pycache__/sdist.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/distributions/__pycache__/wheel.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/distributions/__pycache__/wheel.cpython-312.pyc index f8513af..554a40e 100644 Binary files a/venv/Lib/site-packages/pip/_internal/distributions/__pycache__/wheel.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/distributions/__pycache__/wheel.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/index/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/index/__pycache__/__init__.cpython-312.pyc index 4ebf61e..a8ac41a 100644 Binary files a/venv/Lib/site-packages/pip/_internal/index/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/index/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/index/__pycache__/collector.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/index/__pycache__/collector.cpython-312.pyc index cae53ef..e50ed70 100644 Binary files a/venv/Lib/site-packages/pip/_internal/index/__pycache__/collector.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/index/__pycache__/collector.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/index/__pycache__/package_finder.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/index/__pycache__/package_finder.cpython-312.pyc index 82b41a9..738bdda 100644 Binary files a/venv/Lib/site-packages/pip/_internal/index/__pycache__/package_finder.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/index/__pycache__/package_finder.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/index/__pycache__/sources.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/index/__pycache__/sources.cpython-312.pyc index bc3f1fc..2d29b0c 100644 Binary files a/venv/Lib/site-packages/pip/_internal/index/__pycache__/sources.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/index/__pycache__/sources.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/locations/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/locations/__pycache__/__init__.cpython-312.pyc index 3c36b3a..d40bd11 100644 Binary files a/venv/Lib/site-packages/pip/_internal/locations/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/locations/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/locations/__pycache__/_distutils.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/locations/__pycache__/_distutils.cpython-312.pyc index 045ae3f..704f4fa 100644 Binary files a/venv/Lib/site-packages/pip/_internal/locations/__pycache__/_distutils.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/locations/__pycache__/_distutils.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/locations/__pycache__/_sysconfig.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/locations/__pycache__/_sysconfig.cpython-312.pyc index 5dc06a6..082f561 100644 Binary files a/venv/Lib/site-packages/pip/_internal/locations/__pycache__/_sysconfig.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/locations/__pycache__/_sysconfig.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/locations/__pycache__/base.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/locations/__pycache__/base.cpython-312.pyc index 2d97e58..7324c65 100644 Binary files a/venv/Lib/site-packages/pip/_internal/locations/__pycache__/base.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/locations/__pycache__/base.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/metadata/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/metadata/__pycache__/__init__.cpython-312.pyc index c5484be..6db6e89 100644 Binary files a/venv/Lib/site-packages/pip/_internal/metadata/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/metadata/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/metadata/__pycache__/_json.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/metadata/__pycache__/_json.cpython-312.pyc index 845c768..71d80cc 100644 Binary files a/venv/Lib/site-packages/pip/_internal/metadata/__pycache__/_json.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/metadata/__pycache__/_json.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/metadata/__pycache__/base.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/metadata/__pycache__/base.cpython-312.pyc index 9fbecf2..2721a42 100644 Binary files a/venv/Lib/site-packages/pip/_internal/metadata/__pycache__/base.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/metadata/__pycache__/base.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/metadata/__pycache__/pkg_resources.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/metadata/__pycache__/pkg_resources.cpython-312.pyc index dde3b87..7c62d40 100644 Binary files a/venv/Lib/site-packages/pip/_internal/metadata/__pycache__/pkg_resources.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/metadata/__pycache__/pkg_resources.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/metadata/importlib/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/metadata/importlib/__pycache__/__init__.cpython-312.pyc index afb7d62..7401102 100644 Binary files a/venv/Lib/site-packages/pip/_internal/metadata/importlib/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/metadata/importlib/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/metadata/importlib/__pycache__/_compat.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/metadata/importlib/__pycache__/_compat.cpython-312.pyc index dbb0bd4..25d3125 100644 Binary files a/venv/Lib/site-packages/pip/_internal/metadata/importlib/__pycache__/_compat.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/metadata/importlib/__pycache__/_compat.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/metadata/importlib/__pycache__/_dists.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/metadata/importlib/__pycache__/_dists.cpython-312.pyc index 5ca4d82..81313be 100644 Binary files a/venv/Lib/site-packages/pip/_internal/metadata/importlib/__pycache__/_dists.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/metadata/importlib/__pycache__/_dists.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/metadata/importlib/__pycache__/_envs.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/metadata/importlib/__pycache__/_envs.cpython-312.pyc index 7a9f279..864889c 100644 Binary files a/venv/Lib/site-packages/pip/_internal/metadata/importlib/__pycache__/_envs.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/metadata/importlib/__pycache__/_envs.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/models/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/models/__pycache__/__init__.cpython-312.pyc index 849d01f..ce6b831 100644 Binary files a/venv/Lib/site-packages/pip/_internal/models/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/models/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/models/__pycache__/candidate.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/models/__pycache__/candidate.cpython-312.pyc index fd614a7..31f369a 100644 Binary files a/venv/Lib/site-packages/pip/_internal/models/__pycache__/candidate.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/models/__pycache__/candidate.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/models/__pycache__/direct_url.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/models/__pycache__/direct_url.cpython-312.pyc index c5b3170..ed25f35 100644 Binary files a/venv/Lib/site-packages/pip/_internal/models/__pycache__/direct_url.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/models/__pycache__/direct_url.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/models/__pycache__/format_control.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/models/__pycache__/format_control.cpython-312.pyc index 8b9e3f2..37c72df 100644 Binary files a/venv/Lib/site-packages/pip/_internal/models/__pycache__/format_control.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/models/__pycache__/format_control.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/models/__pycache__/index.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/models/__pycache__/index.cpython-312.pyc index 7383d34..8fb5441 100644 Binary files a/venv/Lib/site-packages/pip/_internal/models/__pycache__/index.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/models/__pycache__/index.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/models/__pycache__/installation_report.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/models/__pycache__/installation_report.cpython-312.pyc index 656c129..39ab241 100644 Binary files a/venv/Lib/site-packages/pip/_internal/models/__pycache__/installation_report.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/models/__pycache__/installation_report.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/models/__pycache__/link.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/models/__pycache__/link.cpython-312.pyc index 38bbdd0..c6776ec 100644 Binary files a/venv/Lib/site-packages/pip/_internal/models/__pycache__/link.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/models/__pycache__/link.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/models/__pycache__/scheme.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/models/__pycache__/scheme.cpython-312.pyc index 8d1e83f..5696fdc 100644 Binary files a/venv/Lib/site-packages/pip/_internal/models/__pycache__/scheme.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/models/__pycache__/scheme.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/models/__pycache__/search_scope.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/models/__pycache__/search_scope.cpython-312.pyc index f174144..afa7b27 100644 Binary files a/venv/Lib/site-packages/pip/_internal/models/__pycache__/search_scope.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/models/__pycache__/search_scope.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/models/__pycache__/selection_prefs.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/models/__pycache__/selection_prefs.cpython-312.pyc index d0bea0d..527df54 100644 Binary files a/venv/Lib/site-packages/pip/_internal/models/__pycache__/selection_prefs.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/models/__pycache__/selection_prefs.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/models/__pycache__/target_python.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/models/__pycache__/target_python.cpython-312.pyc index 7d8e23a..e3b6f83 100644 Binary files a/venv/Lib/site-packages/pip/_internal/models/__pycache__/target_python.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/models/__pycache__/target_python.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/models/__pycache__/wheel.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/models/__pycache__/wheel.cpython-312.pyc index b544b9b..f909eb7 100644 Binary files a/venv/Lib/site-packages/pip/_internal/models/__pycache__/wheel.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/models/__pycache__/wheel.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/network/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/network/__pycache__/__init__.cpython-312.pyc index f0eba4b..60c93cb 100644 Binary files a/venv/Lib/site-packages/pip/_internal/network/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/network/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/network/__pycache__/auth.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/network/__pycache__/auth.cpython-312.pyc index 66a74ad..3df32e5 100644 Binary files a/venv/Lib/site-packages/pip/_internal/network/__pycache__/auth.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/network/__pycache__/auth.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/network/__pycache__/cache.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/network/__pycache__/cache.cpython-312.pyc index 8c7c36e..c82fc91 100644 Binary files a/venv/Lib/site-packages/pip/_internal/network/__pycache__/cache.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/network/__pycache__/cache.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/network/__pycache__/download.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/network/__pycache__/download.cpython-312.pyc index eead853..125ea85 100644 Binary files a/venv/Lib/site-packages/pip/_internal/network/__pycache__/download.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/network/__pycache__/download.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/network/__pycache__/lazy_wheel.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/network/__pycache__/lazy_wheel.cpython-312.pyc index 695df18..a26bc80 100644 Binary files a/venv/Lib/site-packages/pip/_internal/network/__pycache__/lazy_wheel.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/network/__pycache__/lazy_wheel.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/network/__pycache__/session.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/network/__pycache__/session.cpython-312.pyc index 0c0ddc7..d056e2d 100644 Binary files a/venv/Lib/site-packages/pip/_internal/network/__pycache__/session.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/network/__pycache__/session.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/network/__pycache__/utils.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/network/__pycache__/utils.cpython-312.pyc index b6e3580..568f0c7 100644 Binary files a/venv/Lib/site-packages/pip/_internal/network/__pycache__/utils.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/network/__pycache__/utils.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/network/__pycache__/xmlrpc.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/network/__pycache__/xmlrpc.cpython-312.pyc index 9ac683f..4cab5f6 100644 Binary files a/venv/Lib/site-packages/pip/_internal/network/__pycache__/xmlrpc.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/network/__pycache__/xmlrpc.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/operations/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/operations/__pycache__/__init__.cpython-312.pyc index cdd5d2a..3e89e60 100644 Binary files a/venv/Lib/site-packages/pip/_internal/operations/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/operations/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/operations/__pycache__/check.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/operations/__pycache__/check.cpython-312.pyc index 8e91132..68253d1 100644 Binary files a/venv/Lib/site-packages/pip/_internal/operations/__pycache__/check.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/operations/__pycache__/check.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/operations/__pycache__/freeze.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/operations/__pycache__/freeze.cpython-312.pyc index 14df5a7..0708b3d 100644 Binary files a/venv/Lib/site-packages/pip/_internal/operations/__pycache__/freeze.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/operations/__pycache__/freeze.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/operations/__pycache__/prepare.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/operations/__pycache__/prepare.cpython-312.pyc index 3ef4e36..e27173a 100644 Binary files a/venv/Lib/site-packages/pip/_internal/operations/__pycache__/prepare.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/operations/__pycache__/prepare.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/operations/build/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/operations/build/__pycache__/__init__.cpython-312.pyc index 9c63394..6663dbd 100644 Binary files a/venv/Lib/site-packages/pip/_internal/operations/build/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/operations/build/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/operations/build/__pycache__/build_tracker.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/operations/build/__pycache__/build_tracker.cpython-312.pyc index 0ad14d3..4ed1379 100644 Binary files a/venv/Lib/site-packages/pip/_internal/operations/build/__pycache__/build_tracker.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/operations/build/__pycache__/build_tracker.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/operations/build/__pycache__/metadata.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/operations/build/__pycache__/metadata.cpython-312.pyc index 535fdde..9ec72b4 100644 Binary files a/venv/Lib/site-packages/pip/_internal/operations/build/__pycache__/metadata.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/operations/build/__pycache__/metadata.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/operations/build/__pycache__/metadata_editable.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/operations/build/__pycache__/metadata_editable.cpython-312.pyc index 2e298f6..929aa84 100644 Binary files a/venv/Lib/site-packages/pip/_internal/operations/build/__pycache__/metadata_editable.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/operations/build/__pycache__/metadata_editable.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/operations/build/__pycache__/metadata_legacy.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/operations/build/__pycache__/metadata_legacy.cpython-312.pyc index 3ed93b5..3c1f848 100644 Binary files a/venv/Lib/site-packages/pip/_internal/operations/build/__pycache__/metadata_legacy.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/operations/build/__pycache__/metadata_legacy.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/operations/build/__pycache__/wheel.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/operations/build/__pycache__/wheel.cpython-312.pyc index 229c894..076ce79 100644 Binary files a/venv/Lib/site-packages/pip/_internal/operations/build/__pycache__/wheel.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/operations/build/__pycache__/wheel.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/operations/build/__pycache__/wheel_editable.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/operations/build/__pycache__/wheel_editable.cpython-312.pyc index 92a0a4a..08e47e0 100644 Binary files a/venv/Lib/site-packages/pip/_internal/operations/build/__pycache__/wheel_editable.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/operations/build/__pycache__/wheel_editable.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/operations/build/__pycache__/wheel_legacy.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/operations/build/__pycache__/wheel_legacy.cpython-312.pyc index 90e6f52..c7a1f62 100644 Binary files a/venv/Lib/site-packages/pip/_internal/operations/build/__pycache__/wheel_legacy.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/operations/build/__pycache__/wheel_legacy.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/operations/install/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/operations/install/__pycache__/__init__.cpython-312.pyc index 9028931..682381d 100644 Binary files a/venv/Lib/site-packages/pip/_internal/operations/install/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/operations/install/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/operations/install/__pycache__/editable_legacy.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/operations/install/__pycache__/editable_legacy.cpython-312.pyc index 478e4df..72ad0ee 100644 Binary files a/venv/Lib/site-packages/pip/_internal/operations/install/__pycache__/editable_legacy.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/operations/install/__pycache__/editable_legacy.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/operations/install/__pycache__/wheel.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/operations/install/__pycache__/wheel.cpython-312.pyc index c9235d3..7d7da98 100644 Binary files a/venv/Lib/site-packages/pip/_internal/operations/install/__pycache__/wheel.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/operations/install/__pycache__/wheel.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/req/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/req/__pycache__/__init__.cpython-312.pyc index c9579cd..95404a2 100644 Binary files a/venv/Lib/site-packages/pip/_internal/req/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/req/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/req/__pycache__/constructors.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/req/__pycache__/constructors.cpython-312.pyc index 6482ef6..25430d8 100644 Binary files a/venv/Lib/site-packages/pip/_internal/req/__pycache__/constructors.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/req/__pycache__/constructors.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/req/__pycache__/req_file.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/req/__pycache__/req_file.cpython-312.pyc index f9a44a7..8653a32 100644 Binary files a/venv/Lib/site-packages/pip/_internal/req/__pycache__/req_file.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/req/__pycache__/req_file.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/req/__pycache__/req_install.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/req/__pycache__/req_install.cpython-312.pyc index d9a01c5..8f17d9d 100644 Binary files a/venv/Lib/site-packages/pip/_internal/req/__pycache__/req_install.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/req/__pycache__/req_install.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/req/__pycache__/req_set.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/req/__pycache__/req_set.cpython-312.pyc index 2674d43..999117c 100644 Binary files a/venv/Lib/site-packages/pip/_internal/req/__pycache__/req_set.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/req/__pycache__/req_set.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/req/__pycache__/req_uninstall.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/req/__pycache__/req_uninstall.cpython-312.pyc index 87f7722..34fa05a 100644 Binary files a/venv/Lib/site-packages/pip/_internal/req/__pycache__/req_uninstall.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/req/__pycache__/req_uninstall.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/resolution/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/resolution/__pycache__/__init__.cpython-312.pyc index a37a2ea..1a65a1a 100644 Binary files a/venv/Lib/site-packages/pip/_internal/resolution/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/resolution/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/resolution/__pycache__/base.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/resolution/__pycache__/base.cpython-312.pyc index a9ae881..7b4eb2c 100644 Binary files a/venv/Lib/site-packages/pip/_internal/resolution/__pycache__/base.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/resolution/__pycache__/base.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/resolution/legacy/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/resolution/legacy/__pycache__/__init__.cpython-312.pyc index d4272af..6d36ca9 100644 Binary files a/venv/Lib/site-packages/pip/_internal/resolution/legacy/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/resolution/legacy/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/resolution/legacy/__pycache__/resolver.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/resolution/legacy/__pycache__/resolver.cpython-312.pyc index a7bd80b..c421cae 100644 Binary files a/venv/Lib/site-packages/pip/_internal/resolution/legacy/__pycache__/resolver.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/resolution/legacy/__pycache__/resolver.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/__pycache__/__init__.cpython-312.pyc index 10a7638..db82ca9 100644 Binary files a/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/__pycache__/base.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/__pycache__/base.cpython-312.pyc index 233df82..c742b78 100644 Binary files a/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/__pycache__/base.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/__pycache__/base.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/__pycache__/candidates.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/__pycache__/candidates.cpython-312.pyc index f025881..6ddc406 100644 Binary files a/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/__pycache__/candidates.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/__pycache__/candidates.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/__pycache__/factory.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/__pycache__/factory.cpython-312.pyc index fd3b16d..0b158da 100644 Binary files a/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/__pycache__/factory.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/__pycache__/factory.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/__pycache__/found_candidates.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/__pycache__/found_candidates.cpython-312.pyc index 83fe2ff..648e9fc 100644 Binary files a/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/__pycache__/found_candidates.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/__pycache__/found_candidates.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/__pycache__/provider.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/__pycache__/provider.cpython-312.pyc index 8775f2b..1e6fa9a 100644 Binary files a/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/__pycache__/provider.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/__pycache__/provider.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/__pycache__/reporter.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/__pycache__/reporter.cpython-312.pyc index 98489ed..84f8b2e 100644 Binary files a/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/__pycache__/reporter.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/__pycache__/reporter.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/__pycache__/requirements.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/__pycache__/requirements.cpython-312.pyc index ed1a737..0c74bd7 100644 Binary files a/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/__pycache__/requirements.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/__pycache__/requirements.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/__pycache__/resolver.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/__pycache__/resolver.cpython-312.pyc index dafb6e2..40769e1 100644 Binary files a/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/__pycache__/resolver.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/resolution/resolvelib/__pycache__/resolver.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/utils/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/utils/__pycache__/__init__.cpython-312.pyc index 8f745c0..90de352 100644 Binary files a/venv/Lib/site-packages/pip/_internal/utils/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/utils/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/utils/__pycache__/_jaraco_text.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/utils/__pycache__/_jaraco_text.cpython-312.pyc index fef5d54..b49f63e 100644 Binary files a/venv/Lib/site-packages/pip/_internal/utils/__pycache__/_jaraco_text.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/utils/__pycache__/_jaraco_text.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/utils/__pycache__/_log.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/utils/__pycache__/_log.cpython-312.pyc index e0b4bdb..e8a3fba 100644 Binary files a/venv/Lib/site-packages/pip/_internal/utils/__pycache__/_log.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/utils/__pycache__/_log.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/utils/__pycache__/appdirs.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/utils/__pycache__/appdirs.cpython-312.pyc index 5647379..6953740 100644 Binary files a/venv/Lib/site-packages/pip/_internal/utils/__pycache__/appdirs.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/utils/__pycache__/appdirs.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/utils/__pycache__/compat.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/utils/__pycache__/compat.cpython-312.pyc index a06a9b4..29136df 100644 Binary files a/venv/Lib/site-packages/pip/_internal/utils/__pycache__/compat.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/utils/__pycache__/compat.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/utils/__pycache__/compatibility_tags.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/utils/__pycache__/compatibility_tags.cpython-312.pyc index 6cccc1b..5a367c2 100644 Binary files a/venv/Lib/site-packages/pip/_internal/utils/__pycache__/compatibility_tags.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/utils/__pycache__/compatibility_tags.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/utils/__pycache__/datetime.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/utils/__pycache__/datetime.cpython-312.pyc index f72e1da..f106d61 100644 Binary files a/venv/Lib/site-packages/pip/_internal/utils/__pycache__/datetime.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/utils/__pycache__/datetime.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/utils/__pycache__/deprecation.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/utils/__pycache__/deprecation.cpython-312.pyc index 2ef9493..0bb3792 100644 Binary files a/venv/Lib/site-packages/pip/_internal/utils/__pycache__/deprecation.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/utils/__pycache__/deprecation.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/utils/__pycache__/direct_url_helpers.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/utils/__pycache__/direct_url_helpers.cpython-312.pyc index 664f10d..08bbe14 100644 Binary files a/venv/Lib/site-packages/pip/_internal/utils/__pycache__/direct_url_helpers.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/utils/__pycache__/direct_url_helpers.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/utils/__pycache__/egg_link.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/utils/__pycache__/egg_link.cpython-312.pyc index 6a9bcee..6c1e1ed 100644 Binary files a/venv/Lib/site-packages/pip/_internal/utils/__pycache__/egg_link.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/utils/__pycache__/egg_link.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/utils/__pycache__/encoding.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/utils/__pycache__/encoding.cpython-312.pyc index a31bde2..286497b 100644 Binary files a/venv/Lib/site-packages/pip/_internal/utils/__pycache__/encoding.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/utils/__pycache__/encoding.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/utils/__pycache__/entrypoints.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/utils/__pycache__/entrypoints.cpython-312.pyc index 611c25b..d925377 100644 Binary files a/venv/Lib/site-packages/pip/_internal/utils/__pycache__/entrypoints.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/utils/__pycache__/entrypoints.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/utils/__pycache__/filesystem.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/utils/__pycache__/filesystem.cpython-312.pyc index f87e143..9f1471e 100644 Binary files a/venv/Lib/site-packages/pip/_internal/utils/__pycache__/filesystem.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/utils/__pycache__/filesystem.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/utils/__pycache__/filetypes.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/utils/__pycache__/filetypes.cpython-312.pyc index 36808f5..9a8c601 100644 Binary files a/venv/Lib/site-packages/pip/_internal/utils/__pycache__/filetypes.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/utils/__pycache__/filetypes.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/utils/__pycache__/glibc.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/utils/__pycache__/glibc.cpython-312.pyc index 6890cb4..83cf0ed 100644 Binary files a/venv/Lib/site-packages/pip/_internal/utils/__pycache__/glibc.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/utils/__pycache__/glibc.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/utils/__pycache__/hashes.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/utils/__pycache__/hashes.cpython-312.pyc index f1498fd..4bb9373 100644 Binary files a/venv/Lib/site-packages/pip/_internal/utils/__pycache__/hashes.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/utils/__pycache__/hashes.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/utils/__pycache__/logging.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/utils/__pycache__/logging.cpython-312.pyc index 2de01a8..6ba7544 100644 Binary files a/venv/Lib/site-packages/pip/_internal/utils/__pycache__/logging.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/utils/__pycache__/logging.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/utils/__pycache__/misc.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/utils/__pycache__/misc.cpython-312.pyc index b6bb36e..d785d31 100644 Binary files a/venv/Lib/site-packages/pip/_internal/utils/__pycache__/misc.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/utils/__pycache__/misc.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/utils/__pycache__/models.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/utils/__pycache__/models.cpython-312.pyc index 0fa504c..8d8e28e 100644 Binary files a/venv/Lib/site-packages/pip/_internal/utils/__pycache__/models.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/utils/__pycache__/models.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/utils/__pycache__/packaging.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/utils/__pycache__/packaging.cpython-312.pyc index 0b06971..8516af5 100644 Binary files a/venv/Lib/site-packages/pip/_internal/utils/__pycache__/packaging.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/utils/__pycache__/packaging.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/utils/__pycache__/setuptools_build.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/utils/__pycache__/setuptools_build.cpython-312.pyc index c152413..2a378fd 100644 Binary files a/venv/Lib/site-packages/pip/_internal/utils/__pycache__/setuptools_build.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/utils/__pycache__/setuptools_build.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/utils/__pycache__/subprocess.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/utils/__pycache__/subprocess.cpython-312.pyc index 3c038c0..9da2daf 100644 Binary files a/venv/Lib/site-packages/pip/_internal/utils/__pycache__/subprocess.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/utils/__pycache__/subprocess.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/utils/__pycache__/temp_dir.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/utils/__pycache__/temp_dir.cpython-312.pyc index 2109521..9011bb6 100644 Binary files a/venv/Lib/site-packages/pip/_internal/utils/__pycache__/temp_dir.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/utils/__pycache__/temp_dir.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/utils/__pycache__/unpacking.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/utils/__pycache__/unpacking.cpython-312.pyc index a072405..e4be3d5 100644 Binary files a/venv/Lib/site-packages/pip/_internal/utils/__pycache__/unpacking.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/utils/__pycache__/unpacking.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/utils/__pycache__/urls.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/utils/__pycache__/urls.cpython-312.pyc index fd00488..e9e0d9e 100644 Binary files a/venv/Lib/site-packages/pip/_internal/utils/__pycache__/urls.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/utils/__pycache__/urls.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/utils/__pycache__/virtualenv.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/utils/__pycache__/virtualenv.cpython-312.pyc index adb088e..2f7aa5c 100644 Binary files a/venv/Lib/site-packages/pip/_internal/utils/__pycache__/virtualenv.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/utils/__pycache__/virtualenv.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/utils/__pycache__/wheel.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/utils/__pycache__/wheel.cpython-312.pyc index 4a6e275..2ec897e 100644 Binary files a/venv/Lib/site-packages/pip/_internal/utils/__pycache__/wheel.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/utils/__pycache__/wheel.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/vcs/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/vcs/__pycache__/__init__.cpython-312.pyc index 8e0051f..4a64377 100644 Binary files a/venv/Lib/site-packages/pip/_internal/vcs/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/vcs/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/vcs/__pycache__/bazaar.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/vcs/__pycache__/bazaar.cpython-312.pyc index 1c3c676..e227039 100644 Binary files a/venv/Lib/site-packages/pip/_internal/vcs/__pycache__/bazaar.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/vcs/__pycache__/bazaar.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/vcs/__pycache__/git.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/vcs/__pycache__/git.cpython-312.pyc index eb8cb4f..d9ebaaa 100644 Binary files a/venv/Lib/site-packages/pip/_internal/vcs/__pycache__/git.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/vcs/__pycache__/git.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/vcs/__pycache__/mercurial.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/vcs/__pycache__/mercurial.cpython-312.pyc index c226623..319b26e 100644 Binary files a/venv/Lib/site-packages/pip/_internal/vcs/__pycache__/mercurial.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/vcs/__pycache__/mercurial.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/vcs/__pycache__/subversion.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/vcs/__pycache__/subversion.cpython-312.pyc index 071064c..8765631 100644 Binary files a/venv/Lib/site-packages/pip/_internal/vcs/__pycache__/subversion.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/vcs/__pycache__/subversion.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_internal/vcs/__pycache__/versioncontrol.cpython-312.pyc b/venv/Lib/site-packages/pip/_internal/vcs/__pycache__/versioncontrol.cpython-312.pyc index 05f65db..408e1dd 100644 Binary files a/venv/Lib/site-packages/pip/_internal/vcs/__pycache__/versioncontrol.cpython-312.pyc and b/venv/Lib/site-packages/pip/_internal/vcs/__pycache__/versioncontrol.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/__pycache__/__init__.cpython-312.pyc index 723760a..ec04edc 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/__pycache__/six.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/__pycache__/six.cpython-312.pyc index 460bf65..564962f 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/__pycache__/six.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/__pycache__/six.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/__pycache__/typing_extensions.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/__pycache__/typing_extensions.cpython-312.pyc index 27619f6..3160e94 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/__pycache__/typing_extensions.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/__pycache__/typing_extensions.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/cachecontrol/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/cachecontrol/__pycache__/__init__.cpython-312.pyc index 5cd6bf5..ee5970a 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/cachecontrol/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/cachecontrol/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/cachecontrol/__pycache__/_cmd.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/cachecontrol/__pycache__/_cmd.cpython-312.pyc index 19ed587..bacaba4 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/cachecontrol/__pycache__/_cmd.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/cachecontrol/__pycache__/_cmd.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/cachecontrol/__pycache__/adapter.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/cachecontrol/__pycache__/adapter.cpython-312.pyc index d65e2bc..c4d0fcd 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/cachecontrol/__pycache__/adapter.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/cachecontrol/__pycache__/adapter.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/cachecontrol/__pycache__/cache.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/cachecontrol/__pycache__/cache.cpython-312.pyc index 883bd40..aeb8689 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/cachecontrol/__pycache__/cache.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/cachecontrol/__pycache__/cache.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/cachecontrol/__pycache__/controller.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/cachecontrol/__pycache__/controller.cpython-312.pyc index 8211e9c..fea7062 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/cachecontrol/__pycache__/controller.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/cachecontrol/__pycache__/controller.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/cachecontrol/__pycache__/filewrapper.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/cachecontrol/__pycache__/filewrapper.cpython-312.pyc index aa9d5e3..6cd046d 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/cachecontrol/__pycache__/filewrapper.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/cachecontrol/__pycache__/filewrapper.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/cachecontrol/__pycache__/heuristics.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/cachecontrol/__pycache__/heuristics.cpython-312.pyc index a06a6d5..e8297c6 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/cachecontrol/__pycache__/heuristics.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/cachecontrol/__pycache__/heuristics.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/cachecontrol/__pycache__/serialize.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/cachecontrol/__pycache__/serialize.cpython-312.pyc index ce345e5..6a85997 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/cachecontrol/__pycache__/serialize.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/cachecontrol/__pycache__/serialize.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/cachecontrol/__pycache__/wrapper.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/cachecontrol/__pycache__/wrapper.cpython-312.pyc index 46b735a..7a0b478 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/cachecontrol/__pycache__/wrapper.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/cachecontrol/__pycache__/wrapper.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/cachecontrol/caches/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/cachecontrol/caches/__pycache__/__init__.cpython-312.pyc index a888957..2f72efa 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/cachecontrol/caches/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/cachecontrol/caches/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/cachecontrol/caches/__pycache__/file_cache.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/cachecontrol/caches/__pycache__/file_cache.cpython-312.pyc index 150bfb3..6e00c83 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/cachecontrol/caches/__pycache__/file_cache.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/cachecontrol/caches/__pycache__/file_cache.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/cachecontrol/caches/__pycache__/redis_cache.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/cachecontrol/caches/__pycache__/redis_cache.cpython-312.pyc index 71e6f85..d09f664 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/cachecontrol/caches/__pycache__/redis_cache.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/cachecontrol/caches/__pycache__/redis_cache.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/certifi/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/certifi/__pycache__/__init__.cpython-312.pyc index 68d800b..355110d 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/certifi/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/certifi/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/certifi/__pycache__/__main__.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/certifi/__pycache__/__main__.cpython-312.pyc index a4e179e..dd22aa6 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/certifi/__pycache__/__main__.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/certifi/__pycache__/__main__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/certifi/__pycache__/core.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/certifi/__pycache__/core.cpython-312.pyc index 1d5611f..8d03f71 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/certifi/__pycache__/core.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/certifi/__pycache__/core.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/__init__.cpython-312.pyc index 51a0a71..e6f6a6b 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/big5freq.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/big5freq.cpython-312.pyc index 86346a4..9092d05 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/big5freq.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/big5freq.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/big5prober.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/big5prober.cpython-312.pyc index a0e845b..55b8502 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/big5prober.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/big5prober.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/chardistribution.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/chardistribution.cpython-312.pyc index 684f7d6..708ce1c 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/chardistribution.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/chardistribution.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/charsetgroupprober.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/charsetgroupprober.cpython-312.pyc index 7a1c730..103dc5b 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/charsetgroupprober.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/charsetgroupprober.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/charsetprober.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/charsetprober.cpython-312.pyc index 12d4c14..2e26d7f 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/charsetprober.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/charsetprober.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/codingstatemachine.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/codingstatemachine.cpython-312.pyc index 147c57d..fc61aab 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/codingstatemachine.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/codingstatemachine.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/codingstatemachinedict.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/codingstatemachinedict.cpython-312.pyc index 2780663..be380b1 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/codingstatemachinedict.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/codingstatemachinedict.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/cp949prober.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/cp949prober.cpython-312.pyc index 4ad402d..911b8c0 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/cp949prober.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/cp949prober.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/enums.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/enums.cpython-312.pyc index 0886ed0..9cedd74 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/enums.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/enums.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/escprober.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/escprober.cpython-312.pyc index de62cfc..a6cc3a9 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/escprober.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/escprober.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/escsm.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/escsm.cpython-312.pyc index d2deeb3..604df1d 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/escsm.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/escsm.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/eucjpprober.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/eucjpprober.cpython-312.pyc index 4108ba0..2040faf 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/eucjpprober.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/eucjpprober.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/euckrfreq.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/euckrfreq.cpython-312.pyc index b14ec71..4b96d9d 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/euckrfreq.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/euckrfreq.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/euckrprober.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/euckrprober.cpython-312.pyc index 27feb69..ef778ad 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/euckrprober.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/euckrprober.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/euctwfreq.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/euctwfreq.cpython-312.pyc index fdec811..ef1c86e 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/euctwfreq.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/euctwfreq.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/euctwprober.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/euctwprober.cpython-312.pyc index 8978ef0..94fc476 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/euctwprober.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/euctwprober.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/gb2312freq.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/gb2312freq.cpython-312.pyc index 3df49dd..30b1a02 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/gb2312freq.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/gb2312freq.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/gb2312prober.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/gb2312prober.cpython-312.pyc index e19d27d..a2ee089 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/gb2312prober.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/gb2312prober.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/hebrewprober.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/hebrewprober.cpython-312.pyc index e84556b..e0d439a 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/hebrewprober.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/hebrewprober.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/jisfreq.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/jisfreq.cpython-312.pyc index 195d91c..39f0787 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/jisfreq.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/jisfreq.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/johabfreq.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/johabfreq.cpython-312.pyc index 84885be..d4fa98e 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/johabfreq.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/johabfreq.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/johabprober.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/johabprober.cpython-312.pyc index a2bde6b..40d6c0e 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/johabprober.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/johabprober.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/jpcntx.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/jpcntx.cpython-312.pyc index 71f8c1e..71f1736 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/jpcntx.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/jpcntx.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/langbulgarianmodel.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/langbulgarianmodel.cpython-312.pyc index b80b688..f0157f0 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/langbulgarianmodel.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/langbulgarianmodel.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/langgreekmodel.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/langgreekmodel.cpython-312.pyc index 6734176..c5e157f 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/langgreekmodel.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/langgreekmodel.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/langhebrewmodel.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/langhebrewmodel.cpython-312.pyc index 0760b4f..06607c6 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/langhebrewmodel.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/langhebrewmodel.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/langhungarianmodel.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/langhungarianmodel.cpython-312.pyc index 0e3e55d..1bb7bad 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/langhungarianmodel.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/langhungarianmodel.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/langrussianmodel.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/langrussianmodel.cpython-312.pyc index 8c7cf28..8354257 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/langrussianmodel.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/langrussianmodel.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/langthaimodel.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/langthaimodel.cpython-312.pyc index 6d47241..d7a6edb 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/langthaimodel.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/langthaimodel.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/langturkishmodel.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/langturkishmodel.cpython-312.pyc index 551ea1d..26a6ae4 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/langturkishmodel.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/langturkishmodel.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/latin1prober.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/latin1prober.cpython-312.pyc index 898542e..61df9d3 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/latin1prober.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/latin1prober.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/macromanprober.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/macromanprober.cpython-312.pyc index d0b2e29..5ad2f31 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/macromanprober.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/macromanprober.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/mbcharsetprober.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/mbcharsetprober.cpython-312.pyc index 9a0888e..d889ad7 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/mbcharsetprober.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/mbcharsetprober.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/mbcsgroupprober.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/mbcsgroupprober.cpython-312.pyc index 6973d1b..468f47c 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/mbcsgroupprober.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/mbcsgroupprober.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/mbcssm.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/mbcssm.cpython-312.pyc index 2c4d227..46741e6 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/mbcssm.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/mbcssm.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/resultdict.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/resultdict.cpython-312.pyc index 52a562b..c9f72e8 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/resultdict.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/resultdict.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/sbcharsetprober.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/sbcharsetprober.cpython-312.pyc index 64a2ce3..278d125 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/sbcharsetprober.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/sbcharsetprober.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/sbcsgroupprober.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/sbcsgroupprober.cpython-312.pyc index 6b7bb4e..94c2565 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/sbcsgroupprober.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/sbcsgroupprober.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/sjisprober.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/sjisprober.cpython-312.pyc index 4469899..c54ce04 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/sjisprober.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/sjisprober.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/universaldetector.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/universaldetector.cpython-312.pyc index fb7d92f..5fd6ac1 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/universaldetector.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/universaldetector.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/utf1632prober.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/utf1632prober.cpython-312.pyc index f55a353..8a1c3ea 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/utf1632prober.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/utf1632prober.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/utf8prober.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/utf8prober.cpython-312.pyc index bd683b2..26e0ca8 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/utf8prober.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/utf8prober.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/version.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/version.cpython-312.pyc index 7ad6454..ef1af85 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/version.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/chardet/__pycache__/version.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/chardet/cli/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/chardet/cli/__pycache__/__init__.cpython-312.pyc index 30f39c1..354341e 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/chardet/cli/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/chardet/cli/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/chardet/cli/__pycache__/chardetect.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/chardet/cli/__pycache__/chardetect.cpython-312.pyc index c45ec5d..004d84a 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/chardet/cli/__pycache__/chardetect.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/chardet/cli/__pycache__/chardetect.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/chardet/metadata/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/chardet/metadata/__pycache__/__init__.cpython-312.pyc index ea73fad..d11e4cc 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/chardet/metadata/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/chardet/metadata/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/chardet/metadata/__pycache__/languages.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/chardet/metadata/__pycache__/languages.cpython-312.pyc index e201537..9daf4dc 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/chardet/metadata/__pycache__/languages.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/chardet/metadata/__pycache__/languages.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/colorama/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/colorama/__pycache__/__init__.cpython-312.pyc index 69d404a..72e230f 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/colorama/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/colorama/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/colorama/__pycache__/ansi.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/colorama/__pycache__/ansi.cpython-312.pyc index eea1bbe..424b36f 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/colorama/__pycache__/ansi.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/colorama/__pycache__/ansi.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/colorama/__pycache__/ansitowin32.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/colorama/__pycache__/ansitowin32.cpython-312.pyc index c9ff3d6..ff49fcc 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/colorama/__pycache__/ansitowin32.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/colorama/__pycache__/ansitowin32.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/colorama/__pycache__/initialise.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/colorama/__pycache__/initialise.cpython-312.pyc index 26c6bf3..430998c 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/colorama/__pycache__/initialise.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/colorama/__pycache__/initialise.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/colorama/__pycache__/win32.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/colorama/__pycache__/win32.cpython-312.pyc index 6c6f661..7192519 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/colorama/__pycache__/win32.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/colorama/__pycache__/win32.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/colorama/__pycache__/winterm.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/colorama/__pycache__/winterm.cpython-312.pyc index 976ab06..4741484 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/colorama/__pycache__/winterm.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/colorama/__pycache__/winterm.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/colorama/tests/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/colorama/tests/__pycache__/__init__.cpython-312.pyc index 3385867..d74d88c 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/colorama/tests/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/colorama/tests/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/colorama/tests/__pycache__/ansi_test.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/colorama/tests/__pycache__/ansi_test.cpython-312.pyc index 5ed8df8..0d34b13 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/colorama/tests/__pycache__/ansi_test.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/colorama/tests/__pycache__/ansi_test.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/colorama/tests/__pycache__/ansitowin32_test.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/colorama/tests/__pycache__/ansitowin32_test.cpython-312.pyc index 12d4b53..dd586c1 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/colorama/tests/__pycache__/ansitowin32_test.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/colorama/tests/__pycache__/ansitowin32_test.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/colorama/tests/__pycache__/initialise_test.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/colorama/tests/__pycache__/initialise_test.cpython-312.pyc index da2e027..fa19fe8 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/colorama/tests/__pycache__/initialise_test.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/colorama/tests/__pycache__/initialise_test.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/colorama/tests/__pycache__/isatty_test.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/colorama/tests/__pycache__/isatty_test.cpython-312.pyc index 7abd76c..508b4a4 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/colorama/tests/__pycache__/isatty_test.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/colorama/tests/__pycache__/isatty_test.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/colorama/tests/__pycache__/utils.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/colorama/tests/__pycache__/utils.cpython-312.pyc index 3b76a48..0be3165 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/colorama/tests/__pycache__/utils.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/colorama/tests/__pycache__/utils.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/colorama/tests/__pycache__/winterm_test.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/colorama/tests/__pycache__/winterm_test.cpython-312.pyc index c45049d..63351b7 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/colorama/tests/__pycache__/winterm_test.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/colorama/tests/__pycache__/winterm_test.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/distlib/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/distlib/__pycache__/__init__.cpython-312.pyc index 6f99623..5430fb8 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/distlib/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/distlib/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/distlib/__pycache__/compat.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/distlib/__pycache__/compat.cpython-312.pyc index a7f2d1e..6e1a01d 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/distlib/__pycache__/compat.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/distlib/__pycache__/compat.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/distlib/__pycache__/database.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/distlib/__pycache__/database.cpython-312.pyc index 5061165..28c59b1 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/distlib/__pycache__/database.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/distlib/__pycache__/database.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/distlib/__pycache__/index.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/distlib/__pycache__/index.cpython-312.pyc index 0327334..7899630 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/distlib/__pycache__/index.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/distlib/__pycache__/index.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/distlib/__pycache__/locators.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/distlib/__pycache__/locators.cpython-312.pyc index ececf5e..e4d4fd5 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/distlib/__pycache__/locators.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/distlib/__pycache__/locators.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/distlib/__pycache__/manifest.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/distlib/__pycache__/manifest.cpython-312.pyc index c5dcf84..5c4a75b 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/distlib/__pycache__/manifest.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/distlib/__pycache__/manifest.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/distlib/__pycache__/markers.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/distlib/__pycache__/markers.cpython-312.pyc index 52ea16e..c615bc5 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/distlib/__pycache__/markers.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/distlib/__pycache__/markers.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/distlib/__pycache__/metadata.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/distlib/__pycache__/metadata.cpython-312.pyc index 829de9e..85ae4ad 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/distlib/__pycache__/metadata.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/distlib/__pycache__/metadata.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/distlib/__pycache__/resources.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/distlib/__pycache__/resources.cpython-312.pyc index 8c451a3..b4c787e 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/distlib/__pycache__/resources.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/distlib/__pycache__/resources.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/distlib/__pycache__/scripts.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/distlib/__pycache__/scripts.cpython-312.pyc index d199c1f..1265fb2 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/distlib/__pycache__/scripts.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/distlib/__pycache__/scripts.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/distlib/__pycache__/util.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/distlib/__pycache__/util.cpython-312.pyc index 3594b03..b14b58a 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/distlib/__pycache__/util.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/distlib/__pycache__/util.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/distlib/__pycache__/version.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/distlib/__pycache__/version.cpython-312.pyc index 4eb7e6e..df462c3 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/distlib/__pycache__/version.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/distlib/__pycache__/version.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/distlib/__pycache__/wheel.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/distlib/__pycache__/wheel.cpython-312.pyc index 2d0cafa..8095297 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/distlib/__pycache__/wheel.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/distlib/__pycache__/wheel.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/distro/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/distro/__pycache__/__init__.cpython-312.pyc index eed8948..f561ea3 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/distro/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/distro/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/distro/__pycache__/__main__.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/distro/__pycache__/__main__.cpython-312.pyc index 0520864..a61b96b 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/distro/__pycache__/__main__.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/distro/__pycache__/__main__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/distro/__pycache__/distro.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/distro/__pycache__/distro.cpython-312.pyc index a4fb9fb..30563ff 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/distro/__pycache__/distro.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/distro/__pycache__/distro.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/idna/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/idna/__pycache__/__init__.cpython-312.pyc index 28e22ab..94d2548 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/idna/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/idna/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/idna/__pycache__/codec.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/idna/__pycache__/codec.cpython-312.pyc index ba607cf..39dd685 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/idna/__pycache__/codec.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/idna/__pycache__/codec.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/idna/__pycache__/compat.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/idna/__pycache__/compat.cpython-312.pyc index e20a201..fceedf3 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/idna/__pycache__/compat.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/idna/__pycache__/compat.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/idna/__pycache__/core.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/idna/__pycache__/core.cpython-312.pyc index 0dfcc1a..80fcd51 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/idna/__pycache__/core.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/idna/__pycache__/core.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/idna/__pycache__/idnadata.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/idna/__pycache__/idnadata.cpython-312.pyc index 891c42b..7acac5a 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/idna/__pycache__/idnadata.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/idna/__pycache__/idnadata.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/idna/__pycache__/intranges.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/idna/__pycache__/intranges.cpython-312.pyc index eeb8976..bde7380 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/idna/__pycache__/intranges.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/idna/__pycache__/intranges.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/idna/__pycache__/package_data.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/idna/__pycache__/package_data.cpython-312.pyc index df6f995..7262110 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/idna/__pycache__/package_data.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/idna/__pycache__/package_data.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/idna/__pycache__/uts46data.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/idna/__pycache__/uts46data.cpython-312.pyc index ad8da38..c2ad161 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/idna/__pycache__/uts46data.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/idna/__pycache__/uts46data.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/msgpack/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/msgpack/__pycache__/__init__.cpython-312.pyc index 1aae854..c2d2859 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/msgpack/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/msgpack/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/msgpack/__pycache__/exceptions.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/msgpack/__pycache__/exceptions.cpython-312.pyc index 683372d..233e2db 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/msgpack/__pycache__/exceptions.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/msgpack/__pycache__/exceptions.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/msgpack/__pycache__/ext.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/msgpack/__pycache__/ext.cpython-312.pyc index 970eb77..d0dae30 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/msgpack/__pycache__/ext.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/msgpack/__pycache__/ext.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/msgpack/__pycache__/fallback.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/msgpack/__pycache__/fallback.cpython-312.pyc index 8e8c3e1..1902b5a 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/msgpack/__pycache__/fallback.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/msgpack/__pycache__/fallback.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/packaging/__pycache__/__about__.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/packaging/__pycache__/__about__.cpython-312.pyc index 2ee4d99..68b1e62 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/packaging/__pycache__/__about__.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/packaging/__pycache__/__about__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/packaging/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/packaging/__pycache__/__init__.cpython-312.pyc index a73d462..6e57692 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/packaging/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/packaging/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/packaging/__pycache__/_manylinux.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/packaging/__pycache__/_manylinux.cpython-312.pyc index 40b4a31..2016ea2 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/packaging/__pycache__/_manylinux.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/packaging/__pycache__/_manylinux.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/packaging/__pycache__/_musllinux.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/packaging/__pycache__/_musllinux.cpython-312.pyc index 51a4534..d5b949e 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/packaging/__pycache__/_musllinux.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/packaging/__pycache__/_musllinux.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/packaging/__pycache__/_structures.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/packaging/__pycache__/_structures.cpython-312.pyc index 6ad8a0b..e250512 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/packaging/__pycache__/_structures.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/packaging/__pycache__/_structures.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/packaging/__pycache__/markers.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/packaging/__pycache__/markers.cpython-312.pyc index a29b2e2..4e2245c 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/packaging/__pycache__/markers.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/packaging/__pycache__/markers.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/packaging/__pycache__/requirements.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/packaging/__pycache__/requirements.cpython-312.pyc index 591d54d..1354755 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/packaging/__pycache__/requirements.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/packaging/__pycache__/requirements.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/packaging/__pycache__/specifiers.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/packaging/__pycache__/specifiers.cpython-312.pyc index 53d89de..51c3b29 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/packaging/__pycache__/specifiers.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/packaging/__pycache__/specifiers.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/packaging/__pycache__/tags.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/packaging/__pycache__/tags.cpython-312.pyc index bcb7157..9cc67bc 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/packaging/__pycache__/tags.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/packaging/__pycache__/tags.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/packaging/__pycache__/utils.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/packaging/__pycache__/utils.cpython-312.pyc index 61a1210..bf201c1 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/packaging/__pycache__/utils.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/packaging/__pycache__/utils.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/packaging/__pycache__/version.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/packaging/__pycache__/version.cpython-312.pyc index 8d62ebe..7b1ab8a 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/packaging/__pycache__/version.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/packaging/__pycache__/version.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/pkg_resources/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/pkg_resources/__pycache__/__init__.cpython-312.pyc index 20e34e9..dedf722 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/pkg_resources/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/pkg_resources/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/platformdirs/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/platformdirs/__pycache__/__init__.cpython-312.pyc index d5f4823..5180828 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/platformdirs/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/platformdirs/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/platformdirs/__pycache__/__main__.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/platformdirs/__pycache__/__main__.cpython-312.pyc index 4a5972e..3a52ac3 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/platformdirs/__pycache__/__main__.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/platformdirs/__pycache__/__main__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/platformdirs/__pycache__/android.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/platformdirs/__pycache__/android.cpython-312.pyc index 0eda719..35858c0 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/platformdirs/__pycache__/android.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/platformdirs/__pycache__/android.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/platformdirs/__pycache__/api.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/platformdirs/__pycache__/api.cpython-312.pyc index c1b825f..4adcc37 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/platformdirs/__pycache__/api.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/platformdirs/__pycache__/api.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/platformdirs/__pycache__/macos.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/platformdirs/__pycache__/macos.cpython-312.pyc index e699ca3..231e296 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/platformdirs/__pycache__/macos.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/platformdirs/__pycache__/macos.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/platformdirs/__pycache__/unix.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/platformdirs/__pycache__/unix.cpython-312.pyc index 011f3e6..f3a20f9 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/platformdirs/__pycache__/unix.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/platformdirs/__pycache__/unix.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/platformdirs/__pycache__/version.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/platformdirs/__pycache__/version.cpython-312.pyc index 8c305af..da11e9d 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/platformdirs/__pycache__/version.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/platformdirs/__pycache__/version.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/platformdirs/__pycache__/windows.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/platformdirs/__pycache__/windows.cpython-312.pyc index 648b4eb..4428c45 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/platformdirs/__pycache__/windows.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/platformdirs/__pycache__/windows.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/__init__.cpython-312.pyc index e11e539..b17134a 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/__main__.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/__main__.cpython-312.pyc index bc0d182..78bccbf 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/__main__.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/__main__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/cmdline.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/cmdline.cpython-312.pyc index 904c2dc..56bb4e6 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/cmdline.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/cmdline.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/console.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/console.cpython-312.pyc index 2e21e1e..c8d0d1e 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/console.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/console.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/filter.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/filter.cpython-312.pyc index 9c7754e..8a68e5a 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/filter.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/filter.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/formatter.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/formatter.cpython-312.pyc index 98cae63..e783ad4 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/formatter.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/formatter.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/lexer.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/lexer.cpython-312.pyc index 3dffe70..f6d81ff 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/lexer.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/lexer.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/modeline.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/modeline.cpython-312.pyc index 140c7ea..432183b 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/modeline.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/modeline.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/plugin.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/plugin.cpython-312.pyc index 529b35e..ad85901 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/plugin.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/plugin.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/regexopt.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/regexopt.cpython-312.pyc index d120604..d0f07f1 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/regexopt.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/regexopt.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/scanner.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/scanner.cpython-312.pyc index b2abfd5..b8da7e4 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/scanner.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/scanner.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/sphinxext.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/sphinxext.cpython-312.pyc index da0861e..6396643 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/sphinxext.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/sphinxext.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/style.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/style.cpython-312.pyc index 40b27e2..89f5e7d 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/style.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/style.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/token.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/token.cpython-312.pyc index fc89a1c..5a08ae5 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/token.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/token.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/unistring.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/unistring.cpython-312.pyc index a261964..93a07aa 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/unistring.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/unistring.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/util.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/util.cpython-312.pyc index 908a993..dbbb80f 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/util.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/pygments/__pycache__/util.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/pygments/filters/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/pygments/filters/__pycache__/__init__.cpython-312.pyc index a392449..0282ad5 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/pygments/filters/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/pygments/filters/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/pygments/formatters/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/pygments/formatters/__pycache__/__init__.cpython-312.pyc index 3429a17..53367f8 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/pygments/formatters/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/pygments/formatters/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/pygments/formatters/__pycache__/_mapping.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/pygments/formatters/__pycache__/_mapping.cpython-312.pyc index 7490389..3a1dbfe 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/pygments/formatters/__pycache__/_mapping.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/pygments/formatters/__pycache__/_mapping.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/pygments/formatters/__pycache__/bbcode.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/pygments/formatters/__pycache__/bbcode.cpython-312.pyc index 3d155a5..cf6b2d8 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/pygments/formatters/__pycache__/bbcode.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/pygments/formatters/__pycache__/bbcode.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/pygments/formatters/__pycache__/groff.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/pygments/formatters/__pycache__/groff.cpython-312.pyc index 09c81a7..f212e97 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/pygments/formatters/__pycache__/groff.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/pygments/formatters/__pycache__/groff.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/pygments/formatters/__pycache__/html.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/pygments/formatters/__pycache__/html.cpython-312.pyc index 796a766..6160551 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/pygments/formatters/__pycache__/html.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/pygments/formatters/__pycache__/html.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/pygments/formatters/__pycache__/img.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/pygments/formatters/__pycache__/img.cpython-312.pyc index bc626eb..6c0a827 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/pygments/formatters/__pycache__/img.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/pygments/formatters/__pycache__/img.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/pygments/formatters/__pycache__/irc.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/pygments/formatters/__pycache__/irc.cpython-312.pyc index cb4224a..e5ecfd9 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/pygments/formatters/__pycache__/irc.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/pygments/formatters/__pycache__/irc.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/pygments/formatters/__pycache__/latex.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/pygments/formatters/__pycache__/latex.cpython-312.pyc index e818458..814c7f9 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/pygments/formatters/__pycache__/latex.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/pygments/formatters/__pycache__/latex.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/pygments/formatters/__pycache__/other.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/pygments/formatters/__pycache__/other.cpython-312.pyc index d8f0e2a..99ea1cf 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/pygments/formatters/__pycache__/other.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/pygments/formatters/__pycache__/other.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/pygments/formatters/__pycache__/pangomarkup.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/pygments/formatters/__pycache__/pangomarkup.cpython-312.pyc index fbd4c86..963bac1 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/pygments/formatters/__pycache__/pangomarkup.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/pygments/formatters/__pycache__/pangomarkup.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/pygments/formatters/__pycache__/rtf.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/pygments/formatters/__pycache__/rtf.cpython-312.pyc index 52f6e05..31ae50b 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/pygments/formatters/__pycache__/rtf.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/pygments/formatters/__pycache__/rtf.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/pygments/formatters/__pycache__/svg.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/pygments/formatters/__pycache__/svg.cpython-312.pyc index cb53703..9d0a206 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/pygments/formatters/__pycache__/svg.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/pygments/formatters/__pycache__/svg.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/pygments/formatters/__pycache__/terminal.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/pygments/formatters/__pycache__/terminal.cpython-312.pyc index 260b71a..0754e3a 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/pygments/formatters/__pycache__/terminal.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/pygments/formatters/__pycache__/terminal.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/pygments/formatters/__pycache__/terminal256.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/pygments/formatters/__pycache__/terminal256.cpython-312.pyc index 4effd91..4c80bda 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/pygments/formatters/__pycache__/terminal256.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/pygments/formatters/__pycache__/terminal256.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/pygments/lexers/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/pygments/lexers/__pycache__/__init__.cpython-312.pyc index 30cc5b8..617a683 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/pygments/lexers/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/pygments/lexers/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/pygments/lexers/__pycache__/_mapping.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/pygments/lexers/__pycache__/_mapping.cpython-312.pyc index 870a34c..e529c49 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/pygments/lexers/__pycache__/_mapping.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/pygments/lexers/__pycache__/_mapping.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/pygments/lexers/__pycache__/python.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/pygments/lexers/__pycache__/python.cpython-312.pyc index 1a05a36..2609246 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/pygments/lexers/__pycache__/python.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/pygments/lexers/__pycache__/python.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/pygments/styles/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/pygments/styles/__pycache__/__init__.cpython-312.pyc index d66f1db..cd33013 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/pygments/styles/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/pygments/styles/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/pyparsing/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/pyparsing/__pycache__/__init__.cpython-312.pyc index c813d22..737aacb 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/pyparsing/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/pyparsing/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/pyparsing/__pycache__/actions.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/pyparsing/__pycache__/actions.cpython-312.pyc index 0445577..5434b56 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/pyparsing/__pycache__/actions.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/pyparsing/__pycache__/actions.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/pyparsing/__pycache__/common.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/pyparsing/__pycache__/common.cpython-312.pyc index e3d4a7c..9b67f44 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/pyparsing/__pycache__/common.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/pyparsing/__pycache__/common.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/pyparsing/__pycache__/core.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/pyparsing/__pycache__/core.cpython-312.pyc index b4568d7..bc72f53 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/pyparsing/__pycache__/core.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/pyparsing/__pycache__/core.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/pyparsing/__pycache__/exceptions.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/pyparsing/__pycache__/exceptions.cpython-312.pyc index 504d9fc..400d23d 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/pyparsing/__pycache__/exceptions.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/pyparsing/__pycache__/exceptions.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/pyparsing/__pycache__/helpers.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/pyparsing/__pycache__/helpers.cpython-312.pyc index c404a61..f422c73 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/pyparsing/__pycache__/helpers.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/pyparsing/__pycache__/helpers.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/pyparsing/__pycache__/results.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/pyparsing/__pycache__/results.cpython-312.pyc index 7229331..e2a02fb 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/pyparsing/__pycache__/results.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/pyparsing/__pycache__/results.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/pyparsing/__pycache__/testing.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/pyparsing/__pycache__/testing.cpython-312.pyc index 5c02a86..5252e59 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/pyparsing/__pycache__/testing.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/pyparsing/__pycache__/testing.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/pyparsing/__pycache__/unicode.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/pyparsing/__pycache__/unicode.cpython-312.pyc index e0cea05..ecb45ae 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/pyparsing/__pycache__/unicode.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/pyparsing/__pycache__/unicode.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/pyparsing/__pycache__/util.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/pyparsing/__pycache__/util.cpython-312.pyc index 451c383..5ea32d2 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/pyparsing/__pycache__/util.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/pyparsing/__pycache__/util.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/pyparsing/diagram/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/pyparsing/diagram/__pycache__/__init__.cpython-312.pyc index a5d54f7..9dd215f 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/pyparsing/diagram/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/pyparsing/diagram/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/pyproject_hooks/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/pyproject_hooks/__pycache__/__init__.cpython-312.pyc index 36ef6ca..708ae26 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/pyproject_hooks/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/pyproject_hooks/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/pyproject_hooks/__pycache__/_compat.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/pyproject_hooks/__pycache__/_compat.cpython-312.pyc index f6d3b52..b6fae72 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/pyproject_hooks/__pycache__/_compat.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/pyproject_hooks/__pycache__/_compat.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/pyproject_hooks/__pycache__/_impl.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/pyproject_hooks/__pycache__/_impl.cpython-312.pyc index df48a18..0567e96 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/pyproject_hooks/__pycache__/_impl.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/pyproject_hooks/__pycache__/_impl.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/pyproject_hooks/_in_process/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/pyproject_hooks/_in_process/__pycache__/__init__.cpython-312.pyc index 538e6ed..98a022d 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/pyproject_hooks/_in_process/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/pyproject_hooks/_in_process/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/pyproject_hooks/_in_process/__pycache__/_in_process.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/pyproject_hooks/_in_process/__pycache__/_in_process.cpython-312.pyc index 82d91b5..137caad 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/pyproject_hooks/_in_process/__pycache__/_in_process.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/pyproject_hooks/_in_process/__pycache__/_in_process.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/requests/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/requests/__pycache__/__init__.cpython-312.pyc index b9662ef..5e3c9be 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/requests/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/requests/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/requests/__pycache__/__version__.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/requests/__pycache__/__version__.cpython-312.pyc index 66919ef..4474fc8 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/requests/__pycache__/__version__.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/requests/__pycache__/__version__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/requests/__pycache__/_internal_utils.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/requests/__pycache__/_internal_utils.cpython-312.pyc index 591df79..eb9eeff 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/requests/__pycache__/_internal_utils.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/requests/__pycache__/_internal_utils.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/requests/__pycache__/adapters.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/requests/__pycache__/adapters.cpython-312.pyc index cb12cc6..3a1e267 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/requests/__pycache__/adapters.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/requests/__pycache__/adapters.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/requests/__pycache__/api.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/requests/__pycache__/api.cpython-312.pyc index 404b0cf..683befe 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/requests/__pycache__/api.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/requests/__pycache__/api.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/requests/__pycache__/auth.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/requests/__pycache__/auth.cpython-312.pyc index 5579e05..7f791b5 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/requests/__pycache__/auth.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/requests/__pycache__/auth.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/requests/__pycache__/certs.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/requests/__pycache__/certs.cpython-312.pyc index 9f25481..10ee9de 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/requests/__pycache__/certs.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/requests/__pycache__/certs.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/requests/__pycache__/compat.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/requests/__pycache__/compat.cpython-312.pyc index 9690574..2d378ec 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/requests/__pycache__/compat.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/requests/__pycache__/compat.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/requests/__pycache__/cookies.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/requests/__pycache__/cookies.cpython-312.pyc index ac39b0b..6f9269a 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/requests/__pycache__/cookies.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/requests/__pycache__/cookies.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/requests/__pycache__/exceptions.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/requests/__pycache__/exceptions.cpython-312.pyc index 2b6ab9d..5943dcb 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/requests/__pycache__/exceptions.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/requests/__pycache__/exceptions.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/requests/__pycache__/help.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/requests/__pycache__/help.cpython-312.pyc index 711945f..b5fa867 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/requests/__pycache__/help.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/requests/__pycache__/help.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/requests/__pycache__/hooks.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/requests/__pycache__/hooks.cpython-312.pyc index 96a10cf..569ea49 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/requests/__pycache__/hooks.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/requests/__pycache__/hooks.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/requests/__pycache__/models.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/requests/__pycache__/models.cpython-312.pyc index 5f1c6d4..34b8d2f 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/requests/__pycache__/models.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/requests/__pycache__/models.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/requests/__pycache__/packages.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/requests/__pycache__/packages.cpython-312.pyc index 7273779..b840743 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/requests/__pycache__/packages.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/requests/__pycache__/packages.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/requests/__pycache__/sessions.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/requests/__pycache__/sessions.cpython-312.pyc index 366d0ee..f060f46 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/requests/__pycache__/sessions.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/requests/__pycache__/sessions.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/requests/__pycache__/status_codes.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/requests/__pycache__/status_codes.cpython-312.pyc index 2e38212..395e7c4 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/requests/__pycache__/status_codes.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/requests/__pycache__/status_codes.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/requests/__pycache__/structures.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/requests/__pycache__/structures.cpython-312.pyc index 1c2c97e..bfd797e 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/requests/__pycache__/structures.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/requests/__pycache__/structures.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/requests/__pycache__/utils.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/requests/__pycache__/utils.cpython-312.pyc index e543dcf..9697c25 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/requests/__pycache__/utils.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/requests/__pycache__/utils.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/resolvelib/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/resolvelib/__pycache__/__init__.cpython-312.pyc index 2843987..6a716e1 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/resolvelib/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/resolvelib/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/resolvelib/__pycache__/providers.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/resolvelib/__pycache__/providers.cpython-312.pyc index 39303e3..8864a40 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/resolvelib/__pycache__/providers.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/resolvelib/__pycache__/providers.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/resolvelib/__pycache__/reporters.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/resolvelib/__pycache__/reporters.cpython-312.pyc index 20286c6..a133824 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/resolvelib/__pycache__/reporters.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/resolvelib/__pycache__/reporters.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/resolvelib/__pycache__/resolvers.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/resolvelib/__pycache__/resolvers.cpython-312.pyc index b08cf20..037ed3e 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/resolvelib/__pycache__/resolvers.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/resolvelib/__pycache__/resolvers.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/resolvelib/__pycache__/structs.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/resolvelib/__pycache__/structs.cpython-312.pyc index 2b30840..c319307 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/resolvelib/__pycache__/structs.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/resolvelib/__pycache__/structs.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/resolvelib/compat/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/resolvelib/compat/__pycache__/__init__.cpython-312.pyc index 5dffe32..cc73371 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/resolvelib/compat/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/resolvelib/compat/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/resolvelib/compat/__pycache__/collections_abc.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/resolvelib/compat/__pycache__/collections_abc.cpython-312.pyc index 561e3db..a8a5ae2 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/resolvelib/compat/__pycache__/collections_abc.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/resolvelib/compat/__pycache__/collections_abc.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/__init__.cpython-312.pyc index 95d2bd9..feba621 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/__main__.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/__main__.cpython-312.pyc index 8e47114..014d62d 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/__main__.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/__main__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_cell_widths.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_cell_widths.cpython-312.pyc index 8c7f785..9584674 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_cell_widths.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_cell_widths.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_emoji_codes.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_emoji_codes.cpython-312.pyc index 8564c17..8cbed20 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_emoji_codes.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_emoji_codes.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_emoji_replace.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_emoji_replace.cpython-312.pyc index cd4ab90..f9c00ff 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_emoji_replace.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_emoji_replace.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_export_format.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_export_format.cpython-312.pyc index 56ce861..b62c873 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_export_format.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_export_format.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_extension.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_extension.cpython-312.pyc index a337002..443fec3 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_extension.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_extension.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_fileno.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_fileno.cpython-312.pyc index 532c084..f23352d 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_fileno.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_fileno.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_inspect.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_inspect.cpython-312.pyc index 232bbd8..309ed9e 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_inspect.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_inspect.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_log_render.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_log_render.cpython-312.pyc index 22e4c37..7c363c0 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_log_render.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_log_render.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_loop.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_loop.cpython-312.pyc index 525a01b..543575f 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_loop.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_loop.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_null_file.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_null_file.cpython-312.pyc index 4536e62..86eb62d 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_null_file.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_null_file.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_palettes.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_palettes.cpython-312.pyc index 5da2e9f..e43df8d 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_palettes.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_palettes.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_pick.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_pick.cpython-312.pyc index b922326..ce4eea0 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_pick.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_pick.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_ratio.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_ratio.cpython-312.pyc index 1896e85..f799b6f 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_ratio.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_ratio.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_spinners.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_spinners.cpython-312.pyc index ba598be..f16217f 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_spinners.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_spinners.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_stack.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_stack.cpython-312.pyc index 342c48c..640569e 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_stack.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_stack.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_timer.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_timer.cpython-312.pyc index 5f87911..bea559d 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_timer.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_timer.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_win32_console.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_win32_console.cpython-312.pyc index 7232ca2..e01352d 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_win32_console.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_win32_console.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_windows.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_windows.cpython-312.pyc index c593452..f9f70a8 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_windows.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_windows.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_windows_renderer.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_windows_renderer.cpython-312.pyc index 4c3acff..8b88a0d 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_windows_renderer.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_windows_renderer.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_wrap.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_wrap.cpython-312.pyc index 97ff085..d876b6e 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_wrap.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/_wrap.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/abc.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/abc.cpython-312.pyc index 8d494fa..1d38e9a 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/abc.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/abc.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/align.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/align.cpython-312.pyc index 8769432..93e9f83 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/align.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/align.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/ansi.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/ansi.cpython-312.pyc index 9b4b955..7dab55a 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/ansi.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/ansi.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/bar.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/bar.cpython-312.pyc index dad07d5..5c249c8 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/bar.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/bar.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/box.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/box.cpython-312.pyc index ec2f5af..0273347 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/box.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/box.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/cells.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/cells.cpython-312.pyc index e900527..863dc20 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/cells.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/cells.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/color.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/color.cpython-312.pyc index fc28bb4..33dfba1 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/color.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/color.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/color_triplet.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/color_triplet.cpython-312.pyc index cec8e28..df1f4d8 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/color_triplet.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/color_triplet.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/columns.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/columns.cpython-312.pyc index b02c993..4f29f21 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/columns.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/columns.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/console.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/console.cpython-312.pyc index 6da438f..c46fd56 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/console.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/console.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/constrain.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/constrain.cpython-312.pyc index e2557c7..2901d96 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/constrain.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/constrain.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/containers.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/containers.cpython-312.pyc index 19853a2..0c1eadc 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/containers.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/containers.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/control.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/control.cpython-312.pyc index 7899c1a..9781451 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/control.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/control.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/default_styles.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/default_styles.cpython-312.pyc index e43253d..678d16c 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/default_styles.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/default_styles.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/diagnose.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/diagnose.cpython-312.pyc index 4b1a34c..c9cc837 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/diagnose.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/diagnose.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/emoji.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/emoji.cpython-312.pyc index a8fe2a3..a0aaa6a 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/emoji.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/emoji.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/errors.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/errors.cpython-312.pyc index 786fe86..93b2c4d 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/errors.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/errors.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/file_proxy.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/file_proxy.cpython-312.pyc index 73f2f3f..4ce96c1 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/file_proxy.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/file_proxy.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/filesize.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/filesize.cpython-312.pyc index 894b1f2..281d5f9 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/filesize.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/filesize.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/highlighter.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/highlighter.cpython-312.pyc index c9f6195..7880939 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/highlighter.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/highlighter.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/json.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/json.cpython-312.pyc index cb6cb03..948ef3b 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/json.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/json.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/jupyter.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/jupyter.cpython-312.pyc index 9b58cd4..a515c24 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/jupyter.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/jupyter.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/layout.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/layout.cpython-312.pyc index a390f37..2857cf2 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/layout.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/layout.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/live.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/live.cpython-312.pyc index f4e5e5f..b272fe8 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/live.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/live.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/live_render.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/live_render.cpython-312.pyc index bbc152b..81b3145 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/live_render.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/live_render.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/logging.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/logging.cpython-312.pyc index e1e1046..e482d6c 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/logging.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/logging.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/markup.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/markup.cpython-312.pyc index 41307c7..b0ff53b 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/markup.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/markup.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/measure.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/measure.cpython-312.pyc index d5e57ab..cd5bf73 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/measure.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/measure.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/padding.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/padding.cpython-312.pyc index 34d4665..2e2891d 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/padding.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/padding.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/pager.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/pager.cpython-312.pyc index 2e54e2a..218bf80 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/pager.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/pager.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/palette.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/palette.cpython-312.pyc index 3840c5f..be9e737 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/palette.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/palette.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/panel.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/panel.cpython-312.pyc index f9986f6..b2ae77b 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/panel.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/panel.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/pretty.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/pretty.cpython-312.pyc index 7643513..c4b8490 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/pretty.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/pretty.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/progress.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/progress.cpython-312.pyc index a47c87a..29c5e3b 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/progress.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/progress.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/progress_bar.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/progress_bar.cpython-312.pyc index 40855a1..b2edb01 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/progress_bar.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/progress_bar.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/prompt.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/prompt.cpython-312.pyc index 4d4b027..55e6fed 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/prompt.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/prompt.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/protocol.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/protocol.cpython-312.pyc index c3bd38e..93bb8dd 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/protocol.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/protocol.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/region.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/region.cpython-312.pyc index 06674e4..319e42a 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/region.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/region.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/repr.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/repr.cpython-312.pyc index 1e70388..1503a0f 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/repr.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/repr.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/rule.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/rule.cpython-312.pyc index 16cf9f0..e5960e5 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/rule.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/rule.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/scope.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/scope.cpython-312.pyc index 620cd1d..9b47313 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/scope.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/scope.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/screen.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/screen.cpython-312.pyc index adccbf0..379b73a 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/screen.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/screen.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/segment.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/segment.cpython-312.pyc index 5cf0443..8714c1a 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/segment.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/segment.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/spinner.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/spinner.cpython-312.pyc index 4260d10..9c45ab2 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/spinner.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/spinner.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/status.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/status.cpython-312.pyc index 5553927..be946a3 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/status.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/status.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/style.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/style.cpython-312.pyc index 5a81733..2f1daac 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/style.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/style.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/styled.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/styled.cpython-312.pyc index 9030dca..a469417 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/styled.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/styled.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/syntax.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/syntax.cpython-312.pyc index 0e16031..87109e6 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/syntax.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/syntax.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/table.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/table.cpython-312.pyc index 3eb719c..cc43542 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/table.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/table.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/terminal_theme.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/terminal_theme.cpython-312.pyc index 65025de..4a25d87 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/terminal_theme.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/terminal_theme.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/text.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/text.cpython-312.pyc index 2343179..7338b72 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/text.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/text.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/theme.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/theme.cpython-312.pyc index f728b07..0ece919 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/theme.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/theme.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/themes.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/themes.cpython-312.pyc index 1b56790..083da4b 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/themes.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/themes.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/traceback.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/traceback.cpython-312.pyc index f4c8b22..31ca426 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/traceback.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/traceback.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/tree.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/tree.cpython-312.pyc index 0cd7553..1fb37fc 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/tree.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/rich/__pycache__/tree.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/tenacity/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/tenacity/__pycache__/__init__.cpython-312.pyc index c4b8600..9c8479d 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/tenacity/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/tenacity/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/tenacity/__pycache__/_asyncio.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/tenacity/__pycache__/_asyncio.cpython-312.pyc index 20acd37..f7412a8 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/tenacity/__pycache__/_asyncio.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/tenacity/__pycache__/_asyncio.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/tenacity/__pycache__/_utils.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/tenacity/__pycache__/_utils.cpython-312.pyc index 138b916..46a38db 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/tenacity/__pycache__/_utils.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/tenacity/__pycache__/_utils.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/tenacity/__pycache__/after.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/tenacity/__pycache__/after.cpython-312.pyc index 5c8c72c..283d839 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/tenacity/__pycache__/after.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/tenacity/__pycache__/after.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/tenacity/__pycache__/before.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/tenacity/__pycache__/before.cpython-312.pyc index 7fb8065..556caa4 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/tenacity/__pycache__/before.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/tenacity/__pycache__/before.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/tenacity/__pycache__/before_sleep.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/tenacity/__pycache__/before_sleep.cpython-312.pyc index f0192e8..1e781ef 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/tenacity/__pycache__/before_sleep.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/tenacity/__pycache__/before_sleep.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/tenacity/__pycache__/nap.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/tenacity/__pycache__/nap.cpython-312.pyc index 419f81a..599d07d 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/tenacity/__pycache__/nap.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/tenacity/__pycache__/nap.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/tenacity/__pycache__/retry.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/tenacity/__pycache__/retry.cpython-312.pyc index 0c65ac3..3c8cc18 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/tenacity/__pycache__/retry.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/tenacity/__pycache__/retry.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/tenacity/__pycache__/stop.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/tenacity/__pycache__/stop.cpython-312.pyc index 0e95e5c..fe56f13 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/tenacity/__pycache__/stop.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/tenacity/__pycache__/stop.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/tenacity/__pycache__/tornadoweb.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/tenacity/__pycache__/tornadoweb.cpython-312.pyc index b849539..32ebb7f 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/tenacity/__pycache__/tornadoweb.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/tenacity/__pycache__/tornadoweb.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/tenacity/__pycache__/wait.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/tenacity/__pycache__/wait.cpython-312.pyc index b775455..8dec03b 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/tenacity/__pycache__/wait.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/tenacity/__pycache__/wait.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/tomli/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/tomli/__pycache__/__init__.cpython-312.pyc index 70ac52f..bdd4029 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/tomli/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/tomli/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/tomli/__pycache__/_parser.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/tomli/__pycache__/_parser.cpython-312.pyc index 1bb4688..803e8f0 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/tomli/__pycache__/_parser.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/tomli/__pycache__/_parser.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/tomli/__pycache__/_re.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/tomli/__pycache__/_re.cpython-312.pyc index e2b657c..97834b1 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/tomli/__pycache__/_re.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/tomli/__pycache__/_re.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/tomli/__pycache__/_types.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/tomli/__pycache__/_types.cpython-312.pyc index 6d3876b..3a822fd 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/tomli/__pycache__/_types.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/tomli/__pycache__/_types.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/truststore/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/truststore/__pycache__/__init__.cpython-312.pyc index 3c63a01..b8de432 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/truststore/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/truststore/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/truststore/__pycache__/_api.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/truststore/__pycache__/_api.cpython-312.pyc index 5cb414d..fd6c458 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/truststore/__pycache__/_api.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/truststore/__pycache__/_api.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/truststore/__pycache__/_macos.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/truststore/__pycache__/_macos.cpython-312.pyc index 7d9c221..f81f706 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/truststore/__pycache__/_macos.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/truststore/__pycache__/_macos.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/truststore/__pycache__/_openssl.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/truststore/__pycache__/_openssl.cpython-312.pyc index 5621498..d858cb8 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/truststore/__pycache__/_openssl.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/truststore/__pycache__/_openssl.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/truststore/__pycache__/_ssl_constants.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/truststore/__pycache__/_ssl_constants.cpython-312.pyc index f0cb039..09eba1b 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/truststore/__pycache__/_ssl_constants.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/truststore/__pycache__/_ssl_constants.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/truststore/__pycache__/_windows.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/truststore/__pycache__/_windows.cpython-312.pyc index c0b7ba9..a2c5ded 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/truststore/__pycache__/_windows.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/truststore/__pycache__/_windows.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/urllib3/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/urllib3/__pycache__/__init__.cpython-312.pyc index 2847af4..dd05d0d 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/urllib3/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/urllib3/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/urllib3/__pycache__/_collections.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/urllib3/__pycache__/_collections.cpython-312.pyc index 9b1b661..7e3cb72 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/urllib3/__pycache__/_collections.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/urllib3/__pycache__/_collections.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/urllib3/__pycache__/_version.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/urllib3/__pycache__/_version.cpython-312.pyc index 74d83eb..69e9142 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/urllib3/__pycache__/_version.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/urllib3/__pycache__/_version.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/urllib3/__pycache__/connection.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/urllib3/__pycache__/connection.cpython-312.pyc index cc597fa..e5a05f9 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/urllib3/__pycache__/connection.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/urllib3/__pycache__/connection.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/urllib3/__pycache__/connectionpool.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/urllib3/__pycache__/connectionpool.cpython-312.pyc index 592a2ed..941da8f 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/urllib3/__pycache__/connectionpool.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/urllib3/__pycache__/connectionpool.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/urllib3/__pycache__/exceptions.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/urllib3/__pycache__/exceptions.cpython-312.pyc index 8cc4e58..58511c9 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/urllib3/__pycache__/exceptions.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/urllib3/__pycache__/exceptions.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/urllib3/__pycache__/fields.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/urllib3/__pycache__/fields.cpython-312.pyc index 2ef9365..51ac65d 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/urllib3/__pycache__/fields.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/urllib3/__pycache__/fields.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/urllib3/__pycache__/filepost.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/urllib3/__pycache__/filepost.cpython-312.pyc index 9f56bbe..2fc9f9b 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/urllib3/__pycache__/filepost.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/urllib3/__pycache__/filepost.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/urllib3/__pycache__/poolmanager.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/urllib3/__pycache__/poolmanager.cpython-312.pyc index 830a3af..364b77c 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/urllib3/__pycache__/poolmanager.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/urllib3/__pycache__/poolmanager.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/urllib3/__pycache__/request.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/urllib3/__pycache__/request.cpython-312.pyc index 57b2775..11973b8 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/urllib3/__pycache__/request.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/urllib3/__pycache__/request.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/urllib3/__pycache__/response.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/urllib3/__pycache__/response.cpython-312.pyc index 76718b2..9af10d4 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/urllib3/__pycache__/response.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/urllib3/__pycache__/response.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/__pycache__/__init__.cpython-312.pyc index fbf4eeb..2a5a044 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/__pycache__/_appengine_environ.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/__pycache__/_appengine_environ.cpython-312.pyc index daea13b..9239042 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/__pycache__/_appengine_environ.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/__pycache__/_appengine_environ.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/__pycache__/appengine.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/__pycache__/appengine.cpython-312.pyc index 1190162..0fc16f5 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/__pycache__/appengine.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/__pycache__/appengine.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/__pycache__/ntlmpool.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/__pycache__/ntlmpool.cpython-312.pyc index 34a095d..2e4cfcf 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/__pycache__/ntlmpool.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/__pycache__/ntlmpool.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/__pycache__/pyopenssl.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/__pycache__/pyopenssl.cpython-312.pyc index eb5d8c4..7d72424 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/__pycache__/pyopenssl.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/__pycache__/pyopenssl.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/__pycache__/securetransport.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/__pycache__/securetransport.cpython-312.pyc index 2e3fef8..ee6916c 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/__pycache__/securetransport.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/__pycache__/securetransport.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/__pycache__/socks.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/__pycache__/socks.cpython-312.pyc index 2f04b57..07e14bf 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/__pycache__/socks.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/__pycache__/socks.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/_securetransport/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/_securetransport/__pycache__/__init__.cpython-312.pyc index 8ae75fd..2881143 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/_securetransport/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/_securetransport/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/_securetransport/__pycache__/bindings.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/_securetransport/__pycache__/bindings.cpython-312.pyc index 1140271..2afcf3a 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/_securetransport/__pycache__/bindings.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/_securetransport/__pycache__/bindings.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/_securetransport/__pycache__/low_level.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/_securetransport/__pycache__/low_level.cpython-312.pyc index 54ce97f..ffe2411 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/_securetransport/__pycache__/low_level.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/urllib3/contrib/_securetransport/__pycache__/low_level.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/urllib3/packages/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/urllib3/packages/__pycache__/__init__.cpython-312.pyc index 8095a52..d00f61c 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/urllib3/packages/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/urllib3/packages/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/urllib3/packages/__pycache__/six.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/urllib3/packages/__pycache__/six.cpython-312.pyc index 86b81f8..03e0e58 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/urllib3/packages/__pycache__/six.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/urllib3/packages/__pycache__/six.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/urllib3/packages/backports/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/urllib3/packages/backports/__pycache__/__init__.cpython-312.pyc index 4d35eaf..1fb8127 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/urllib3/packages/backports/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/urllib3/packages/backports/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/urllib3/packages/backports/__pycache__/makefile.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/urllib3/packages/backports/__pycache__/makefile.cpython-312.pyc index b963a75..449cd6f 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/urllib3/packages/backports/__pycache__/makefile.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/urllib3/packages/backports/__pycache__/makefile.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/urllib3/packages/backports/__pycache__/weakref_finalize.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/urllib3/packages/backports/__pycache__/weakref_finalize.cpython-312.pyc index 5ee9aac..bd5a269 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/urllib3/packages/backports/__pycache__/weakref_finalize.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/urllib3/packages/backports/__pycache__/weakref_finalize.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/urllib3/util/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/urllib3/util/__pycache__/__init__.cpython-312.pyc index f8d3a25..eebeadb 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/urllib3/util/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/urllib3/util/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/urllib3/util/__pycache__/connection.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/urllib3/util/__pycache__/connection.cpython-312.pyc index a0ff33c..0d29d81 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/urllib3/util/__pycache__/connection.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/urllib3/util/__pycache__/connection.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/urllib3/util/__pycache__/proxy.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/urllib3/util/__pycache__/proxy.cpython-312.pyc index 281efd8..ce0e08e 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/urllib3/util/__pycache__/proxy.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/urllib3/util/__pycache__/proxy.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/urllib3/util/__pycache__/queue.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/urllib3/util/__pycache__/queue.cpython-312.pyc index f0b2b10..41e2bc3 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/urllib3/util/__pycache__/queue.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/urllib3/util/__pycache__/queue.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/urllib3/util/__pycache__/request.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/urllib3/util/__pycache__/request.cpython-312.pyc index 320a69f..f506c6f 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/urllib3/util/__pycache__/request.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/urllib3/util/__pycache__/request.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/urllib3/util/__pycache__/response.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/urllib3/util/__pycache__/response.cpython-312.pyc index 10230b3..353c915 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/urllib3/util/__pycache__/response.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/urllib3/util/__pycache__/response.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/urllib3/util/__pycache__/retry.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/urllib3/util/__pycache__/retry.cpython-312.pyc index f386fe6..4cff1e0 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/urllib3/util/__pycache__/retry.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/urllib3/util/__pycache__/retry.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/urllib3/util/__pycache__/ssl_.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/urllib3/util/__pycache__/ssl_.cpython-312.pyc index acbdb82..a78fb78 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/urllib3/util/__pycache__/ssl_.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/urllib3/util/__pycache__/ssl_.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/urllib3/util/__pycache__/ssl_match_hostname.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/urllib3/util/__pycache__/ssl_match_hostname.cpython-312.pyc index 88649db..9844b42 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/urllib3/util/__pycache__/ssl_match_hostname.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/urllib3/util/__pycache__/ssl_match_hostname.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/urllib3/util/__pycache__/ssltransport.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/urllib3/util/__pycache__/ssltransport.cpython-312.pyc index dbb1df1..d1df55c 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/urllib3/util/__pycache__/ssltransport.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/urllib3/util/__pycache__/ssltransport.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/urllib3/util/__pycache__/timeout.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/urllib3/util/__pycache__/timeout.cpython-312.pyc index 98d306d..fc3b307 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/urllib3/util/__pycache__/timeout.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/urllib3/util/__pycache__/timeout.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/urllib3/util/__pycache__/url.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/urllib3/util/__pycache__/url.cpython-312.pyc index b1d221a..067aeaf 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/urllib3/util/__pycache__/url.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/urllib3/util/__pycache__/url.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/urllib3/util/__pycache__/wait.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/urllib3/util/__pycache__/wait.cpython-312.pyc index e2dd3ac..eeca8d8 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/urllib3/util/__pycache__/wait.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/urllib3/util/__pycache__/wait.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/webencodings/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/webencodings/__pycache__/__init__.cpython-312.pyc index ce78c24..8057eca 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/webencodings/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/webencodings/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/webencodings/__pycache__/labels.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/webencodings/__pycache__/labels.cpython-312.pyc index 34bd41e..15b5cfd 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/webencodings/__pycache__/labels.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/webencodings/__pycache__/labels.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/webencodings/__pycache__/mklabels.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/webencodings/__pycache__/mklabels.cpython-312.pyc index 34d6342..2796922 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/webencodings/__pycache__/mklabels.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/webencodings/__pycache__/mklabels.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/webencodings/__pycache__/tests.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/webencodings/__pycache__/tests.cpython-312.pyc index 7336e0a..77ad9d3 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/webencodings/__pycache__/tests.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/webencodings/__pycache__/tests.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pip/_vendor/webencodings/__pycache__/x_user_defined.cpython-312.pyc b/venv/Lib/site-packages/pip/_vendor/webencodings/__pycache__/x_user_defined.cpython-312.pyc index 9ff8d8d..cd60178 100644 Binary files a/venv/Lib/site-packages/pip/_vendor/webencodings/__pycache__/x_user_defined.cpython-312.pyc and b/venv/Lib/site-packages/pip/_vendor/webencodings/__pycache__/x_user_defined.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/propcache-0.4.1.dist-info/RECORD b/venv/Lib/site-packages/propcache-0.4.1.dist-info/RECORD index 4e7f77f..2a45154 100644 --- a/venv/Lib/site-packages/propcache-0.4.1.dist-info/RECORD +++ b/venv/Lib/site-packages/propcache-0.4.1.dist-info/RECORD @@ -1,6 +1,7 @@ propcache-0.4.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 propcache-0.4.1.dist-info/METADATA,sha256=uH_-mZacCpex3PvgM5lxCcQRoVNcys9To6caNbJAlz0,14188 propcache-0.4.1.dist-info/RECORD,, +propcache-0.4.1.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 propcache-0.4.1.dist-info/WHEEL,sha256=8UP9x9puWI0P1V_d7K2oMTBqfeLNm21CTzZ_Ptr0NXU,101 propcache-0.4.1.dist-info/licenses/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358 propcache-0.4.1.dist-info/licenses/NOTICE,sha256=VtasbIEFwKUTBMIdsGDjYa-ajqCvmnXCOcKLXRNpODg,609 diff --git a/venv/Lib/site-packages/propcache-0.4.1.dist-info/REQUESTED b/venv/Lib/site-packages/propcache-0.4.1.dist-info/REQUESTED new file mode 100644 index 0000000..e69de29 diff --git a/venv/Lib/site-packages/propcache/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/propcache/__pycache__/__init__.cpython-312.pyc index a81f826..266b98b 100644 Binary files a/venv/Lib/site-packages/propcache/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/propcache/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/propcache/__pycache__/_helpers.cpython-312.pyc b/venv/Lib/site-packages/propcache/__pycache__/_helpers.cpython-312.pyc index 4ea2851..1a239c2 100644 Binary files a/venv/Lib/site-packages/propcache/__pycache__/_helpers.cpython-312.pyc and b/venv/Lib/site-packages/propcache/__pycache__/_helpers.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/propcache/__pycache__/_helpers_py.cpython-312.pyc b/venv/Lib/site-packages/propcache/__pycache__/_helpers_py.cpython-312.pyc index 806a47c..9c1b73d 100644 Binary files a/venv/Lib/site-packages/propcache/__pycache__/_helpers_py.cpython-312.pyc and b/venv/Lib/site-packages/propcache/__pycache__/_helpers_py.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/propcache/__pycache__/api.cpython-312.pyc b/venv/Lib/site-packages/propcache/__pycache__/api.cpython-312.pyc index 6fe66f2..0c1fb58 100644 Binary files a/venv/Lib/site-packages/propcache/__pycache__/api.cpython-312.pyc and b/venv/Lib/site-packages/propcache/__pycache__/api.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/psycopg2/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/psycopg2/__pycache__/__init__.cpython-312.pyc index 800282a..7df0e15 100644 Binary files a/venv/Lib/site-packages/psycopg2/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/psycopg2/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/psycopg2/__pycache__/_ipaddress.cpython-312.pyc b/venv/Lib/site-packages/psycopg2/__pycache__/_ipaddress.cpython-312.pyc index 5500721..34017b2 100644 Binary files a/venv/Lib/site-packages/psycopg2/__pycache__/_ipaddress.cpython-312.pyc and b/venv/Lib/site-packages/psycopg2/__pycache__/_ipaddress.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/psycopg2/__pycache__/_json.cpython-312.pyc b/venv/Lib/site-packages/psycopg2/__pycache__/_json.cpython-312.pyc index 0fe3518..f65b863 100644 Binary files a/venv/Lib/site-packages/psycopg2/__pycache__/_json.cpython-312.pyc and b/venv/Lib/site-packages/psycopg2/__pycache__/_json.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/psycopg2/__pycache__/_range.cpython-312.pyc b/venv/Lib/site-packages/psycopg2/__pycache__/_range.cpython-312.pyc index dd69bba..c8e2742 100644 Binary files a/venv/Lib/site-packages/psycopg2/__pycache__/_range.cpython-312.pyc and b/venv/Lib/site-packages/psycopg2/__pycache__/_range.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/psycopg2/__pycache__/errorcodes.cpython-312.pyc b/venv/Lib/site-packages/psycopg2/__pycache__/errorcodes.cpython-312.pyc index 0df9793..cd2e9d8 100644 Binary files a/venv/Lib/site-packages/psycopg2/__pycache__/errorcodes.cpython-312.pyc and b/venv/Lib/site-packages/psycopg2/__pycache__/errorcodes.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/psycopg2/__pycache__/errors.cpython-312.pyc b/venv/Lib/site-packages/psycopg2/__pycache__/errors.cpython-312.pyc index 88e8830..2b926c8 100644 Binary files a/venv/Lib/site-packages/psycopg2/__pycache__/errors.cpython-312.pyc and b/venv/Lib/site-packages/psycopg2/__pycache__/errors.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/psycopg2/__pycache__/extensions.cpython-312.pyc b/venv/Lib/site-packages/psycopg2/__pycache__/extensions.cpython-312.pyc index 798acba..5134503 100644 Binary files a/venv/Lib/site-packages/psycopg2/__pycache__/extensions.cpython-312.pyc and b/venv/Lib/site-packages/psycopg2/__pycache__/extensions.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/psycopg2/__pycache__/extras.cpython-312.pyc b/venv/Lib/site-packages/psycopg2/__pycache__/extras.cpython-312.pyc index d593174..490c798 100644 Binary files a/venv/Lib/site-packages/psycopg2/__pycache__/extras.cpython-312.pyc and b/venv/Lib/site-packages/psycopg2/__pycache__/extras.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/psycopg2/__pycache__/pool.cpython-312.pyc b/venv/Lib/site-packages/psycopg2/__pycache__/pool.cpython-312.pyc index 923afa6..ebcc38d 100644 Binary files a/venv/Lib/site-packages/psycopg2/__pycache__/pool.cpython-312.pyc and b/venv/Lib/site-packages/psycopg2/__pycache__/pool.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/psycopg2/__pycache__/sql.cpython-312.pyc b/venv/Lib/site-packages/psycopg2/__pycache__/sql.cpython-312.pyc index dd45161..0e2bb06 100644 Binary files a/venv/Lib/site-packages/psycopg2/__pycache__/sql.cpython-312.pyc and b/venv/Lib/site-packages/psycopg2/__pycache__/sql.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/psycopg2/__pycache__/tz.cpython-312.pyc b/venv/Lib/site-packages/psycopg2/__pycache__/tz.cpython-312.pyc index eb9aed9..622688f 100644 Binary files a/venv/Lib/site-packages/psycopg2/__pycache__/tz.cpython-312.pyc and b/venv/Lib/site-packages/psycopg2/__pycache__/tz.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pycparser-2.23.dist-info/RECORD b/venv/Lib/site-packages/pycparser-2.23.dist-info/RECORD index 4e9376b..cc09bb8 100644 --- a/venv/Lib/site-packages/pycparser-2.23.dist-info/RECORD +++ b/venv/Lib/site-packages/pycparser-2.23.dist-info/RECORD @@ -2,6 +2,7 @@ pycparser-2.23.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNu pycparser-2.23.dist-info/LICENSE,sha256=DIRjmTaep23de1xE_m0WSXQV_PAV9cu1CMJL-YuBxbE,1543 pycparser-2.23.dist-info/METADATA,sha256=osmhHMxa3n5sPwv5WeUpyyPnm76eohXYGZyKGmWbPFc,993 pycparser-2.23.dist-info/RECORD,, +pycparser-2.23.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 pycparser-2.23.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92 pycparser-2.23.dist-info/top_level.txt,sha256=c-lPcS74L_8KoH7IE6PQF5ofyirRQNV4VhkbSFIPeWM,10 pycparser/__init__.py,sha256=FQFl5XuxXZiYHrBuN1EElN1COlR8k4aCSdG7h7a7zLw,2918 diff --git a/venv/Lib/site-packages/pycparser-2.23.dist-info/REQUESTED b/venv/Lib/site-packages/pycparser-2.23.dist-info/REQUESTED new file mode 100644 index 0000000..e69de29 diff --git a/venv/Lib/site-packages/pycparser/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/pycparser/__pycache__/__init__.cpython-312.pyc index 1a12502..3146983 100644 Binary files a/venv/Lib/site-packages/pycparser/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/pycparser/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pycparser/__pycache__/_ast_gen.cpython-312.pyc b/venv/Lib/site-packages/pycparser/__pycache__/_ast_gen.cpython-312.pyc index b75ced9..0db1129 100644 Binary files a/venv/Lib/site-packages/pycparser/__pycache__/_ast_gen.cpython-312.pyc and b/venv/Lib/site-packages/pycparser/__pycache__/_ast_gen.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pycparser/__pycache__/_build_tables.cpython-312.pyc b/venv/Lib/site-packages/pycparser/__pycache__/_build_tables.cpython-312.pyc index 68ff116..752dcea 100644 Binary files a/venv/Lib/site-packages/pycparser/__pycache__/_build_tables.cpython-312.pyc and b/venv/Lib/site-packages/pycparser/__pycache__/_build_tables.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pycparser/__pycache__/ast_transforms.cpython-312.pyc b/venv/Lib/site-packages/pycparser/__pycache__/ast_transforms.cpython-312.pyc index 4c6f2be..a8aabe9 100644 Binary files a/venv/Lib/site-packages/pycparser/__pycache__/ast_transforms.cpython-312.pyc and b/venv/Lib/site-packages/pycparser/__pycache__/ast_transforms.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pycparser/__pycache__/c_ast.cpython-312.pyc b/venv/Lib/site-packages/pycparser/__pycache__/c_ast.cpython-312.pyc index 2d7eb14..8ea89ce 100644 Binary files a/venv/Lib/site-packages/pycparser/__pycache__/c_ast.cpython-312.pyc and b/venv/Lib/site-packages/pycparser/__pycache__/c_ast.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pycparser/__pycache__/c_generator.cpython-312.pyc b/venv/Lib/site-packages/pycparser/__pycache__/c_generator.cpython-312.pyc index ee9a96c..16c8e1b 100644 Binary files a/venv/Lib/site-packages/pycparser/__pycache__/c_generator.cpython-312.pyc and b/venv/Lib/site-packages/pycparser/__pycache__/c_generator.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pycparser/__pycache__/c_lexer.cpython-312.pyc b/venv/Lib/site-packages/pycparser/__pycache__/c_lexer.cpython-312.pyc index fbe2700..17c30fe 100644 Binary files a/venv/Lib/site-packages/pycparser/__pycache__/c_lexer.cpython-312.pyc and b/venv/Lib/site-packages/pycparser/__pycache__/c_lexer.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pycparser/__pycache__/c_parser.cpython-312.pyc b/venv/Lib/site-packages/pycparser/__pycache__/c_parser.cpython-312.pyc index ecb7cb4..8c5a070 100644 Binary files a/venv/Lib/site-packages/pycparser/__pycache__/c_parser.cpython-312.pyc and b/venv/Lib/site-packages/pycparser/__pycache__/c_parser.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pycparser/__pycache__/lextab.cpython-312.pyc b/venv/Lib/site-packages/pycparser/__pycache__/lextab.cpython-312.pyc index 433c3c6..1d26ca9 100644 Binary files a/venv/Lib/site-packages/pycparser/__pycache__/lextab.cpython-312.pyc and b/venv/Lib/site-packages/pycparser/__pycache__/lextab.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pycparser/__pycache__/plyparser.cpython-312.pyc b/venv/Lib/site-packages/pycparser/__pycache__/plyparser.cpython-312.pyc index 18d7813..cb91ad0 100644 Binary files a/venv/Lib/site-packages/pycparser/__pycache__/plyparser.cpython-312.pyc and b/venv/Lib/site-packages/pycparser/__pycache__/plyparser.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pycparser/__pycache__/yacctab.cpython-312.pyc b/venv/Lib/site-packages/pycparser/__pycache__/yacctab.cpython-312.pyc index c1576c5..4e2fa51 100644 Binary files a/venv/Lib/site-packages/pycparser/__pycache__/yacctab.cpython-312.pyc and b/venv/Lib/site-packages/pycparser/__pycache__/yacctab.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pycparser/ply/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/pycparser/ply/__pycache__/__init__.cpython-312.pyc index 2fb9738..8f09e15 100644 Binary files a/venv/Lib/site-packages/pycparser/ply/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/pycparser/ply/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pycparser/ply/__pycache__/cpp.cpython-312.pyc b/venv/Lib/site-packages/pycparser/ply/__pycache__/cpp.cpython-312.pyc index aa88c88..4b477ee 100644 Binary files a/venv/Lib/site-packages/pycparser/ply/__pycache__/cpp.cpython-312.pyc and b/venv/Lib/site-packages/pycparser/ply/__pycache__/cpp.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pycparser/ply/__pycache__/ctokens.cpython-312.pyc b/venv/Lib/site-packages/pycparser/ply/__pycache__/ctokens.cpython-312.pyc index cbcfa49..c3d81a6 100644 Binary files a/venv/Lib/site-packages/pycparser/ply/__pycache__/ctokens.cpython-312.pyc and b/venv/Lib/site-packages/pycparser/ply/__pycache__/ctokens.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pycparser/ply/__pycache__/lex.cpython-312.pyc b/venv/Lib/site-packages/pycparser/ply/__pycache__/lex.cpython-312.pyc index 5d2ef49..e9727c9 100644 Binary files a/venv/Lib/site-packages/pycparser/ply/__pycache__/lex.cpython-312.pyc and b/venv/Lib/site-packages/pycparser/ply/__pycache__/lex.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pycparser/ply/__pycache__/yacc.cpython-312.pyc b/venv/Lib/site-packages/pycparser/ply/__pycache__/yacc.cpython-312.pyc index 3afd327..ff19f9b 100644 Binary files a/venv/Lib/site-packages/pycparser/ply/__pycache__/yacc.cpython-312.pyc and b/venv/Lib/site-packages/pycparser/ply/__pycache__/yacc.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pycparser/ply/__pycache__/ygen.cpython-312.pyc b/venv/Lib/site-packages/pycparser/ply/__pycache__/ygen.cpython-312.pyc index e371b21..729f8f4 100644 Binary files a/venv/Lib/site-packages/pycparser/ply/__pycache__/ygen.cpython-312.pyc and b/venv/Lib/site-packages/pycparser/ply/__pycache__/ygen.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/pycryptodomex-3.23.0.dist-info/AUTHORS.rst b/venv/Lib/site-packages/pycryptodomex-3.23.0.dist-info/AUTHORS.rst new file mode 100644 index 0000000..f110c81 --- /dev/null +++ b/venv/Lib/site-packages/pycryptodomex-3.23.0.dist-info/AUTHORS.rst @@ -0,0 +1,51 @@ +Simon Arneaud +Nevins Bartolomeo +Thorsten E. Behrens +Tim Berners-Lee +Frédéric Bertolus +Ian Bicking +Joris Bontje +Antoon Bosselaers +Andrea Bottoni +Jean-Paul Calderone +Sergey Chernov +Geremy Condra +Jan Dittberner +Andrew Eland +Philippe Frycia +Peter Gutmann +Hirendra Hindocha +Nikhil Jhingan +Sebastian Kayser +Ryan Kelly +Andrew M. Kuchling +Piers Lauder +Legrandin +M.-A. Lemburg +Wim Lewis +Darsey C. Litzenberger +Richard Mitchell +Mark Moraes +Lim Chee Siang +Bryan Olson +Wallace Owen +Colin Plumb +Robey Pointer +Lorenz Quack +Sebastian Ramacher +Jeethu Rao +James P. Rutledge +Matt Schreiner +Peter Simmons +Janne Snabb +Tom St. Denis +Anders Sundman +Paul Swartz +Fabrizio Tarizzo +Kevin M. Turner +Barry A. Warsaw +Eric Young +Hannes van Niekerk +Stefan Seering +Koki Takahashi +Lauro de Lima diff --git a/venv/Lib/site-packages/pycryptodomex-3.23.0.dist-info/INSTALLER b/venv/Lib/site-packages/pycryptodomex-3.23.0.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/venv/Lib/site-packages/pycryptodomex-3.23.0.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/venv/Lib/site-packages/pycryptodomex-3.23.0.dist-info/LICENSE.rst b/venv/Lib/site-packages/pycryptodomex-3.23.0.dist-info/LICENSE.rst new file mode 100644 index 0000000..3008ff7 --- /dev/null +++ b/venv/Lib/site-packages/pycryptodomex-3.23.0.dist-info/LICENSE.rst @@ -0,0 +1,61 @@ +The source code in PyCryptodome is partially in the public domain +and partially released under the BSD 2-Clause license. + +In either case, there are minimal if no restrictions on the redistribution, +modification and usage of the software. + +Public domain +============= + +All code originating from PyCrypto is free and unencumbered software +released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to + +BSD license +=========== + +All direct contributions to PyCryptodome are released under the following +license. The copyright of each piece belongs to the respective author. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/venv/Lib/site-packages/pycryptodomex-3.23.0.dist-info/METADATA b/venv/Lib/site-packages/pycryptodomex-3.23.0.dist-info/METADATA new file mode 100644 index 0000000..1fab34c --- /dev/null +++ b/venv/Lib/site-packages/pycryptodomex-3.23.0.dist-info/METADATA @@ -0,0 +1,86 @@ +Metadata-Version: 2.1 +Name: pycryptodomex +Version: 3.23.0 +Summary: Cryptographic library for Python +Home-page: https://www.pycryptodome.org +Author: Helder Eijs +Author-email: helderijs@gmail.com +License: BSD, Public Domain +Project-URL: Source, https://github.com/Legrandin/pycryptodome/ +Project-URL: Changelog, https://www.pycryptodome.org/src/changelog +Platform: Posix; MacOS X; Windows +Classifier: Development Status :: 5 - Production/Stable +Classifier: License :: OSI Approved :: BSD License +Classifier: License :: Public Domain +Classifier: Intended Audience :: Developers +Classifier: Operating System :: Unix +Classifier: Operating System :: Microsoft :: Windows +Classifier: Operating System :: MacOS :: MacOS X +Classifier: Topic :: Security :: Cryptography +Classifier: Programming Language :: Python :: 2 +Classifier: Programming Language :: Python :: 2.7 +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: 3.9 +Classifier: Programming Language :: Python :: 3.10 +Classifier: Programming Language :: Python :: 3.11 +Classifier: Programming Language :: Python :: 3.12 +Classifier: Programming Language :: Python :: 3.13 +Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, !=3.6.* +License-File: LICENSE.rst +License-File: AUTHORS.rst + + +PyCryptodome +============ + +PyCryptodome is a self-contained Python package of low-level +cryptographic primitives. + +It supports Python 2.7, Python 3.7 and newer, and PyPy. + +You can install it with:: + + pip install pycryptodomex + +All modules are installed under the ``Cryptodome`` package. + +Check the pycryptodome_ project for the equivalent library that +works under the ``Crypto`` package. + +PyCryptodome is a fork of PyCrypto. It brings several enhancements +with respect to the last official version of PyCrypto (2.6.1), +for instance: + +* Authenticated encryption modes (GCM, CCM, EAX, SIV, OCB, KW, KWP) +* Hybrid Public Key Encryption (HPKE) +* Accelerated AES on Intel platforms via AES-NI +* First class support for PyPy +* Elliptic curves cryptography (NIST P-curves; Ed25519, Ed448, Curve25519) +* Better and more compact API (`nonce` and `iv` attributes for ciphers, + automatic generation of random nonces and IVs, simplified CTR cipher mode, + and more) +* SHA-3 (including SHAKE XOFs) and BLAKE2 hash algorithms +* Salsa20 and ChaCha20 stream ciphers +* scrypt and HKDF +* Deterministic (EC)DSA and EdDSA +* Password-protected PKCS#8 key containers +* Shamir's Secret Sharing scheme +* Random numbers get sourced directly from the OS (and not from a CSPRNG in userspace) +* Simplified install process, including better support for Windows +* Cleaner RSA and DSA key generation (largely based on FIPS 186-4) +* Major clean ups and simplification of the code base + +PyCryptodome is not a wrapper to a separate C library like *OpenSSL*. +To the largest possible extent, algorithms are implemented in pure Python. +Only the pieces that are extremely critical to performance (e.g. block ciphers) +are implemented as C extensions. + +For more information, see the `homepage`_. + +All the code can be downloaded from `GitHub`_. + +.. _pycryptodome: https://pypi.python.org/pypi/pycryptodome +.. _`homepage`: http://www.pycryptodome.org +.. _GitHub: https://github.com/Legrandin/pycryptodome diff --git a/venv/Lib/site-packages/pycryptodomex-3.23.0.dist-info/RECORD b/venv/Lib/site-packages/pycryptodomex-3.23.0.dist-info/RECORD new file mode 100644 index 0000000..5bf1987 --- /dev/null +++ b/venv/Lib/site-packages/pycryptodomex-3.23.0.dist-info/RECORD @@ -0,0 +1,559 @@ +Cryptodome/Cipher/AES.py,sha256=0qQZLPYPVpmG05QBDS_f1kgUPeBvw0yfgjJCFrkvQ2g,9292 +Cryptodome/Cipher/AES.pyi,sha256=iAx2BPX5y-ruWOQR8ViA8JCPGidvHgt4F6b57OhRP9s,3819 +Cryptodome/Cipher/ARC2.py,sha256=V9n840g0dN1T0TptzdPmmT6ls910gLe8hcao1Kbh3Z8,7201 +Cryptodome/Cipher/ARC2.pyi,sha256=xyTB6xRCyu7nBkMSXZbeCneTouhHB3Xl0edij8pnr4I,1048 +Cryptodome/Cipher/ARC4.py,sha256=AVKpMrxLDlI4r1ycFF7yWmnmbjlYBKcA1g-87oDl7Iw,5264 +Cryptodome/Cipher/ARC4.pyi,sha256=KIVbwv9lMe_UDEIHXrXlBq2KX42YuAQfshhyXHxIQFQ,438 +Cryptodome/Cipher/Blowfish.py,sha256=KX1aLk62Jlg-3D6MORlHcLJ3c6jfAMF9cc4Lfm9d4As,6135 +Cryptodome/Cipher/Blowfish.pyi,sha256=o2PvWhEjM_QHRwqITiM1fxwlH-czCRuV3I6Grj_3Om0,1084 +Cryptodome/Cipher/CAST.py,sha256=6LqRWKoNfceogc_UEWAqTGJruM5qr8IiwIneXm37m8I,6246 +Cryptodome/Cipher/CAST.pyi,sha256=FGnXUFl2wKJ_iyP2TkAr6KiXsAiYU5tbtoA3kheN_h0,1049 +Cryptodome/Cipher/ChaCha20.py,sha256=Wx9wJEGPXwSijaQUrpT5hTo8sjCYNwXHgH82oeJ_QYU,11150 +Cryptodome/Cipher/ChaCha20.pyi,sha256=zjGnGC5DadyPZdkpgTzmfnr6Z-zu2YIbEku-qxPZ5mg,798 +Cryptodome/Cipher/ChaCha20_Poly1305.py,sha256=Ciw4zam_gqNW9l1_g0AgmGj8xyuRvKcn26MvcSp4l0g,11887 +Cryptodome/Cipher/ChaCha20_Poly1305.pyi,sha256=bYgKNijEfZvOhRAZyCcg1XD0RpnhtFOvQyrkp7IKEnM,1107 +Cryptodome/Cipher/DES.py,sha256=Qa7wZHNM8nk4i82HXwJS0n_fs1ZZBLf6GTX2PIL370c,6121 +Cryptodome/Cipher/DES.pyi,sha256=v7r4rsed_EXLjCYFN5ekNzWnqspQqlUE_ggOkApqOOY,1029 +Cryptodome/Cipher/DES3.py,sha256=w1R2ZC17JunHHPFvb7DkxE-cxkOjvxHxmQ44rAczLu0,7128 +Cryptodome/Cipher/DES3.pyi,sha256=O4aNLporQcJ_yskOTA264WNPcZhyCAX_n0UMTE18tX8,1101 +Cryptodome/Cipher/PKCS1_OAEP.py,sha256=1LT-rjSwyrF5PtVm0dV4ugmYx-x44DFQ5y6RHVqtQgA,8839 +Cryptodome/Cipher/PKCS1_OAEP.pyi,sha256=aiVwYUrONdhuJeq58qqv01G2t_-FqYk1VvsaR1JOCZ8,1218 +Cryptodome/Cipher/PKCS1_v1_5.py,sha256=KNbb1gaE8hCoz2YqesZry5eOMIt-LyT5tXnGZMcN-WA,7232 +Cryptodome/Cipher/PKCS1_v1_5.pyi,sha256=SdzDVwsGN792r_S7OJr34TiKrZPL_7-aH-t6PBIYat8,710 +Cryptodome/Cipher/Salsa20.py,sha256=J0ArZwgeAVEkdJJqPxFTxvyhrlKAOM9-ZFwXm8pfyh0,6536 +Cryptodome/Cipher/Salsa20.pyi,sha256=7c0zuTZa1UbPawHH_vxz8edVi7UL_bR_7yYhLC4CeuY,770 +Cryptodome/Cipher/_ARC4.pyd,sha256=432iohQOsY-4QGXUE4rRByU5yCRkR1qU9ah6BJ5gH34,10752 +Cryptodome/Cipher/_EKSBlowfish.py,sha256=h9fLOkfjI0UZoeAaKw0AcxkmTiy5TlSohkoi_QAWWjY,5348 +Cryptodome/Cipher/_EKSBlowfish.pyi,sha256=8hMOScdbBmD8_SjVBb75X6OSy8LvY2cX9J-FVUZEBwY,285 +Cryptodome/Cipher/_Salsa20.pyd,sha256=We4HXsuYd7wk9cJ_otWQuuD2qjCm4CQy4esly0WavA4,13824 +Cryptodome/Cipher/__init__.py,sha256=94td0PVK-deBB_J7tdDmYF_GS8IbuUDLUruIrDNfs_A,3733 +Cryptodome/Cipher/__init__.pyi,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +Cryptodome/Cipher/__pycache__/AES.cpython-312.pyc,, +Cryptodome/Cipher/__pycache__/ARC2.cpython-312.pyc,, +Cryptodome/Cipher/__pycache__/ARC4.cpython-312.pyc,, +Cryptodome/Cipher/__pycache__/Blowfish.cpython-312.pyc,, +Cryptodome/Cipher/__pycache__/CAST.cpython-312.pyc,, +Cryptodome/Cipher/__pycache__/ChaCha20.cpython-312.pyc,, +Cryptodome/Cipher/__pycache__/ChaCha20_Poly1305.cpython-312.pyc,, +Cryptodome/Cipher/__pycache__/DES.cpython-312.pyc,, +Cryptodome/Cipher/__pycache__/DES3.cpython-312.pyc,, +Cryptodome/Cipher/__pycache__/PKCS1_OAEP.cpython-312.pyc,, +Cryptodome/Cipher/__pycache__/PKCS1_v1_5.cpython-312.pyc,, +Cryptodome/Cipher/__pycache__/Salsa20.cpython-312.pyc,, +Cryptodome/Cipher/__pycache__/_EKSBlowfish.cpython-312.pyc,, +Cryptodome/Cipher/__pycache__/__init__.cpython-312.pyc,, +Cryptodome/Cipher/__pycache__/_mode_cbc.cpython-312.pyc,, +Cryptodome/Cipher/__pycache__/_mode_ccm.cpython-312.pyc,, +Cryptodome/Cipher/__pycache__/_mode_cfb.cpython-312.pyc,, +Cryptodome/Cipher/__pycache__/_mode_ctr.cpython-312.pyc,, +Cryptodome/Cipher/__pycache__/_mode_eax.cpython-312.pyc,, +Cryptodome/Cipher/__pycache__/_mode_ecb.cpython-312.pyc,, +Cryptodome/Cipher/__pycache__/_mode_gcm.cpython-312.pyc,, +Cryptodome/Cipher/__pycache__/_mode_kw.cpython-312.pyc,, +Cryptodome/Cipher/__pycache__/_mode_kwp.cpython-312.pyc,, +Cryptodome/Cipher/__pycache__/_mode_ocb.cpython-312.pyc,, +Cryptodome/Cipher/__pycache__/_mode_ofb.cpython-312.pyc,, +Cryptodome/Cipher/__pycache__/_mode_openpgp.cpython-312.pyc,, +Cryptodome/Cipher/__pycache__/_mode_siv.cpython-312.pyc,, +Cryptodome/Cipher/__pycache__/_pkcs1_oaep_decode.cpython-312.pyc,, +Cryptodome/Cipher/_chacha20.pyd,sha256=VzZQatbcLz2JO5eMhyfXTC8K6Hu8L8_P6MfpgupehuI,13312 +Cryptodome/Cipher/_mode_cbc.py,sha256=rEVych0WNCsPS0uB4G8RCNw5Fzb2i19yPBdvQUACI4w,11201 +Cryptodome/Cipher/_mode_cbc.pyi,sha256=MsRzfzI3aR2shTTqUGzROeF_pwkTmwejzfNRPryFDcw,716 +Cryptodome/Cipher/_mode_ccm.py,sha256=fBDPFSeyEgLSPN8YLgTjfju1Ek3WbRcSDgvmiHEYhlU,25982 +Cryptodome/Cipher/_mode_ccm.pyi,sha256=DxNMOW6CTL8MVwb69wSpGGzp4uAa_56u9_jdXzJ01mI,1722 +Cryptodome/Cipher/_mode_cfb.py,sha256=VreWYFTR1zU1RvpIC8C7EacOG_AekJVoywDcmUzjAFg,11034 +Cryptodome/Cipher/_mode_cfb.pyi,sha256=Fe5CgCgwD8uAevVX2yePIpwmDsmOiuGXFmG0Ns_lwqk,757 +Cryptodome/Cipher/_mode_ctr.py,sha256=HkdFZCGhBzzhKYr7r54v8iinFk2ELGatdclttMnS7Xc,16245 +Cryptodome/Cipher/_mode_ctr.pyi,sha256=q4aX482ihynZy2plReoeP83BhMnge_tw2fruOPJwEu8,831 +Cryptodome/Cipher/_mode_eax.py,sha256=T09hII2rGli6OgPnDeO54x5SdNEyvqNpL6rLDnNkBNw,14893 +Cryptodome/Cipher/_mode_eax.pyi,sha256=xSRlBtL_DisTuuOl1HRnxHmUkywkSZ_vzzISbDm_lhE,1590 +Cryptodome/Cipher/_mode_ecb.py,sha256=0KdenMViMOHAREEaGmdg_3Z41EnhJjrv_vfidS42D_g,8541 +Cryptodome/Cipher/_mode_ecb.pyi,sha256=iope1576_Jy3o62VuuGryqTkR3dnYHeOkf3W5RBxQ1I,615 +Cryptodome/Cipher/_mode_gcm.py,sha256=iJncrgc5w-XIdHC2pKBVLt3Prj35V65Je_Ntwn0Da2I,21961 +Cryptodome/Cipher/_mode_gcm.pyi,sha256=SbaoR9LHHaVWOH0Zh5Ru3QwlnM85UsY8nRBhy063Mf4,1586 +Cryptodome/Cipher/_mode_kw.py,sha256=4ocbvLQ9UYBIumosV5pTjUNKQe6gOwXTVc4Cfk_BbWU,4612 +Cryptodome/Cipher/_mode_kwp.py,sha256=VOlbuWjKyvvs5tyy8V7yUPbagWeBIEAhom7KiJUPyRE,4074 +Cryptodome/Cipher/_mode_ocb.py,sha256=MmNVDHreAeMIi8V3MQHJ2PayRiiRbrxYznY_MCnZ2fo,20511 +Cryptodome/Cipher/_mode_ocb.pyi,sha256=4ME243Yt2TwkeT2vmJ2UBhrzCjANcwi8itLvaec6kuU,1267 +Cryptodome/Cipher/_mode_ofb.py,sha256=qG0Kz6ut-FLvEmSEomemw5U69o_Rfm_OSWxNLfybz-c,10511 +Cryptodome/Cipher/_mode_ofb.pyi,sha256=0bGmhavkhgQ0jaOuPFS69U7QvVzJ8MuThnqC-Id_ns8,720 +Cryptodome/Cipher/_mode_openpgp.py,sha256=RmULsbtKNe4wSrrCOBekhwS6vk-T7OxM5i7pfUnEQYk,7267 +Cryptodome/Cipher/_mode_openpgp.pyi,sha256=XhUhseqY0UY3RZepT_Xfgvvkn3w9wG9tsDN54ep51-U,576 +Cryptodome/Cipher/_mode_siv.py,sha256=dhCwgVOJUmFkX0afT7fS1SEdhsvn9G0n5Jy7G6TsX5Q,14401 +Cryptodome/Cipher/_mode_siv.pyi,sha256=gNrioYewTy43KbzfeN4Nsx4iygkirUIPZQd8RI8VOOU,1299 +Cryptodome/Cipher/_pkcs1_decode.pyd,sha256=7RLD1RLl4LQkX9xag_1GSXuy3zHkkZm2JlrOUUL-UCE,13312 +Cryptodome/Cipher/_pkcs1_oaep_decode.py,sha256=zS0KGXY0iNh1-PmGqXEd0O7Jz-9mNVaiH5OTSJ7UzJw,1873 +Cryptodome/Cipher/_raw_aes.pyd,sha256=iJ-bVYpHpDM7_T44FOrsIyishkhyLZEseHP96mL8-IY,35328 +Cryptodome/Cipher/_raw_aesni.pyd,sha256=bJor7Vwb2azYvOp_XyD3-mPkRlsJFK5wJQvVmoAoMzw,15360 +Cryptodome/Cipher/_raw_arc2.pyd,sha256=7aVqo6-51q39lbqVCtEke14sau2qLbhq8Mj6eSFzWaQ,14848 +Cryptodome/Cipher/_raw_blowfish.pyd,sha256=7qfgWXIW7ObSOzUXQ_3AjTKlvN5Xse-nJKO2E4tpKtk,19456 +Cryptodome/Cipher/_raw_cast.pyd,sha256=kEQtAS0_kYyw94A1aA22o3MUix3n6EVF5fNZbGVc1qs,24064 +Cryptodome/Cipher/_raw_cbc.pyd,sha256=bGxfrBtZM_uFf8w-Wod2Ule1SEKF3hR-m7X8hUIjpwc,11776 +Cryptodome/Cipher/_raw_cfb.pyd,sha256=JuNRxPreNcFG2E3w4iwkaOARhtOooeUbtsjY6ofwnNc,12288 +Cryptodome/Cipher/_raw_ctr.pyd,sha256=IpmU5MuDgHmlcRyMD_6yX7RoSnDs2kl920nIoxVZSoM,14848 +Cryptodome/Cipher/_raw_des.pyd,sha256=i9hGnsv3B7kNiPzDIhPx9od9rDbc92eg9MHOi6gbV1Y,52736 +Cryptodome/Cipher/_raw_des3.pyd,sha256=gJOQJWquVaEmVIkoNILy_uNJV-TytDd9dElgJ0ByTss,52736 +Cryptodome/Cipher/_raw_ecb.pyd,sha256=2k6s3jluc4jsXaUTN2JAl1fc2q4wIlkKc9mtlQhEwx8,10240 +Cryptodome/Cipher/_raw_eksblowfish.pyd,sha256=QOGngQKgeAWMsGtP9BQR-JIDVkkVvAvOBPTCZD3rmyQ,20480 +Cryptodome/Cipher/_raw_ocb.pyd,sha256=YfijykUds6B7OBXE2Ro3EAxBbxYOPM-mETvvDIDQwSs,17920 +Cryptodome/Cipher/_raw_ofb.pyd,sha256=t3oqkyLCjR3XndkXa9bWl_LuPdEMss4kzf2dQrUz_v8,11776 +Cryptodome/Hash/BLAKE2b.py,sha256=8xK5co1bSrZuh8SKpIo1TiCWSWFjl8u9qhMlTMtYDDI,9686 +Cryptodome/Hash/BLAKE2b.pyi,sha256=L3n6bSF5eNssWnzyl-c-VVwhAOhvpbLLTB3v_MrjU98,938 +Cryptodome/Hash/BLAKE2s.py,sha256=1BG4aAx5sgwMWuODbmU4xWpyq29A75gp5cWRwqdIaEs,9692 +Cryptodome/Hash/BLAKE2s.pyi,sha256=JZM_CHRQKMQ0ULROaSagCUICPmi_k00qTQMrj5VXwlE,765 +Cryptodome/Hash/CMAC.py,sha256=T3gT_8VE_6oDrPVhGUi9mScURh1_n1J8KJ-KG_i_esE,10838 +Cryptodome/Hash/CMAC.pyi,sha256=ipeHpon5AOZgIHxBmgwrZtPUDbRtCfTqnBlUNkDSb1c,852 +Cryptodome/Hash/HMAC.py,sha256=vRXF-Vc_Jb4diGvKbYZ9Fye5zA1RXa1qOSBmPw4wi1o,8407 +Cryptodome/Hash/HMAC.pyi,sha256=wsYXlp6cRB3MT4ROm4updn9JmZJywjm96I1fT69qZyw,649 +Cryptodome/Hash/KMAC128.py,sha256=DS-Z2KVCC4SXv3s98M-GeWA1DhyN89KyxUuO-j553AY,6136 +Cryptodome/Hash/KMAC128.pyi,sha256=ODtXtiV4EizZJL-k3LMkIz7Q16hH-J0Wvb0-2CUSQMI,936 +Cryptodome/Hash/KMAC256.py,sha256=zaBtiPDA8uBPlBibdTRSIyb8AWGUGyu9TijXb_t5LZI,2984 +Cryptodome/Hash/KMAC256.pyi,sha256=siCAblhP-PqcSihzPxoJa2MbcACWAg6tz3Zrlvhqguc,236 +Cryptodome/Hash/KangarooTwelve.py,sha256=n92KWhE0s_TYjqEeEFf4SU4RKeriwfVCVxf5G-GmUL0,7400 +Cryptodome/Hash/KangarooTwelve.pyi,sha256=TBi9F_rh2IPYcQg2sQUQCmcyrvRjmWfwn9G3vWNuIbA,588 +Cryptodome/Hash/MD2.py,sha256=lgHY10pAKMkvtwz850ug1gRSYm_e50VEnKBCL2c_3cU,6289 +Cryptodome/Hash/MD2.pyi,sha256=OzyeeKQxOsnXk11K6SxlCHm-j1UAdHgVRCmRm0eUu0I,511 +Cryptodome/Hash/MD4.py,sha256=7Q2Sa9N4pBUnyoFKXftc9s-5jTgJED4mc_QLy5sIVHc,6783 +Cryptodome/Hash/MD4.pyi,sha256=BgLaKjQtnvH3wBX5U7LfJ_UcJaXpn4kETnFXlmLrpf8,551 +Cryptodome/Hash/MD5.py,sha256=Gi0zXBuP9Bcn2bZnHXhPOKR3xm_It7i3PGZtHBHp3DA,6814 +Cryptodome/Hash/MD5.pyi,sha256=ij4nQwJFS_9EUMHfbaiaBI8T6wSOZMZ4FAjxgGb4Qws,511 +Cryptodome/Hash/Poly1305.py,sha256=YpSlwUh0n_gSX7PEh7327CexkqfAQmDYEh3xQkywLmA,8323 +Cryptodome/Hash/Poly1305.pyi,sha256=faix2ykfl_h1Hr4mqvtmY1cUZ8ShOCf4EUiVmQ492Bo,689 +Cryptodome/Hash/RIPEMD.py,sha256=7_C7TF9YNiwGKdpDH6DhBMyUCvoFbBCBb7Cd1vtJKaY,1237 +Cryptodome/Hash/RIPEMD.pyi,sha256=OF1xoKXall89LrNfSyBvlFHbc_RUE0Lglcw9E8sMr_o,101 +Cryptodome/Hash/RIPEMD160.py,sha256=PmUpEB1pf6ILijErF549JG3zVxO_XYkiHjHQFRzqwr4,6579 +Cryptodome/Hash/RIPEMD160.pyi,sha256=hPZDol3yDmp2GtTh7NxvBEk9tcyvYQglS5RKMWYqAOc,535 +Cryptodome/Hash/SHA.py,sha256=P5c2qVd6Lss3CzeU2ENxrSmlDApruW8zv9NBbywRGyI,1180 +Cryptodome/Hash/SHA.pyi,sha256=WDvvYR9HCZVq5CcRc-kffawjbZ3-jTVwlWU81juHCiE,173 +Cryptodome/Hash/SHA1.py,sha256=BHb_NtWmR0dF-LxSq8tl9WRBYNeT4460mUV4AoFWZJ0,6887 +Cryptodome/Hash/SHA1.pyi,sha256=T8llIkOxtKRDwIxrIvXFNDxjRTQFoT--nMndEt5pUeo,555 +Cryptodome/Hash/SHA224.py,sha256=7PYW7PZrnEaMc4HWcL8cUbEEeppW7o_L1Vnxht3NyZA,7099 +Cryptodome/Hash/SHA224.pyi,sha256=o_vO5JjDxMrcjVE2rO1Mad6blBgCrqSu-Mayct8eBUo,563 +Cryptodome/Hash/SHA256.py,sha256=OhxNZ-pzcTWpexNQFkY6w7lw-uqKteMkV1lYc5NjbmU,7094 +Cryptodome/Hash/SHA256.pyi,sha256=B4ktcMD6MqGd2iMiA71_8NJbGfMOWZkkg2qNS7YWGnE,630 +Cryptodome/Hash/SHA384.py,sha256=U-RsA71x1AQsOBWxOcXct7OJeVmVCplQg1BPrpS27dQ,7097 +Cryptodome/Hash/SHA384.pyi,sha256=EC-NzsSz4-PgGfbOKxZcD93EG3DrLjFpJwvjXyJ_LV8,563 +Cryptodome/Hash/SHA3_224.py,sha256=KHN7trWbvf-gM10-IRXRNHRc8XXdQnIxcrmlSL2AQGk,6365 +Cryptodome/Hash/SHA3_224.pyi,sha256=q5q_NiMkf3f95VA4yFMf9MIucFMs3vFA-p8LZFoVrDY,624 +Cryptodome/Hash/SHA3_256.py,sha256=3ZjrBLsd40RXAkEuiGtP0JzTacqogt0Ouha66ceO_1Q,6365 +Cryptodome/Hash/SHA3_256.pyi,sha256=fu82bgKFGTJwdKrfB_72X9h1ZN6ugqHeHgNjSpKAR6s,624 +Cryptodome/Hash/SHA3_384.py,sha256=9-SKGo9NlLs0Z_jDk4505gtPZZnDF-GnbZdSf5o1P7A,6465 +Cryptodome/Hash/SHA3_384.pyi,sha256=0yilMnwleso1FsfBG2F9MNXgx8mRWjL0xrPd_iadz38,624 +Cryptodome/Hash/SHA3_512.py,sha256=PA6NqjHHVYDjkG4J3SNK94G9_HUXPpV3xZpDojAQmP0,6317 +Cryptodome/Hash/SHA3_512.pyi,sha256=VpmwVDWKDFVglsEywJyLMFLl7-gVom7avFrV6Ja_jpw,624 +Cryptodome/Hash/SHA512.py,sha256=04Pr8PhSJAQQtNKpg9MYqZfiIvtH5snj509eXjwwxvQ,7936 +Cryptodome/Hash/SHA512.pyi,sha256=uw4N9PP_-0ornv5bZ010B7vSSGeLC_KkT_CqB9JH29o,644 +Cryptodome/Hash/SHAKE128.py,sha256=IiSMYv-AOsxpV4mCvNlggLyu2rIGLAMrNaPAZLrjgbg,5414 +Cryptodome/Hash/SHAKE128.pyi,sha256=AMqkBlrZdWHlzW-JkWvf3aR2auyFxGKrqLYIp_zYooI,491 +Cryptodome/Hash/SHAKE256.py,sha256=bRfkojyavh7MU0KLYkI4SqITyU9GEeDPapL8rQ-EuhI,5416 +Cryptodome/Hash/SHAKE256.pyi,sha256=2WrcI4NBl4e_evT8XA6pW3VZKraDK0Ahx-2W85ltdQQ,491 +Cryptodome/Hash/TupleHash128.py,sha256=RD1B68n0OE43CsUb4BxWkTy9vh30yTdpsehSILUFBSw,4892 +Cryptodome/Hash/TupleHash128.pyi,sha256=tWceXo_EUTwuDJ8HLBqchoZW8M1meD3AEfxFVsG9IwY,688 +Cryptodome/Hash/TupleHash256.py,sha256=lrspcLVMwnDeGT-3EVWv-_VPms8hMQrErZaIk6R4s98,2902 +Cryptodome/Hash/TupleHash256.pyi,sha256=CwFKgIIH5MKmN139at5AyXtYAsj56nZ0jzM8E4bGcEw,149 +Cryptodome/Hash/TurboSHAKE128.py,sha256=NO7U_kL_oXbUZvWz58VQcernnqX85Ooxw40dV5bVrJo,3959 +Cryptodome/Hash/TurboSHAKE128.pyi,sha256=t2FwSdCyExGA6gtzroysc4OaJ9OUvmtNl5b50BmN5rc,591 +Cryptodome/Hash/TurboSHAKE256.py,sha256=rXnhUqLIPukKxh_3JF31cGc_vihyDZ3o4H4v3b8OUds,779 +Cryptodome/Hash/TurboSHAKE256.pyi,sha256=ht6lAfjtVrrnZSQVJDs4hFqxyUoeStDnN6mKN6gCNeo,318 +Cryptodome/Hash/_BLAKE2b.pyd,sha256=mhCs6Bb2ECl7zyUMbahfq7-AbdQaZbhEHhNeg5DNaHA,14336 +Cryptodome/Hash/_BLAKE2s.pyd,sha256=iOc0x3KQnMxxWPVM6NSIvQtBLr4ukyxVOeB8tmdCQ8w,13824 +Cryptodome/Hash/_MD2.pyd,sha256=7wRAr3ngnr1mUJAWS90XDRDqsOY8Hj4RYIi7BrY7-ys,14336 +Cryptodome/Hash/_MD4.pyd,sha256=BBceCZQW4a7SJSpQ2_3UqwOnSNl-5pQguP9Q1dCZ3pE,13824 +Cryptodome/Hash/_MD5.pyd,sha256=7hF06AR5iJdfvzLvMJ-Vm31xZU5jblqx3eGBK9eMhHA,15360 +Cryptodome/Hash/_RIPEMD160.pyd,sha256=zil9Yobcn89URZpBb9bfDVZV3NWFxaNPuQGBQozPbt0,13824 +Cryptodome/Hash/_SHA1.pyd,sha256=dt2DupHOzNmC1Nqvy7PGlQ-IEqkrYZ-j2iSlDiPEPhc,17920 +Cryptodome/Hash/_SHA224.pyd,sha256=qvFA9g26d2DYmkzTdxEn2xi1_Fd8iu1llvHnVIFXKiU,21504 +Cryptodome/Hash/_SHA256.pyd,sha256=40N8_2PMMVCQUGl77BfymySihCqvu6eCOCgbXMYhdz4,21504 +Cryptodome/Hash/_SHA384.pyd,sha256=ow06_OjEv-mMSUsJ1s6k22QrvxlOzrkIdaeUNMcD22U,26112 +Cryptodome/Hash/_SHA512.pyd,sha256=o0G1CzSkqFAoq3pNGCLQQFWmW95O6FGLX3nPeSlXzk0,26112 +Cryptodome/Hash/__init__.py,sha256=eaqUfxwp2Dit-ftpb-XvwWn6Z8c8zuiruJ_WWYXWtEA,3008 +Cryptodome/Hash/__init__.pyi,sha256=uKFXwDXySo48KeX_d8OYNsT94St9br4wyyIHtWXaK1w,2121 +Cryptodome/Hash/__pycache__/BLAKE2b.cpython-312.pyc,, +Cryptodome/Hash/__pycache__/BLAKE2s.cpython-312.pyc,, +Cryptodome/Hash/__pycache__/CMAC.cpython-312.pyc,, +Cryptodome/Hash/__pycache__/HMAC.cpython-312.pyc,, +Cryptodome/Hash/__pycache__/KMAC128.cpython-312.pyc,, +Cryptodome/Hash/__pycache__/KMAC256.cpython-312.pyc,, +Cryptodome/Hash/__pycache__/KangarooTwelve.cpython-312.pyc,, +Cryptodome/Hash/__pycache__/MD2.cpython-312.pyc,, +Cryptodome/Hash/__pycache__/MD4.cpython-312.pyc,, +Cryptodome/Hash/__pycache__/MD5.cpython-312.pyc,, +Cryptodome/Hash/__pycache__/Poly1305.cpython-312.pyc,, +Cryptodome/Hash/__pycache__/RIPEMD.cpython-312.pyc,, +Cryptodome/Hash/__pycache__/RIPEMD160.cpython-312.pyc,, +Cryptodome/Hash/__pycache__/SHA.cpython-312.pyc,, +Cryptodome/Hash/__pycache__/SHA1.cpython-312.pyc,, +Cryptodome/Hash/__pycache__/SHA224.cpython-312.pyc,, +Cryptodome/Hash/__pycache__/SHA256.cpython-312.pyc,, +Cryptodome/Hash/__pycache__/SHA384.cpython-312.pyc,, +Cryptodome/Hash/__pycache__/SHA3_224.cpython-312.pyc,, +Cryptodome/Hash/__pycache__/SHA3_256.cpython-312.pyc,, +Cryptodome/Hash/__pycache__/SHA3_384.cpython-312.pyc,, +Cryptodome/Hash/__pycache__/SHA3_512.cpython-312.pyc,, +Cryptodome/Hash/__pycache__/SHA512.cpython-312.pyc,, +Cryptodome/Hash/__pycache__/SHAKE128.cpython-312.pyc,, +Cryptodome/Hash/__pycache__/SHAKE256.cpython-312.pyc,, +Cryptodome/Hash/__pycache__/TupleHash128.cpython-312.pyc,, +Cryptodome/Hash/__pycache__/TupleHash256.cpython-312.pyc,, +Cryptodome/Hash/__pycache__/TurboSHAKE128.cpython-312.pyc,, +Cryptodome/Hash/__pycache__/TurboSHAKE256.cpython-312.pyc,, +Cryptodome/Hash/__pycache__/__init__.cpython-312.pyc,, +Cryptodome/Hash/__pycache__/cSHAKE128.cpython-312.pyc,, +Cryptodome/Hash/__pycache__/cSHAKE256.cpython-312.pyc,, +Cryptodome/Hash/__pycache__/keccak.cpython-312.pyc,, +Cryptodome/Hash/_ghash_clmul.pyd,sha256=yMyVg8LZHY7yUHPgGoY6QMCfoKiQB_i7BELfRrom8OM,12800 +Cryptodome/Hash/_ghash_portable.pyd,sha256=zR15oNiSPDn3NoyS-uDHMa5g7NNNHJ84fUgksq8WgDY,12288 +Cryptodome/Hash/_keccak.pyd,sha256=yoSmR1wUSFb1zXKli50xnyCGOTk58Uunmbf7ZWZu7AM,15360 +Cryptodome/Hash/_poly1305.pyd,sha256=fzmGRhCn4iddUh7ovtYJO3_vsyVu7sPBuqO9gA0b9CM,13824 +Cryptodome/Hash/cSHAKE128.py,sha256=NJyrBgLqQLz_J3_7S9woNJ61uiKrrKonh8Blvl5jL9s,6566 +Cryptodome/Hash/cSHAKE128.pyi,sha256=mW3iO2pB1xWLPA3Ys95d5TL2lTcGZAhmy-GSQ6iC86M,513 +Cryptodome/Hash/cSHAKE256.py,sha256=1_dCU5iK2WUQ9Tzr11bpTksbRcwzmzJTSe4l1bO1dFg,2266 +Cryptodome/Hash/cSHAKE256.pyi,sha256=XaV6CS2NiWzl0pXX3WnVa27x5Ko4KUNG9-oKb9xWrvI,243 +Cryptodome/Hash/keccak.py,sha256=3gTy2DzxqYs_iVkE8i08QmWtnDcA_xj_U1BytfWiAVs,7736 +Cryptodome/Hash/keccak.pyi,sha256=Oh2z5zIe-zDEqvD61XKHKMeq3Ou76R5CcpQNsfmmd_k,764 +Cryptodome/IO/PEM.py,sha256=X6Wv3fkBPAMly-4w3piTnUHhFHeVYYyVfmbgKvh5Lso,7252 +Cryptodome/IO/PEM.pyi,sha256=_Rfemx2e6zlQIjvl5bFqjKPuCn5IIlV_C4gr_z1nodA,313 +Cryptodome/IO/PKCS8.py,sha256=_3XOl7jFenzv15Xis9rCLBN_J0YmbdCN0Du4VlLabBo,8053 +Cryptodome/IO/PKCS8.pyi,sha256=-tQFFhwtx0cTUkG0GYjmUpXUO38_lx_M_It21jTH0UQ,625 +Cryptodome/IO/_PBES.py,sha256=ZjPQ8oljdUOcphCf7ZXRF7R0u_4w1b6Wp5ZAWumybi0,20545 +Cryptodome/IO/_PBES.pyi,sha256=gWRjwQEhdMYm_fKGCY2FG_VeIBh5_p3urfd3_RzqB5Q,781 +Cryptodome/IO/__init__.py,sha256=ZV2-UvE4AizNrvbbKFaeuh1RNhfRKtiGhdeT5Awh9fo,1571 +Cryptodome/IO/__pycache__/PEM.cpython-312.pyc,, +Cryptodome/IO/__pycache__/PKCS8.cpython-312.pyc,, +Cryptodome/IO/__pycache__/_PBES.cpython-312.pyc,, +Cryptodome/IO/__pycache__/__init__.cpython-312.pyc,, +Cryptodome/Math/Numbers.py,sha256=zVknqn1LV-VQq8xtKjKQ9vFl5R5YO6rRhaxOEOMrNzo,2175 +Cryptodome/Math/Numbers.pyi,sha256=NuMBSxVpNAY3fGT7wOWEB-ZBmj_xCBbx_Flh2lRe0UI,88 +Cryptodome/Math/Primality.py,sha256=njFfZQMHIIJu5KZZbn7JAxXwKp0JA4bYwBq9ojCHtQA,11756 +Cryptodome/Math/Primality.pyi,sha256=9z2uqG5Fd_3jtuMUodo4RBqPDKisZKAYgh4QcGuAyQM,841 +Cryptodome/Math/_IntegerBase.py,sha256=t7dGz35A4_uQAcguzlmBcH2zep2RG_SKwEjCoj6K-ig,11689 +Cryptodome/Math/_IntegerBase.pyi,sha256=yKJq_2cvBrnE2AKG4O-N3osrQf9MMXq3WsoP0NAcdR4,3810 +Cryptodome/Math/_IntegerCustom.py,sha256=JrqMKboLbO23E8B79Vu8YWqWfQ1r-l_10o0PkxVBxcg,5909 +Cryptodome/Math/_IntegerCustom.pyi,sha256=uvIBlf22Tvq1Jv5nYVHOlHFtzn74l-37-SvHROU67P0,143 +Cryptodome/Math/_IntegerGMP.py,sha256=Mg31WyFru-wJoq-M4DKm-zJiox6iL9pU5JoFCBNCSsA,28680 +Cryptodome/Math/_IntegerGMP.pyi,sha256=MtTQsLL9F59d_RoEwiotP9TReNXHZF7PFXVPwHPH5Qg,81 +Cryptodome/Math/_IntegerNative.py,sha256=IAHebjXYJTTcey1lmTjN6JEck1pRk34enQln1zENx_Y,11710 +Cryptodome/Math/_IntegerNative.pyi,sha256=yh3QTsrBR0sfva0Vq4aIH7EOGCoyw664jD-fG0aOYuc,84 +Cryptodome/Math/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +Cryptodome/Math/__pycache__/Numbers.cpython-312.pyc,, +Cryptodome/Math/__pycache__/Primality.cpython-312.pyc,, +Cryptodome/Math/__pycache__/_IntegerBase.cpython-312.pyc,, +Cryptodome/Math/__pycache__/_IntegerCustom.cpython-312.pyc,, +Cryptodome/Math/__pycache__/_IntegerGMP.cpython-312.pyc,, +Cryptodome/Math/__pycache__/_IntegerNative.cpython-312.pyc,, +Cryptodome/Math/__pycache__/__init__.cpython-312.pyc,, +Cryptodome/Math/_modexp.pyd,sha256=T3ZQvmclpwopzFfN8dmi_YhsBsxd3jXBzNp90p3F__Q,30720 +Cryptodome/Protocol/DH.py,sha256=DpS3H5yanBlH-gc6-7vUReGa-LZmCtkFJ0tgUWw7Nuo,5836 +Cryptodome/Protocol/DH.pyi,sha256=AWWVSCLiAYhIVddY7NUmstU1VgZaZ_QCEbA51Nd2ETM,728 +Cryptodome/Protocol/HPKE.py,sha256=L9VnCr5OqD2EQmll0onkpy8-lEMqiHNH9ssd5eq-wk0,17461 +Cryptodome/Protocol/KDF.py,sha256=NbKU2LvKxYwKJaAhj3VcDI8qF1v3ZSDypeis3KlmPmQ,23088 +Cryptodome/Protocol/KDF.pyi,sha256=K7CoB5XoqyCyB41zF9wOdqps17YmP-3E2PRbDGt1sgQ,2196 +Cryptodome/Protocol/SecretSharing.py,sha256=S5wFKFfTR1jUuvczC8H_IM4ciR-R7YAyCTFxWWj3wyk,9435 +Cryptodome/Protocol/SecretSharing.pyi,sha256=F7tLBxpbqrmGeAVGp7D1BvGGpoPLKiqcnDtyfD2cCSE,820 +Cryptodome/Protocol/__init__.py,sha256=XlGaxvvEX9yFpGDg3a0HC69IvBbBuikGpnFo-J4_CJk,1585 +Cryptodome/Protocol/__init__.pyi,sha256=0X_yhA6C6L3z_CN4snuCT-DJdQZHMpV0bBglNAf9phs,44 +Cryptodome/Protocol/__pycache__/DH.cpython-312.pyc,, +Cryptodome/Protocol/__pycache__/HPKE.cpython-312.pyc,, +Cryptodome/Protocol/__pycache__/KDF.cpython-312.pyc,, +Cryptodome/Protocol/__pycache__/SecretSharing.cpython-312.pyc,, +Cryptodome/Protocol/__pycache__/__init__.cpython-312.pyc,, +Cryptodome/Protocol/_scrypt.pyd,sha256=Ec-RVUNsI94Cq8Em71q8DFnQ1bNVX8UfFnkSryGtOPY,12288 +Cryptodome/PublicKey/DSA.py,sha256=iGVqAcV_H6ad2DcnNqVIe_fNVpfbLDDokBaKgiFcOgA,23116 +Cryptodome/PublicKey/DSA.pyi,sha256=fi2SzJExOGn_uay94PRij2u5mV_xVLzA6MLx9zPpbE8,1412 +Cryptodome/PublicKey/ECC.py,sha256=XZVUdemvM6j89xVrBoOMmTpJzq5TcpPZoOHf6mBjTv4,49309 +Cryptodome/PublicKey/ECC.pyi,sha256=nLj-t_FoKVs4z0mXqMU9Hira_Oeh4OrYAsGtvqFvhkE,2671 +Cryptodome/PublicKey/ElGamal.py,sha256=P07xfRi_PtB-HoaXVTmh1R5PnGk7KwvVpY65U7jLbVw,8917 +Cryptodome/PublicKey/ElGamal.pyi,sha256=cBx8pmCg7L-LYz-7GggPRH_Gk-Eoll02nGFl9iHNgLY,692 +Cryptodome/PublicKey/RSA.py,sha256=tze8ns5IsjVF1psFLcZf3erUyzfHUq55SObjU_O2H_8,32036 +Cryptodome/PublicKey/RSA.pyi,sha256=_tUwGEP63bkmLhffJpdG1VuaWU4mtzbenEk3MaujGdU,2607 +Cryptodome/PublicKey/__init__.py,sha256=6-htOSzXhJZjkKpI5HLqEWuUTJ8aKsOP4Ijfvjd2lI4,3240 +Cryptodome/PublicKey/__init__.pyi,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +Cryptodome/PublicKey/__pycache__/DSA.cpython-312.pyc,, +Cryptodome/PublicKey/__pycache__/ECC.cpython-312.pyc,, +Cryptodome/PublicKey/__pycache__/ElGamal.cpython-312.pyc,, +Cryptodome/PublicKey/__pycache__/RSA.cpython-312.pyc,, +Cryptodome/PublicKey/__pycache__/__init__.cpython-312.pyc,, +Cryptodome/PublicKey/__pycache__/_curve.cpython-312.pyc,, +Cryptodome/PublicKey/__pycache__/_edwards.cpython-312.pyc,, +Cryptodome/PublicKey/__pycache__/_montgomery.cpython-312.pyc,, +Cryptodome/PublicKey/__pycache__/_nist_ecc.cpython-312.pyc,, +Cryptodome/PublicKey/__pycache__/_openssh.cpython-312.pyc,, +Cryptodome/PublicKey/__pycache__/_point.cpython-312.pyc,, +Cryptodome/PublicKey/_curve.py,sha256=XMw7yU5wo_yw1e0OpHsSEdO_Tk7gKGu40sIHi2DKoUo,1849 +Cryptodome/PublicKey/_curve25519.pyd,sha256=gYhRqcK4ONXJpFqqAePmeQ-Ejz7Ut8KPLlTauwu4VE4,19456 +Cryptodome/PublicKey/_curve448.pyd,sha256=qrcHIwTsMnRZakn62qK7BGejFIddNkGC1Fm_OSG75gk,58880 +Cryptodome/PublicKey/_ec_ws.pyd,sha256=ByCrN7znAj6jYmHGaBFUvkdGc_Ku4Pii3nQ0vxvWDQw,755200 +Cryptodome/PublicKey/_ed25519.pyd,sha256=o_ucIsfBLeBD2EbNsKXiRW221iagAlhlLHSl5hS9Jz8,23552 +Cryptodome/PublicKey/_ed448.pyd,sha256=luK12ze4QF4TGXOGN_wGbdta1ex7lx869VKmI85rxPU,74752 +Cryptodome/PublicKey/_edwards.py,sha256=eksZeLoFCXVtuPUDaenAjZ1z-cytQpEKsiQHiMykw44,4795 +Cryptodome/PublicKey/_montgomery.py,sha256=KPpvcJah7TA9-YyEAZCuCnyKNDMNU4maZMp0583HXEY,5395 +Cryptodome/PublicKey/_nist_ecc.py,sha256=bk8WppMIcWgSYb25StAlSt4X7A6MG6A1_uRtaSw5FVQ,10427 +Cryptodome/PublicKey/_openssh.py,sha256=F3C16xlMP1AXVRVgFscrfVPD6cMLmvSDsSeElvcRq7A,5281 +Cryptodome/PublicKey/_openssh.pyi,sha256=VkwrAdxdCWv1CHYduIHiARcuLWDpOboveOIL5Gp03aA,331 +Cryptodome/PublicKey/_point.py,sha256=HGWeXw6NR4NcIAkQOVeY057nk40Ca_sGJ97F8INOSCo,16964 +Cryptodome/PublicKey/_point.pyi,sha256=REp5g6MyVtb5Kf5EHghzDskLqeByFXYjwxxccQtkmn0,1774 +Cryptodome/Random/__init__.py,sha256=aXCBituBeqMCHmJMe_rqwOvnAXnzjYMuy4-4L3f5z2k,1870 +Cryptodome/Random/__init__.pyi,sha256=OpVI7weoPC8r99sF7bd2vXiLnZwRLqgVUzMkKDnMJ9c,386 +Cryptodome/Random/__pycache__/__init__.cpython-312.pyc,, +Cryptodome/Random/__pycache__/random.cpython-312.pyc,, +Cryptodome/Random/random.py,sha256=hH2FDSh45d3cXJhLCOy86KS2mNOJDZpx8gxWWUJDBvA,5384 +Cryptodome/Random/random.pyi,sha256=BDrtovJjpCoAhvy7DKgB_x2b85b_zJZkUv8l3VAwoBM,854 +Cryptodome/SelfTest/Cipher/__init__.py,sha256=7tkMRwS2xaB2AVtnyW54xkQCS7S0DlUoCMvjN0DHS5A,3866 +Cryptodome/SelfTest/Cipher/__pycache__/__init__.cpython-312.pyc,, +Cryptodome/SelfTest/Cipher/__pycache__/common.cpython-312.pyc,, +Cryptodome/SelfTest/Cipher/__pycache__/test_AES.cpython-312.pyc,, +Cryptodome/SelfTest/Cipher/__pycache__/test_ARC2.cpython-312.pyc,, +Cryptodome/SelfTest/Cipher/__pycache__/test_ARC4.cpython-312.pyc,, +Cryptodome/SelfTest/Cipher/__pycache__/test_Blowfish.cpython-312.pyc,, +Cryptodome/SelfTest/Cipher/__pycache__/test_CAST.cpython-312.pyc,, +Cryptodome/SelfTest/Cipher/__pycache__/test_CBC.cpython-312.pyc,, +Cryptodome/SelfTest/Cipher/__pycache__/test_CCM.cpython-312.pyc,, +Cryptodome/SelfTest/Cipher/__pycache__/test_CFB.cpython-312.pyc,, +Cryptodome/SelfTest/Cipher/__pycache__/test_CTR.cpython-312.pyc,, +Cryptodome/SelfTest/Cipher/__pycache__/test_ChaCha20.cpython-312.pyc,, +Cryptodome/SelfTest/Cipher/__pycache__/test_ChaCha20_Poly1305.cpython-312.pyc,, +Cryptodome/SelfTest/Cipher/__pycache__/test_DES.cpython-312.pyc,, +Cryptodome/SelfTest/Cipher/__pycache__/test_DES3.cpython-312.pyc,, +Cryptodome/SelfTest/Cipher/__pycache__/test_EAX.cpython-312.pyc,, +Cryptodome/SelfTest/Cipher/__pycache__/test_GCM.cpython-312.pyc,, +Cryptodome/SelfTest/Cipher/__pycache__/test_KW.cpython-312.pyc,, +Cryptodome/SelfTest/Cipher/__pycache__/test_OCB.cpython-312.pyc,, +Cryptodome/SelfTest/Cipher/__pycache__/test_OFB.cpython-312.pyc,, +Cryptodome/SelfTest/Cipher/__pycache__/test_OpenPGP.cpython-312.pyc,, +Cryptodome/SelfTest/Cipher/__pycache__/test_SIV.cpython-312.pyc,, +Cryptodome/SelfTest/Cipher/__pycache__/test_Salsa20.cpython-312.pyc,, +Cryptodome/SelfTest/Cipher/__pycache__/test_pkcs1_15.cpython-312.pyc,, +Cryptodome/SelfTest/Cipher/__pycache__/test_pkcs1_oaep.cpython-312.pyc,, +Cryptodome/SelfTest/Cipher/common.py,sha256=sgzVUzZfhRHFUQpICcfCrY9PKEq3dCIITt7H-xdnK78,17846 +Cryptodome/SelfTest/Cipher/test_AES.py,sha256=7gf1OT4BVREejdviOBVNa_UBueA4iQJ5FUqQ3sCuMhE,73102 +Cryptodome/SelfTest/Cipher/test_ARC2.py,sha256=UGmhvQpXEEgtT7F5x3aybDiKeaF2TPEp08NLUYZ76bM,6641 +Cryptodome/SelfTest/Cipher/test_ARC4.py,sha256=wn_kB1U73aSzF3d-oWMEEZZJ9wP-fjlLcvssaVLxFr8,25466 +Cryptodome/SelfTest/Cipher/test_Blowfish.py,sha256=HAps0owX5gW0s4hZU5kVpIGIuAwGXT5hBaddGLIIXR8,7402 +Cryptodome/SelfTest/Cipher/test_CAST.py,sha256=0lTumK5USL4zJUlbdgSIWE_XqgHITnw33FdcO2fEg1M,3392 +Cryptodome/SelfTest/Cipher/test_CBC.py,sha256=wFEkDUL014fE_PjZuT59V8bAapUizmSRVg9Xh_pyDrs,20778 +Cryptodome/SelfTest/Cipher/test_CCM.py,sha256=i07bk6jnLdkE6Xw5DvVE_nueChBsS7Of1pbKKffE4Mc,39483 +Cryptodome/SelfTest/Cipher/test_CFB.py,sha256=jI5wZNdNX-u23aLY9zKw_ci529jGBiiFCxqe3Q6Sjsk,16496 +Cryptodome/SelfTest/Cipher/test_CTR.py,sha256=oLOqbnyO7_dCYuRiQf4kM4TwkvvxJznDfiIMEDqKZww,21806 +Cryptodome/SelfTest/Cipher/test_ChaCha20.py,sha256=OKspeVjA9cridAh0s6T-w52uUFRKBUmvrCeslwu3nEw,20869 +Cryptodome/SelfTest/Cipher/test_ChaCha20_Poly1305.py,sha256=WrqkJ5Hup0pEOoryf2sweJraTaJer9PCe1Xm_Qpytbw,31518 +Cryptodome/SelfTest/Cipher/test_DES.py,sha256=xBV44PCDlTzS2yC8oXjqAlVVv_8xYiZVRmDZ0CJinVo,16325 +Cryptodome/SelfTest/Cipher/test_DES3.py,sha256=PD9wlJujWnrYV_hoqWXLPGDezPZHrY9X0Tdqkn1P5rA,6780 +Cryptodome/SelfTest/Cipher/test_EAX.py,sha256=6IIi-RBhdjDMWnh6pc2e0qp_6X4q_t6BCBoaSVY5UNo,29626 +Cryptodome/SelfTest/Cipher/test_GCM.py,sha256=THTaxaXGycE7wT7yS3hdp6ajFSAhFwhTs4HLAWV9O-M,38259 +Cryptodome/SelfTest/Cipher/test_KW.py,sha256=nwkHlWk1PeoeZFXrTzSLp6_Dyjjfakmg9p3H0ZXNSIY,5797 +Cryptodome/SelfTest/Cipher/test_OCB.py,sha256=KIC6b2Jd6omHfEh3n0gyAL8wz8Dt4dZ2BUTvFfsVfNw,33512 +Cryptodome/SelfTest/Cipher/test_OFB.py,sha256=LoC0LVt4-rbO_f06DGc_5LTHrNmA8Fkc64JzgYoOYaE,9633 +Cryptodome/SelfTest/Cipher/test_OpenPGP.py,sha256=iib_xktQxGijK7CGUlgpcH_cZflE9JzVM3Qf_XVaf-0,8715 +Cryptodome/SelfTest/Cipher/test_SIV.py,sha256=w8POpl6r1lc6HqrBjTmAD7wDJ9ie0XcFwbd0fWDjTc4,20519 +Cryptodome/SelfTest/Cipher/test_Salsa20.py,sha256=fEbIK-XeIqYlQZnjmYoNCbKilImsoaGx2tZtLpRBoJc,16974 +Cryptodome/SelfTest/Cipher/test_pkcs1_15.py,sha256=9iRqSZC9fy-GKCmvhVoySyB-1DWjk5opvgLVEjBqtu4,11255 +Cryptodome/SelfTest/Cipher/test_pkcs1_oaep.py,sha256=__42U5oGtg2S0ecDC6D_csh-KOnlg_eqYzMQ6JdDKjw,22828 +Cryptodome/SelfTest/Hash/__init__.py,sha256=EUpXYa5rmdgXU3qltHTgoIXhMz1da59Ni1fQ5L5EpjI,3975 +Cryptodome/SelfTest/Hash/__pycache__/__init__.cpython-312.pyc,, +Cryptodome/SelfTest/Hash/__pycache__/common.cpython-312.pyc,, +Cryptodome/SelfTest/Hash/__pycache__/test_BLAKE2.cpython-312.pyc,, +Cryptodome/SelfTest/Hash/__pycache__/test_CMAC.cpython-312.pyc,, +Cryptodome/SelfTest/Hash/__pycache__/test_HMAC.cpython-312.pyc,, +Cryptodome/SelfTest/Hash/__pycache__/test_KMAC.cpython-312.pyc,, +Cryptodome/SelfTest/Hash/__pycache__/test_KangarooTwelve.cpython-312.pyc,, +Cryptodome/SelfTest/Hash/__pycache__/test_MD2.cpython-312.pyc,, +Cryptodome/SelfTest/Hash/__pycache__/test_MD4.cpython-312.pyc,, +Cryptodome/SelfTest/Hash/__pycache__/test_MD5.cpython-312.pyc,, +Cryptodome/SelfTest/Hash/__pycache__/test_Poly1305.cpython-312.pyc,, +Cryptodome/SelfTest/Hash/__pycache__/test_RIPEMD160.cpython-312.pyc,, +Cryptodome/SelfTest/Hash/__pycache__/test_SHA1.cpython-312.pyc,, +Cryptodome/SelfTest/Hash/__pycache__/test_SHA224.cpython-312.pyc,, +Cryptodome/SelfTest/Hash/__pycache__/test_SHA256.cpython-312.pyc,, +Cryptodome/SelfTest/Hash/__pycache__/test_SHA384.cpython-312.pyc,, +Cryptodome/SelfTest/Hash/__pycache__/test_SHA3_224.cpython-312.pyc,, +Cryptodome/SelfTest/Hash/__pycache__/test_SHA3_256.cpython-312.pyc,, +Cryptodome/SelfTest/Hash/__pycache__/test_SHA3_384.cpython-312.pyc,, +Cryptodome/SelfTest/Hash/__pycache__/test_SHA3_512.cpython-312.pyc,, +Cryptodome/SelfTest/Hash/__pycache__/test_SHA512.cpython-312.pyc,, +Cryptodome/SelfTest/Hash/__pycache__/test_SHAKE.cpython-312.pyc,, +Cryptodome/SelfTest/Hash/__pycache__/test_TupleHash.cpython-312.pyc,, +Cryptodome/SelfTest/Hash/__pycache__/test_TurboSHAKE.cpython-312.pyc,, +Cryptodome/SelfTest/Hash/__pycache__/test_cSHAKE.cpython-312.pyc,, +Cryptodome/SelfTest/Hash/__pycache__/test_keccak.cpython-312.pyc,, +Cryptodome/SelfTest/Hash/common.py,sha256=9G2tKtfgVALjsR8-eQDvYvaCKXueZlDW-jYBwX10buk,10196 +Cryptodome/SelfTest/Hash/test_BLAKE2.py,sha256=crGaKJGvdUIQlgk_dwnmw1tNjfHAsKc3njpqJkbh8-w,16812 +Cryptodome/SelfTest/Hash/test_CMAC.py,sha256=4Y2Z9JgoahxRa7i-_98Hjv0NihLoESsP-TcTvnN1qEA,13840 +Cryptodome/SelfTest/Hash/test_HMAC.py,sha256=jjknNmUyOT6k8xwniXVU3u90ZOU8L9AckbTcEXz8wjc,20501 +Cryptodome/SelfTest/Hash/test_KMAC.py,sha256=X29M65qxQTq2D4bg0w4FHNNjO_vqwJUFdN6kckYRjls,12066 +Cryptodome/SelfTest/Hash/test_KangarooTwelve.py,sha256=H5c9x-Hd5LzFTS8ClHC51NuDmHiO2tJq0ezEs8DK-Go,12101 +Cryptodome/SelfTest/Hash/test_MD2.py,sha256=6gTLogj8pRgZE2dHh1EqfPqxY2Ii8CxFbpvbdWKY1PU,2398 +Cryptodome/SelfTest/Hash/test_MD4.py,sha256=tQi0srMp8i2bMLmqkFhBHupCRSMitwIRQhuHR0BHQRI,2423 +Cryptodome/SelfTest/Hash/test_MD5.py,sha256=ULNmbk2L_fCyBkqXsRiHzM3tFRtBBrA_tLBqszZReZU,3394 +Cryptodome/SelfTest/Hash/test_Poly1305.py,sha256=nyFAYXsNrCEStWfoG4HqIVhS8ToDVlRyatnAy4o9xMA,18871 +Cryptodome/SelfTest/Hash/test_RIPEMD160.py,sha256=qyYtRZK3biUx7vVv44I5_w5jC1Hq7sKtyEILNSTJeC4,2746 +Cryptodome/SelfTest/Hash/test_SHA1.py,sha256=H1ua8elqq_qy_xcwhbifMXC1fKouj-oIboAr9OZczu8,3022 +Cryptodome/SelfTest/Hash/test_SHA224.py,sha256=stEbOZCuezHgGfzkW5LrBoa-AWoBkhOTdlx75eq75F0,2604 +Cryptodome/SelfTest/Hash/test_SHA256.py,sha256=Hy7Oc5GZZOenj1eqhf3ZoKwdj6iSRRhyqUISy-DWJ8Y,3731 +Cryptodome/SelfTest/Hash/test_SHA384.py,sha256=-Sv9_DcjxPTmzCxoUzvNCmV1sriEVMJg6aOuqP6iSAc,2783 +Cryptodome/SelfTest/Hash/test_SHA3_224.py,sha256=fL3av7zlmD2gfpufid8NdL3fCxnobWAd7Vbs6q8TwrY,2929 +Cryptodome/SelfTest/Hash/test_SHA3_256.py,sha256=ux8yjpBcqqJG-AsHF8M3UrG9ds1wGyURFd3I3kaAPcM,2931 +Cryptodome/SelfTest/Hash/test_SHA3_384.py,sha256=LQ0VEA37cQgk3ZglTq2gOOXk9tATND5quSEbvd6RwW8,2929 +Cryptodome/SelfTest/Hash/test_SHA3_512.py,sha256=j3Cpamopb86Nw1tun6C3FlFl23xswZ6qv6NYgAQeZEE,2930 +Cryptodome/SelfTest/Hash/test_SHA512.py,sha256=XhY1s5CewTtktS_j3iQD_e154HKrt2BWJv0H-X0Y2GQ,5350 +Cryptodome/SelfTest/Hash/test_SHAKE.py,sha256=_WtGLWrq0NNztYrjF8pBWPpsGpoiU11escw83V2fSvk,5085 +Cryptodome/SelfTest/Hash/test_TupleHash.py,sha256=OWB6YAjIXRdXsHpoWurkG7TzRIFHu55mXlWrvn0o2W0,9012 +Cryptodome/SelfTest/Hash/test_TurboSHAKE.py,sha256=L6a1zV7xhC6SyWYs6hsdUJCrUeBXJgMXzeCbJYMZm_4,15493 +Cryptodome/SelfTest/Hash/test_cSHAKE.py,sha256=hXhe8Isb-U0_aN65TXTiYbhwBc3Um6bx3GEm9_j061U,6998 +Cryptodome/SelfTest/Hash/test_keccak.py,sha256=D8SAZwG9WAwyqjIc14ptEnC_lbJ_b_vHAyV9EQXufBU,9159 +Cryptodome/SelfTest/IO/__init__.py,sha256=3_DA13iU6pdnwecWS75IE3eo_XlgIRXD5GI26f21130,2049 +Cryptodome/SelfTest/IO/__pycache__/__init__.cpython-312.pyc,, +Cryptodome/SelfTest/IO/__pycache__/test_PBES.cpython-312.pyc,, +Cryptodome/SelfTest/IO/__pycache__/test_PKCS8.cpython-312.pyc,, +Cryptodome/SelfTest/IO/test_PBES.py,sha256=UcmprWdWLzhilT3Bs8YSXI-g-lOpVIItT9tKif8g3_I,4479 +Cryptodome/SelfTest/IO/test_PKCS8.py,sha256=qJ2m91OKbhqeHWAq_2BWzmUZicbAJ5_6NIuzbboNWq0,19585 +Cryptodome/SelfTest/Math/__init__.py,sha256=lmVagI7okdGGHsqkBY9RpbE0SS2emSqm7YVUctauj6g,2269 +Cryptodome/SelfTest/Math/__pycache__/__init__.cpython-312.pyc,, +Cryptodome/SelfTest/Math/__pycache__/test_Numbers.cpython-312.pyc,, +Cryptodome/SelfTest/Math/__pycache__/test_Primality.cpython-312.pyc,, +Cryptodome/SelfTest/Math/__pycache__/test_modexp.cpython-312.pyc,, +Cryptodome/SelfTest/Math/__pycache__/test_modmult.cpython-312.pyc,, +Cryptodome/SelfTest/Math/test_Numbers.py,sha256=7ObMxyAL6Yg4xRVfH6GlXzi0dr2qZLmZIyKucN6a_g8,33242 +Cryptodome/SelfTest/Math/test_Primality.py,sha256=f9tFV1UclfImfTzAEAGJVdGMvAfl_Hs5SGUE0Cm2ts4,5019 +Cryptodome/SelfTest/Math/test_modexp.py,sha256=bz96efikMQR7BePGpwpncsFHqcLuj32FXOAisplbqOQ,8336 +Cryptodome/SelfTest/Math/test_modmult.py,sha256=SKXTiZxe_OD0xjExw761I5wgSlLqy1PAW3Hs-j9_wlw,4996 +Cryptodome/SelfTest/Protocol/__init__.py,sha256=E4zxDzu1ThOwb5zElmxVpFSGMci_hb1j3dukOVU1P2s,1975 +Cryptodome/SelfTest/Protocol/__pycache__/__init__.cpython-312.pyc,, +Cryptodome/SelfTest/Protocol/__pycache__/test_HPKE.cpython-312.pyc,, +Cryptodome/SelfTest/Protocol/__pycache__/test_KDF.cpython-312.pyc,, +Cryptodome/SelfTest/Protocol/__pycache__/test_SecretSharing.cpython-312.pyc,, +Cryptodome/SelfTest/Protocol/__pycache__/test_ecdh.cpython-312.pyc,, +Cryptodome/SelfTest/Protocol/__pycache__/test_rfc1751.cpython-312.pyc,, +Cryptodome/SelfTest/Protocol/test_HPKE.py,sha256=N31L9ZnyiIFrw1hJsrR_7l7aJZUqfPkMx_R_m1mgcuo,18157 +Cryptodome/SelfTest/Protocol/test_KDF.py,sha256=MD7YLYvZi-K7GHNdHPeCopIh7lkUMyRI40JN7E1KFcc,37681 +Cryptodome/SelfTest/Protocol/test_SecretSharing.py,sha256=7rmpyzeKEjcBowffHZGXMSePE7rSCAwzCCL5cq24TrI,10488 +Cryptodome/SelfTest/Protocol/test_ecdh.py,sha256=XIBGJjn8iCIAVWSH1t6SRUQa0x1qW6zXIBAWqryTAGg,31342 +Cryptodome/SelfTest/Protocol/test_rfc1751.py,sha256=JKckw4veTxAYjyu5k5GqRe5v_v3QsBT1_1lnVBM87oQ,2282 +Cryptodome/SelfTest/PublicKey/__init__.py,sha256=ZSDV80uJYfzI_6LrmeFlcUl7nlFCeREmpMjGRsFoOjA,2747 +Cryptodome/SelfTest/PublicKey/__pycache__/__init__.cpython-312.pyc,, +Cryptodome/SelfTest/PublicKey/__pycache__/test_DSA.cpython-312.pyc,, +Cryptodome/SelfTest/PublicKey/__pycache__/test_ECC_Curve25519.cpython-312.pyc,, +Cryptodome/SelfTest/PublicKey/__pycache__/test_ECC_Curve448.cpython-312.pyc,, +Cryptodome/SelfTest/PublicKey/__pycache__/test_ECC_Ed25519.cpython-312.pyc,, +Cryptodome/SelfTest/PublicKey/__pycache__/test_ECC_Ed448.cpython-312.pyc,, +Cryptodome/SelfTest/PublicKey/__pycache__/test_ECC_NIST.cpython-312.pyc,, +Cryptodome/SelfTest/PublicKey/__pycache__/test_ElGamal.cpython-312.pyc,, +Cryptodome/SelfTest/PublicKey/__pycache__/test_RSA.cpython-312.pyc,, +Cryptodome/SelfTest/PublicKey/__pycache__/test_import_Curve25519.cpython-312.pyc,, +Cryptodome/SelfTest/PublicKey/__pycache__/test_import_Curve448.cpython-312.pyc,, +Cryptodome/SelfTest/PublicKey/__pycache__/test_import_DSA.cpython-312.pyc,, +Cryptodome/SelfTest/PublicKey/__pycache__/test_import_ECC.cpython-312.pyc,, +Cryptodome/SelfTest/PublicKey/__pycache__/test_import_RSA.cpython-312.pyc,, +Cryptodome/SelfTest/PublicKey/test_DSA.py,sha256=nfXepxEC5O5vCmV8xtbui5VdJ4nSRwuHGqioDvPnlaM,9883 +Cryptodome/SelfTest/PublicKey/test_ECC_Curve25519.py,sha256=hEey1-GoeUI1SX1uqz88609R15VFJbrl9y88-b6yuQ8,12290 +Cryptodome/SelfTest/PublicKey/test_ECC_Curve448.py,sha256=Zyygx87oUwcjVS0ckMIR7vf5luCn72VOYfThFE6TikY,10463 +Cryptodome/SelfTest/PublicKey/test_ECC_Ed25519.py,sha256=K6YVmWU8RwvF_tDfFk1pbEs2KrRvFkvBpUN82IaMoFg,14289 +Cryptodome/SelfTest/PublicKey/test_ECC_Ed448.py,sha256=ZAqvkSdmmvdrucy_Y3Gvmf9-48bzNZU98UyqIhpcKP8,15352 +Cryptodome/SelfTest/PublicKey/test_ECC_NIST.py,sha256=MnCKJAAtbV_u6yzyNoJlk2PCVEktLb7CDIYUEdteWhc,53282 +Cryptodome/SelfTest/PublicKey/test_ElGamal.py,sha256=TWDD6dN0pM8rASwbXMW1H3qn0LW0pU73RV85WTYk-WA,8889 +Cryptodome/SelfTest/PublicKey/test_RSA.py,sha256=SczaUQG_o9Lndp3s1tbE52YKrGHtAs04CULoBAf25L8,12984 +Cryptodome/SelfTest/PublicKey/test_import_Curve25519.py,sha256=Ta-120tjGT0yWZQJplHuIzvPWbDWVSfytuW8aP2xRxk,14769 +Cryptodome/SelfTest/PublicKey/test_import_Curve448.py,sha256=wj8eODql94bVz5y_TcwbhzUFkjs9RKkJftkojGp-9JU,12863 +Cryptodome/SelfTest/PublicKey/test_import_DSA.py,sha256=7BJh1gnY2KfUzfmtL8otHv1Htu1c_mxga8H2dk0jqrs,26075 +Cryptodome/SelfTest/PublicKey/test_import_ECC.py,sha256=2xnvvVdCANaArObwi839weDDFHX52pDbnw9o8Mp-zMU,111957 +Cryptodome/SelfTest/PublicKey/test_import_RSA.py,sha256=MJrjsL_0LG93uj-JKF_Pz4JeEDAKT9HHfCYPuBL5PFk,27683 +Cryptodome/SelfTest/Random/__init__.py,sha256=nG2fG7KxKdk3vjJAPv7oxIzjoWPXCR30igMtOXbRBdA,1585 +Cryptodome/SelfTest/Random/__pycache__/__init__.cpython-312.pyc,, +Cryptodome/SelfTest/Random/__pycache__/test_random.cpython-312.pyc,, +Cryptodome/SelfTest/Random/test_random.py,sha256=hM7EBH_QXkS8k-YSp0uaclVLSZKXpk8MpOk3OM6hgro,7181 +Cryptodome/SelfTest/Signature/__init__.py,sha256=7p13oPA-kRcGBe5bvB_dNRAwUEtohA5dGsh8aIsr2u0,1599 +Cryptodome/SelfTest/Signature/__pycache__/__init__.cpython-312.pyc,, +Cryptodome/SelfTest/Signature/__pycache__/test_dss.cpython-312.pyc,, +Cryptodome/SelfTest/Signature/__pycache__/test_eddsa.cpython-312.pyc,, +Cryptodome/SelfTest/Signature/__pycache__/test_pkcs1_15.cpython-312.pyc,, +Cryptodome/SelfTest/Signature/__pycache__/test_pss.cpython-312.pyc,, +Cryptodome/SelfTest/Signature/test_dss.py,sha256=PFKAVBOvoYVJb3Xf48_6PiRET-3gR5NVGnyCSLPJ3FA,58499 +Cryptodome/SelfTest/Signature/test_eddsa.py,sha256=VuoE5OTKqDTL-ZQTUcxBf_gzJG2lY3_KJNRi5Bf8qz0,25670 +Cryptodome/SelfTest/Signature/test_pkcs1_15.py,sha256=N0sFu7hIPRiVNHcQbbFgkLSVvBjwFOadv-EfjwwX_P8,13949 +Cryptodome/SelfTest/Signature/test_pss.py,sha256=mPBWAhUM9aM1Hr49U-FoGmPRoYDoJd3c8vb3CkZfEos,16244 +Cryptodome/SelfTest/Util/__init__.py,sha256=sKEqiyQt8ygT-eU2Q9OxsVeJ-EC1Cwk7CFzVLABSqRY,2067 +Cryptodome/SelfTest/Util/__pycache__/__init__.cpython-312.pyc,, +Cryptodome/SelfTest/Util/__pycache__/test_Counter.cpython-312.pyc,, +Cryptodome/SelfTest/Util/__pycache__/test_Padding.cpython-312.pyc,, +Cryptodome/SelfTest/Util/__pycache__/test_asn1.cpython-312.pyc,, +Cryptodome/SelfTest/Util/__pycache__/test_number.cpython-312.pyc,, +Cryptodome/SelfTest/Util/__pycache__/test_rfc1751.cpython-312.pyc,, +Cryptodome/SelfTest/Util/__pycache__/test_strxor.cpython-312.pyc,, +Cryptodome/SelfTest/Util/test_Counter.py,sha256=AnY96wFWT-Q69r3H3Fdtawj3od3eBLDca_u6VBzfhdM,2359 +Cryptodome/SelfTest/Util/test_Padding.py,sha256=sP03TMZWSc6a5U5--Z5JL2IG7HP6lg0wJiayKr74S-8,5942 +Cryptodome/SelfTest/Util/test_asn1.py,sha256=NmLdlQYXkvI51ujcQbbyR5RDoDhwLm6cpIm7jcW-sp8,32127 +Cryptodome/SelfTest/Util/test_number.py,sha256=Bn3xAEGhPUxiJYaspf5kHPn1OdcvAoI4rvKoVp0mACc,8738 +Cryptodome/SelfTest/Util/test_rfc1751.py,sha256=L_vSzipsLKMogO2onNb6HKNgrKAdyxQEDSK3LhkJaB8,1159 +Cryptodome/SelfTest/Util/test_strxor.py,sha256=LVgW3GgviQYwY1X04faZpdbeX4fPqF1KneCQXW3e-Bo,10503 +Cryptodome/SelfTest/__init__.py,sha256=14AVlJVdw-pXJMvbRPD0b2z6Ox8JL18biYo-N0gn6zo,3327 +Cryptodome/SelfTest/__main__.py,sha256=Nx-CpEOKkKC7fs1M1bEN9rp6kullntlC2n8UMbEufq4,1616 +Cryptodome/SelfTest/__pycache__/__init__.cpython-312.pyc,, +Cryptodome/SelfTest/__pycache__/__main__.cpython-312.pyc,, +Cryptodome/SelfTest/__pycache__/loader.cpython-312.pyc,, +Cryptodome/SelfTest/__pycache__/st_common.cpython-312.pyc,, +Cryptodome/SelfTest/loader.py,sha256=xm9IlBI0xKS95z8K37rA7iOga6lVcOUMCrJtEXXx-b8,8772 +Cryptodome/SelfTest/st_common.py,sha256=48jAxordmWzd0mUrC9lcrdCmWIIrWSMBKDhpcHt1c4o,2004 +Cryptodome/Signature/DSS.py,sha256=4SFgsM4hNTz-_Rw_dsLp3XIFb1suesbXGkjCVNnHaFU,15759 +Cryptodome/Signature/DSS.pyi,sha256=w-tPYhEcjIpy-nn_rclUaNuq1C_NrumC8FbUCprT1Jk,1129 +Cryptodome/Signature/PKCS1_PSS.py,sha256=9blwjmK9uryHmi8iEzHo1eZiS_xbtmphCoG0nSQwC0E,2158 +Cryptodome/Signature/PKCS1_PSS.pyi,sha256=NhjU5nYnFqXvCWQ9cRBsIyzN4FLzk71G3LO8Au7VCko,899 +Cryptodome/Signature/PKCS1_v1_5.py,sha256=ovXeDCf9V4wWlzC1qtqmxNnrISxpmYsOaIVIcPtMXh0,2046 +Cryptodome/Signature/PKCS1_v1_5.pyi,sha256=inbpbrILX1ANs_Q2a9raR6JZjNv5phf81Ynr1qZWO2c,471 +Cryptodome/Signature/__init__.py,sha256=JWfZ2t5myM6ZgcGzhWOYcI__UDfmq79MCp1gr70ehng,1731 +Cryptodome/Signature/__pycache__/DSS.cpython-312.pyc,, +Cryptodome/Signature/__pycache__/PKCS1_PSS.cpython-312.pyc,, +Cryptodome/Signature/__pycache__/PKCS1_v1_5.cpython-312.pyc,, +Cryptodome/Signature/__pycache__/__init__.cpython-312.pyc,, +Cryptodome/Signature/__pycache__/eddsa.cpython-312.pyc,, +Cryptodome/Signature/__pycache__/pkcs1_15.cpython-312.pyc,, +Cryptodome/Signature/__pycache__/pss.cpython-312.pyc,, +Cryptodome/Signature/eddsa.py,sha256=yawYjsmgA44CEXqwdVjR0JzMc1W6VrmtN0gKkqPwnow,12839 +Cryptodome/Signature/eddsa.pyi,sha256=bSXx1RLkK25zKciyauEdqjMODxLV55tSBmNP_mCfj50,751 +Cryptodome/Signature/pkcs1_15.py,sha256=_geed3emKWonOQGp6zEGAO2HLmfUlEy0p2kvKrDiE_8,9124 +Cryptodome/Signature/pkcs1_15.pyi,sha256=2d-TAoyCTE1NFxYRtuxNL-RgDzUtwQKS1O6qYOCpt-s,585 +Cryptodome/Signature/pss.py,sha256=m2hrm5Mfuv-hITleslbY1Qcg7QdbJL2HY6qUkES7iHY,14030 +Cryptodome/Signature/pss.pyi,sha256=G5gBEHSzflN-KisdkNG8QAPhjbf3tO64gW8mkEkakSs,1075 +Cryptodome/Util/Counter.py,sha256=O_VXKIiDpNd4rSFWta1fIPThEa6uANJrBbJnb6WS598,3292 +Cryptodome/Util/Counter.pyi,sha256=eoZmE3DDuJSutO2th1VGbeUiJliGCKUw9j8-M3lYWtA,295 +Cryptodome/Util/Padding.py,sha256=Tn9u-ZXI2BdOGLRoJ2tkotR-g0mrMarXAqjc5ZpYfkY,4471 +Cryptodome/Util/Padding.pyi,sha256=7UZLeznSSB0sTeH_kIMIrffwNbIbP3okLkafG9Fz3vY,243 +Cryptodome/Util/RFC1751.py,sha256=1gLiw7x6XreqaVXGTPp-kPau1VvMr4w7GXylj06x74A,21590 +Cryptodome/Util/RFC1751.pyi,sha256=drLaU0h38iJuotQew2ZR6psDRPVBt7En3WxRmU-Q8sU,166 +Cryptodome/Util/__init__.py,sha256=CJ-OxQjwPewAiIThgkuXk_nzekhq7X6v75Q8w2X4_M0,1992 +Cryptodome/Util/__pycache__/Counter.cpython-312.pyc,, +Cryptodome/Util/__pycache__/Padding.cpython-312.pyc,, +Cryptodome/Util/__pycache__/RFC1751.cpython-312.pyc,, +Cryptodome/Util/__pycache__/__init__.cpython-312.pyc,, +Cryptodome/Util/__pycache__/_cpu_features.cpython-312.pyc,, +Cryptodome/Util/__pycache__/_file_system.cpython-312.pyc,, +Cryptodome/Util/__pycache__/_raw_api.cpython-312.pyc,, +Cryptodome/Util/__pycache__/asn1.cpython-312.pyc,, +Cryptodome/Util/__pycache__/number.cpython-312.pyc,, +Cryptodome/Util/__pycache__/py3compat.cpython-312.pyc,, +Cryptodome/Util/__pycache__/strxor.cpython-312.pyc,, +Cryptodome/Util/_cpu_features.py,sha256=SkiSUK5cWcK6atnwcn6IsN37u8B50jb6NCkF9Y-ZgcQ,2043 +Cryptodome/Util/_cpu_features.pyi,sha256=cv2cS7_1lUxY465cQhM056Vw5egQjctFSZ-LSXs1n14,61 +Cryptodome/Util/_cpuid_c.pyd,sha256=5-byfVIDdo5kVLQGaEejrwJUjIERRtoEfEpTse2vMuk,10240 +Cryptodome/Util/_file_system.py,sha256=M6NhN7P5s89I7M1wEtrirImOWTiItgIGukwyCxPIdXM,2237 +Cryptodome/Util/_file_system.pyi,sha256=L4sFdpksF9gZERm3jPUvc1QPEfJQI2D3Emb1_4SPtbU,103 +Cryptodome/Util/_raw_api.py,sha256=tGqoc3m4j4n2X1DC8UofaNt4K_8G-KK1TsDjvYsxh1U,10889 +Cryptodome/Util/_raw_api.pyi,sha256=g8awMQyCtBk4MNWbPaviNUSs9T_ytT4PkY8ujbAfdIU,933 +Cryptodome/Util/_strxor.pyd,sha256=yAwbFpuJSxQaYPmf2A4NzrHJpZh0gxXCa5VYMdnfRrU,10240 +Cryptodome/Util/asn1.py,sha256=MCxCuyZKfjTxJENYQvDtcxz6GhmcEi4mH1xzBwP56z0,37269 +Cryptodome/Util/asn1.pyi,sha256=TbiJckZUYF_3WcW311QXTRP3GztiF5LkitD5vgz8zFc,3885 +Cryptodome/Util/number.py,sha256=R7_bW-riX7mzRJ2d-IMbnpnelRKQyMgPsdGqKcFOwX4,97920 +Cryptodome/Util/number.pyi,sha256=a9Z-OpCJlyRfs3O8HElxusDP3V_BfUt829P1GtZ3SvE,994 +Cryptodome/Util/py3compat.py,sha256=EtsGMSWCXKvqhWl_qnK_1-5aWjald37O_4JxPfZ-aQI,6014 +Cryptodome/Util/py3compat.pyi,sha256=oZE5dvF4wouKfBFwkyM6rA0-dyxIdtqcCEOCu5XyrC0,870 +Cryptodome/Util/strxor.py,sha256=I-eUQrEdRcYcxNLgR_eYHnPTtEtWl8wvwiENpTwjlgQ,5595 +Cryptodome/Util/strxor.pyi,sha256=yn0HPHSZjP-1AaLm4cma9i9JJypf37NSd2nipjLf4aA,249 +Cryptodome/__init__.py,sha256=CAWH9-flJuapdfreK7J8piAKDdgwJU_dDxwDbhb8hX0,191 +Cryptodome/__init__.pyi,sha256=dI0zM5MRGHxhnfjqpAyPGotKTrPlneTN2Q-jAQXNg1E,103 +Cryptodome/__pycache__/__init__.cpython-312.pyc,, +Cryptodome/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +pycryptodomex-3.23.0.dist-info/AUTHORS.rst,sha256=rJTeKE8VIq7k8-fjAeaK8ZB4a0yDiNGmDLpKOhu-NGU,815 +pycryptodomex-3.23.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +pycryptodomex-3.23.0.dist-info/LICENSE.rst,sha256=YLiVip75t-xRIIe3JVVTchde0rArlp-HJbhTT95IrN0,2987 +pycryptodomex-3.23.0.dist-info/METADATA,sha256=5mRTB_rVrbR-SdzWwd7HzfqoMD_zYoTjsRVSCy94DRQ,3453 +pycryptodomex-3.23.0.dist-info/RECORD,, +pycryptodomex-3.23.0.dist-info/WHEEL,sha256=-EX5DQzNGQEoyL99Q-0P0-D-CXbfqafenaAeiSQ_Ufk,100 +pycryptodomex-3.23.0.dist-info/top_level.txt,sha256=eHU9ase6in1ZSBEtTDpl7fwIPION42nbqZ1uFTyccxs,11 diff --git a/venv/Lib/site-packages/pycryptodomex-3.23.0.dist-info/WHEEL b/venv/Lib/site-packages/pycryptodomex-3.23.0.dist-info/WHEEL new file mode 100644 index 0000000..816dfea --- /dev/null +++ b/venv/Lib/site-packages/pycryptodomex-3.23.0.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.42.0) +Root-Is-Purelib: false +Tag: cp37-abi3-win_amd64 + diff --git a/venv/Lib/site-packages/pycryptodomex-3.23.0.dist-info/top_level.txt b/venv/Lib/site-packages/pycryptodomex-3.23.0.dist-info/top_level.txt new file mode 100644 index 0000000..9cbd375 --- /dev/null +++ b/venv/Lib/site-packages/pycryptodomex-3.23.0.dist-info/top_level.txt @@ -0,0 +1 @@ +Cryptodome diff --git a/venv/Lib/site-packages/pyopenssl-25.3.0.dist-info/INSTALLER b/venv/Lib/site-packages/pyopenssl-25.3.0.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/venv/Lib/site-packages/pyopenssl-25.3.0.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/venv/Lib/site-packages/pyopenssl-25.3.0.dist-info/METADATA b/venv/Lib/site-packages/pyopenssl-25.3.0.dist-info/METADATA new file mode 100644 index 0000000..5c46dbe --- /dev/null +++ b/venv/Lib/site-packages/pyopenssl-25.3.0.dist-info/METADATA @@ -0,0 +1,525 @@ +Metadata-Version: 2.4 +Name: pyOpenSSL +Version: 25.3.0 +Summary: Python wrapper module around the OpenSSL library +Home-page: https://pyopenssl.org/ +Author: The pyOpenSSL developers +Author-email: cryptography-dev@python.org +License: Apache License, Version 2.0 +Project-URL: Source, https://github.com/pyca/pyopenssl +Classifier: Development Status :: 6 - Mature +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: Apache Software License +Classifier: Operating System :: MacOS :: MacOS X +Classifier: Operating System :: Microsoft :: Windows +Classifier: Operating System :: POSIX +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: 3.9 +Classifier: Programming Language :: Python :: 3.10 +Classifier: Programming Language :: Python :: 3.11 +Classifier: Programming Language :: Python :: 3.12 +Classifier: Programming Language :: Python :: 3.13 +Classifier: Programming Language :: Python :: Implementation :: CPython +Classifier: Programming Language :: Python :: Implementation :: PyPy +Classifier: Topic :: Security :: Cryptography +Classifier: Topic :: Software Development :: Libraries :: Python Modules +Classifier: Topic :: System :: Networking +Requires-Python: >=3.7 +License-File: LICENSE +Requires-Dist: cryptography<47,>=45.0.7 +Requires-Dist: typing-extensions>=4.9; python_version < "3.13" and python_version >= "3.8" +Provides-Extra: test +Requires-Dist: pytest-rerunfailures; extra == "test" +Requires-Dist: pretend; extra == "test" +Requires-Dist: pytest>=3.0.1; extra == "test" +Provides-Extra: docs +Requires-Dist: sphinx!=5.2.0,!=5.2.0.post0,!=7.2.5; extra == "docs" +Requires-Dist: sphinx_rtd_theme; extra == "docs" +Dynamic: author +Dynamic: author-email +Dynamic: classifier +Dynamic: description +Dynamic: home-page +Dynamic: license +Dynamic: license-file +Dynamic: project-url +Dynamic: provides-extra +Dynamic: requires-dist +Dynamic: requires-python +Dynamic: summary + +======================================================== +pyOpenSSL -- A Python wrapper around the OpenSSL library +======================================================== + +.. image:: https://readthedocs.org/projects/pyopenssl/badge/?version=stable + :target: https://pyopenssl.org/en/stable/ + :alt: Stable Docs + +.. image:: https://github.com/pyca/pyopenssl/workflows/CI/badge.svg?branch=main + :target: https://github.com/pyca/pyopenssl/actions?query=workflow%3ACI+branch%3Amain + +**Note:** The Python Cryptographic Authority **strongly suggests** the use of `pyca/cryptography`_ +where possible. If you are using pyOpenSSL for anything other than making a TLS connection +**you should move to cryptography and drop your pyOpenSSL dependency**. + +High-level wrapper around a subset of the OpenSSL library. Includes + +* ``SSL.Connection`` objects, wrapping the methods of Python's portable sockets +* Callbacks written in Python +* Extensive error-handling mechanism, mirroring OpenSSL's error codes + +... and much more. + +You can find more information in the documentation_. +Development takes place on GitHub_. + + +Discussion +========== + +If you run into bugs, you can file them in our `issue tracker`_. + +We maintain a cryptography-dev_ mailing list for both user and development discussions. + +You can also join ``#pyca`` on ``irc.libera.chat`` to ask questions or get involved. + + +.. _documentation: https://pyopenssl.org/ +.. _`issue tracker`: https://github.com/pyca/pyopenssl/issues +.. _cryptography-dev: https://mail.python.org/mailman/listinfo/cryptography-dev +.. _GitHub: https://github.com/pyca/pyopenssl +.. _`pyca/cryptography`: https://github.com/pyca/cryptography + + +Release Information +=================== + +25.4.0 (UNRELEASED) +------------------- + +Backward-incompatible changes: +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Deprecations: +^^^^^^^^^^^^^ + +Changes: +^^^^^^^^ + +25.3.0 (2025-09-16) +------------------- + +Backward-incompatible changes: +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Deprecations: +^^^^^^^^^^^^^ + +Changes: +^^^^^^^^ + +- Maximum supported ``cryptography`` version is now 46.x. + + +25.2.0 (2025-09-14) +------------------- + +Backward-incompatible changes: +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +- The minimum ``cryptography`` version is now 45.0.7. + +Deprecations: +^^^^^^^^^^^^^ + +Changes: +^^^^^^^^ + +- pyOpenSSL now sets ``SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER`` on connections by default, matching CPython's behavior. +- Added ``OpenSSL.SSL.Context.clear_mode``. +- Added ``OpenSSL.SSL.Context.set_tls13_ciphersuites`` to set the allowed TLS 1.3 ciphers. +- Added ``OpenSSL.SSL.Connection.set_info_callback`` + +25.1.0 (2025-05-17) +------------------- + +Backward-incompatible changes: +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Deprecations: +^^^^^^^^^^^^^ + +- Attempting using any methods that mutate an ``OpenSSL.SSL.Context`` after it + has been used to create an ``OpenSSL.SSL.Connection`` will emit a warning. In + a future release, this will raise an exception. + +Changes: +^^^^^^^^ + +* ``cryptography`` maximum version has been increased to 45.0.x. + + +25.0.0 (2025-01-12) +------------------- + +Backward-incompatible changes: +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Deprecations: +^^^^^^^^^^^^^ + +Changes: +^^^^^^^^ + +- Corrected type annotations on ``Context.set_alpn_select_callback``, ``Context.set_session_cache_mode``, ``Context.set_options``, ``Context.set_mode``, ``X509.subject_name_hash``, and ``X509Store.load_locations``. +- Deprecated APIs are now marked using ``warnings.deprecated``. ``mypy`` will emit deprecation notices for them when used with ``--enable-error-code deprecated``. + +24.3.0 (2024-11-27) +------------------- + +Backward-incompatible changes: +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +- Removed the deprecated ``OpenSSL.crypto.CRL``, ``OpenSSL.crypto.Revoked``, ``OpenSSL.crypto.dump_crl``, and ``OpenSSL.crypto.load_crl``. ``cryptography.x509``'s CRL functionality should be used instead. +- Removed the deprecated ``OpenSSL.crypto.sign`` and ``OpenSSL.crypto.verify``. ``cryptography.hazmat.primitives.asymmetric``'s signature APIs should be used instead. + +Deprecations: +^^^^^^^^^^^^^ + +- Deprecated ``OpenSSL.rand`` - callers should use ``os.urandom()`` instead. +- Deprecated ``add_extensions`` and ``get_extensions`` on ``OpenSSL.crypto.X509Req`` and ``OpenSSL.crypto.X509``. These should have been deprecated at the same time ``X509Extension`` was. Users should use pyca/cryptography's X.509 APIs instead. +- Deprecated ``OpenSSL.crypto.get_elliptic_curves`` and ``OpenSSL.crypto.get_elliptic_curve``, as well as passing the reult of them to ``OpenSSL.SSL.Context.set_tmp_ecdh``, users should instead pass curves from ``cryptography``. +- Deprecated passing ``X509`` objects to ``OpenSSL.SSL.Context.use_certificate``, ``OpenSSL.SSL.Connection.use_certificate``, ``OpenSSL.SSL.Context.add_extra_chain_cert``, and ``OpenSSL.SSL.Context.add_client_ca``, users should instead pass ``cryptography.x509.Certificate`` instances. This is in preparation for deprecating pyOpenSSL's ``X509`` entirely. +- Deprecated passing ``PKey`` objects to ``OpenSSL.SSL.Context.use_privatekey`` and ``OpenSSL.SSL.Connection.use_privatekey``, users should instead pass ``cryptography`` priate key instances. This is in preparation for deprecating pyOpenSSL's ``PKey`` entirely. + +Changes: +^^^^^^^^ + +* ``cryptography`` maximum version has been increased to 44.0.x. +* ``OpenSSL.SSL.Connection.get_certificate``, ``OpenSSL.SSL.Connection.get_peer_certificate``, ``OpenSSL.SSL.Connection.get_peer_cert_chain``, and ``OpenSSL.SSL.Connection.get_verified_chain`` now take an ``as_cryptography`` keyword-argument. When ``True`` is passed then ``cryptography.x509.Certificate`` are returned, instead of ``OpenSSL.crypto.X509``. In the future, passing ``False`` (the default) will be deprecated. + + +24.2.1 (2024-07-20) +------------------- + +Backward-incompatible changes: +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Deprecations: +^^^^^^^^^^^^^ + +Changes: +^^^^^^^^ + +- Fixed changelog to remove sphinx specific restructured text strings. + + +24.2.0 (2024-07-20) +------------------- + +Backward-incompatible changes: +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Deprecations: +^^^^^^^^^^^^^ + +- Deprecated ``OpenSSL.crypto.X509Req``, ``OpenSSL.crypto.load_certificate_request``, ``OpenSSL.crypto.dump_certificate_request``. Instead, ``cryptography.x509.CertificateSigningRequest``, ``cryptography.x509.CertificateSigningRequestBuilder``, ``cryptography.x509.load_der_x509_csr``, or ``cryptography.x509.load_pem_x509_csr`` should be used. + +Changes: +^^^^^^^^ + +- Added type hints for the ``SSL`` module. + `#1308 `_. +- Changed ``OpenSSL.crypto.PKey.from_cryptography_key`` to accept public and private EC, ED25519, ED448 keys. + `#1310 `_. + +24.1.0 (2024-03-09) +------------------- + +Backward-incompatible changes: +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Removed the deprecated ``OpenSSL.crypto.PKCS12`` and + ``OpenSSL.crypto.NetscapeSPKI``. ``OpenSSL.crypto.PKCS12`` may be replaced + by the PKCS#12 APIs in the ``cryptography`` package. + +Deprecations: +^^^^^^^^^^^^^ + +Changes: +^^^^^^^^ + +24.0.0 (2024-01-22) +------------------- + +Backward-incompatible changes: +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Deprecations: +^^^^^^^^^^^^^ + +Changes: +^^^^^^^^ + +- Added ``OpenSSL.SSL.Connection.get_selected_srtp_profile`` to determine which SRTP profile was negotiated. + `#1279 `_. + +23.3.0 (2023-10-25) +------------------- + +Backward-incompatible changes: +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +- Dropped support for Python 3.6. +- The minimum ``cryptography`` version is now 41.0.5. +- Removed ``OpenSSL.crypto.load_pkcs7`` and ``OpenSSL.crypto.load_pkcs12`` which had been deprecated for 3 years. +- Added ``OpenSSL.SSL.OP_LEGACY_SERVER_CONNECT`` to allow legacy insecure renegotiation between OpenSSL and unpatched servers. + `#1234 `_. + +Deprecations: +^^^^^^^^^^^^^ + +- Deprecated ``OpenSSL.crypto.PKCS12`` (which was intended to have been deprecated at the same time as ``OpenSSL.crypto.load_pkcs12``). +- Deprecated ``OpenSSL.crypto.NetscapeSPKI``. +- Deprecated ``OpenSSL.crypto.CRL`` +- Deprecated ``OpenSSL.crypto.Revoked`` +- Deprecated ``OpenSSL.crypto.load_crl`` and ``OpenSSL.crypto.dump_crl`` +- Deprecated ``OpenSSL.crypto.sign`` and ``OpenSSL.crypto.verify`` +- Deprecated ``OpenSSL.crypto.X509Extension`` + +Changes: +^^^^^^^^ + +- Changed ``OpenSSL.crypto.X509Store.add_crl`` to also accept + ``cryptography``'s ``x509.CertificateRevocationList`` arguments in addition + to the now deprecated ``OpenSSL.crypto.CRL`` arguments. +- Fixed ``test_set_default_verify_paths`` test so that it is skipped if no + network connection is available. + +23.2.0 (2023-05-30) +------------------- + +Backward-incompatible changes: +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +- Removed ``X509StoreFlags.NOTIFY_POLICY``. + `#1213 `_. + +Deprecations: +^^^^^^^^^^^^^ + +Changes: +^^^^^^^^ + +- ``cryptography`` maximum version has been increased to 41.0.x. +- Invalid versions are now rejected in ``OpenSSL.crypto.X509Req.set_version``. +- Added ``X509VerificationCodes`` to ``OpenSSL.SSL``. + `#1202 `_. + +23.1.1 (2023-03-28) +------------------- + +Backward-incompatible changes: +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Deprecations: +^^^^^^^^^^^^^ + +Changes: +^^^^^^^^ + +- Worked around an issue in OpenSSL 3.1.0 which caused `X509Extension.get_short_name` to raise an exception when no short name was known to OpenSSL. + `#1204 `_. + +23.1.0 (2023-03-24) +------------------- + +Backward-incompatible changes: +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Deprecations: +^^^^^^^^^^^^^ + +Changes: +^^^^^^^^ + +- ``cryptography`` maximum version has been increased to 40.0.x. +- Add ``OpenSSL.SSL.Connection.DTLSv1_get_timeout`` and ``OpenSSL.SSL.Connection.DTLSv1_handle_timeout`` + to support DTLS timeouts `#1180 `_. + +23.0.0 (2023-01-01) +------------------- + +Backward-incompatible changes: +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Deprecations: +^^^^^^^^^^^^^ + +Changes: +^^^^^^^^ + +- Add ``OpenSSL.SSL.X509StoreFlags.PARTIAL_CHAIN`` constant to allow for users + to perform certificate verification on partial certificate chains. + `#1166 `_ +- ``cryptography`` maximum version has been increased to 39.0.x. + +22.1.0 (2022-09-25) +------------------- + +Backward-incompatible changes: +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +- Remove support for SSLv2 and SSLv3. +- The minimum ``cryptography`` version is now 38.0.x (and we now pin releases + against ``cryptography`` major versions to prevent future breakage) +- The ``OpenSSL.crypto.X509StoreContextError`` exception has been refactored, + changing its internal attributes. + `#1133 `_ + +Deprecations: +^^^^^^^^^^^^^ + +- ``OpenSSL.SSL.SSLeay_version`` is deprecated in favor of + ``OpenSSL.SSL.OpenSSL_version``. The constants ``OpenSSL.SSL.SSLEAY_*`` are + deprecated in favor of ``OpenSSL.SSL.OPENSSL_*``. + +Changes: +^^^^^^^^ + +- Add ``OpenSSL.SSL.Connection.set_verify`` and ``OpenSSL.SSL.Connection.get_verify_mode`` + to override the context object's verification flags. + `#1073 `_ +- Add ``OpenSSL.SSL.Connection.use_certificate`` and ``OpenSSL.SSL.Connection.use_privatekey`` + to set a certificate per connection (and not just per context) `#1121 `_. + +22.0.0 (2022-01-29) +------------------- + +Backward-incompatible changes: +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +- Drop support for Python 2.7. + `#1047 `_ +- The minimum ``cryptography`` version is now 35.0. + +Deprecations: +^^^^^^^^^^^^^ + +Changes: +^^^^^^^^ + +- Expose wrappers for some `DTLS + `_ + primitives. `#1026 `_ + +21.0.0 (2021-09-28) +------------------- + +Backward-incompatible changes: +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +- The minimum ``cryptography`` version is now 3.3. +- Drop support for Python 3.5 + +Deprecations: +^^^^^^^^^^^^^ + +Changes: +^^^^^^^^ + +- Raise an error when an invalid ALPN value is set. + `#993 `_ +- Added ``OpenSSL.SSL.Context.set_min_proto_version`` and ``OpenSSL.SSL.Context.set_max_proto_version`` + to set the minimum and maximum supported TLS version `#985 `_. +- Updated ``to_cryptography`` and ``from_cryptography`` methods to support an upcoming release of ``cryptography`` without raising deprecation warnings. + `#1030 `_ + +20.0.1 (2020-12-15) +------------------- + +Backward-incompatible changes: +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Deprecations: +^^^^^^^^^^^^^ + +Changes: +^^^^^^^^ + +- Fixed compatibility with OpenSSL 1.1.0. + +20.0.0 (2020-11-27) +------------------- + + +Backward-incompatible changes: +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +- The minimum ``cryptography`` version is now 3.2. +- Remove deprecated ``OpenSSL.tsafe`` module. +- Removed deprecated ``OpenSSL.SSL.Context.set_npn_advertise_callback``, ``OpenSSL.SSL.Context.set_npn_select_callback``, and ``OpenSSL.SSL.Connection.get_next_proto_negotiated``. +- Drop support for Python 3.4 +- Drop support for OpenSSL 1.0.1 and 1.0.2 + +Deprecations: +^^^^^^^^^^^^^ + +- Deprecated ``OpenSSL.crypto.load_pkcs7`` and ``OpenSSL.crypto.load_pkcs12``. + +Changes: +^^^^^^^^ + +- Added a new optional ``chain`` parameter to ``OpenSSL.crypto.X509StoreContext()`` + where additional untrusted certificates can be specified to help chain building. + `#948 `_ +- Added ``OpenSSL.crypto.X509Store.load_locations`` to set trusted + certificate file bundles and/or directories for verification. + `#943 `_ +- Added ``Context.set_keylog_callback`` to log key material. + `#910 `_ +- Added ``OpenSSL.SSL.Connection.get_verified_chain`` to retrieve the + verified certificate chain of the peer. + `#894 `_. +- Make verification callback optional in ``Context.set_verify``. + If omitted, OpenSSL's default verification is used. + `#933 `_ +- Fixed a bug that could truncate or cause a zero-length key error due to a + null byte in private key passphrase in ``OpenSSL.crypto.load_privatekey`` + and ``OpenSSL.crypto.dump_privatekey``. + `#947 `_ + +19.1.0 (2019-11-18) +------------------- + + +Backward-incompatible changes: +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +- Removed deprecated ``ContextType``, ``ConnectionType``, ``PKeyType``, ``X509NameType``, ``X509ReqType``, ``X509Type``, ``X509StoreType``, ``CRLType``, ``PKCS7Type``, ``PKCS12Type``, and ``NetscapeSPKIType`` aliases. + Use the classes without the ``Type`` suffix instead. + `#814 `_ +- The minimum ``cryptography`` version is now 2.8 due to issues on macOS with a transitive dependency. + `#875 `_ + +Deprecations: +^^^^^^^^^^^^^ + +- Deprecated ``OpenSSL.SSL.Context.set_npn_advertise_callback``, ``OpenSSL.SSL.Context.set_npn_select_callback``, and ``OpenSSL.SSL.Connection.get_next_proto_negotiated``. + ALPN should be used instead. + `#820 `_ + + +Changes: +^^^^^^^^ + +- Support ``bytearray`` in ``SSL.Connection.send()`` by using cffi's from_buffer. + `#852 `_ +- The ``OpenSSL.SSL.Context.set_alpn_select_callback`` can return a new ``NO_OVERLAPPING_PROTOCOLS`` sentinel value + to allow a TLS handshake to complete without an application protocol. + +`Full changelog `_. + diff --git a/venv/Lib/site-packages/pyopenssl-25.3.0.dist-info/RECORD b/venv/Lib/site-packages/pyopenssl-25.3.0.dist-info/RECORD new file mode 100644 index 0000000..a273aa2 --- /dev/null +++ b/venv/Lib/site-packages/pyopenssl-25.3.0.dist-info/RECORD @@ -0,0 +1,21 @@ +OpenSSL/SSL.py,sha256=KzyeY0OEOTCiASBbgYC5AEEQ0qFNDv8JqEqfDz2CmW4,115717 +OpenSSL/__init__.py,sha256=46ENrQmALeGbnIoOeFaa3xEiaGcmoYPa16Dfdp6hMio,497 +OpenSSL/__pycache__/SSL.cpython-312.pyc,, +OpenSSL/__pycache__/__init__.cpython-312.pyc,, +OpenSSL/__pycache__/_util.cpython-312.pyc,, +OpenSSL/__pycache__/crypto.cpython-312.pyc,, +OpenSSL/__pycache__/debug.cpython-312.pyc,, +OpenSSL/__pycache__/rand.cpython-312.pyc,, +OpenSSL/__pycache__/version.cpython-312.pyc,, +OpenSSL/_util.py,sha256=FUIjL9tiCFmyQBBvICPcGd6vqjCmvx-OFKhHEVM-pZE,3692 +OpenSSL/crypto.py,sha256=KxbXAitSJDMQpZ0dsD25osnvgwqrWQ3m1YMK5uLzEhU,79657 +OpenSSL/debug.py,sha256=vCl77f2MslUoTRSu9fqP5DL_9DK_RSC7Jpu07Ip9gQM,1008 +OpenSSL/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +OpenSSL/rand.py,sha256=tSxdA95ITOS24rLCI-tE_hm4V8-i68d6nDGFt4vROQM,1252 +OpenSSL/version.py,sha256=sBsBulyckMCs-65_YlxSzhnC56644kYqbdyQvFIUHps,641 +pyopenssl-25.3.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +pyopenssl-25.3.0.dist-info/METADATA,sha256=GvHLx6jxAeyBfkStQxKGIc5ZVEyOXEFYUn2n2hDzmBY,17950 +pyopenssl-25.3.0.dist-info/RECORD,, +pyopenssl-25.3.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91 +pyopenssl-25.3.0.dist-info/licenses/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358 +pyopenssl-25.3.0.dist-info/top_level.txt,sha256=NNxWqS8hKNJh2cUXa1RZOMX62VJfyd8URo1TsYnR_MU,8 diff --git a/venv/Lib/site-packages/pyopenssl-25.3.0.dist-info/WHEEL b/venv/Lib/site-packages/pyopenssl-25.3.0.dist-info/WHEEL new file mode 100644 index 0000000..e7fa31b --- /dev/null +++ b/venv/Lib/site-packages/pyopenssl-25.3.0.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: setuptools (80.9.0) +Root-Is-Purelib: true +Tag: py3-none-any + diff --git a/venv/Lib/site-packages/pyopenssl-25.3.0.dist-info/licenses/LICENSE b/venv/Lib/site-packages/pyopenssl-25.3.0.dist-info/licenses/LICENSE new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/venv/Lib/site-packages/pyopenssl-25.3.0.dist-info/licenses/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/venv/Lib/site-packages/pyopenssl-25.3.0.dist-info/top_level.txt b/venv/Lib/site-packages/pyopenssl-25.3.0.dist-info/top_level.txt new file mode 100644 index 0000000..effce34 --- /dev/null +++ b/venv/Lib/site-packages/pyopenssl-25.3.0.dist-info/top_level.txt @@ -0,0 +1 @@ +OpenSSL diff --git a/venv/Lib/site-packages/python_alipay_sdk-3.4.0.dist-info/INSTALLER b/venv/Lib/site-packages/python_alipay_sdk-3.4.0.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/venv/Lib/site-packages/python_alipay_sdk-3.4.0.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/venv/Lib/site-packages/python_alipay_sdk-3.4.0.dist-info/METADATA b/venv/Lib/site-packages/python_alipay_sdk-3.4.0.dist-info/METADATA new file mode 100644 index 0000000..d78927f --- /dev/null +++ b/venv/Lib/site-packages/python_alipay_sdk-3.4.0.dist-info/METADATA @@ -0,0 +1,29 @@ +Metadata-Version: 2.4 +Name: python-alipay-sdk +Version: 3.4.0 +Summary: Python SDK for AliPay, RSA is the only sign method we support +Home-page: https://github.com/fzlee/alipay +Author: fzlee +Author-email: hi@ifconfiger.com +License: BSD +Keywords: python sdk alipay +Classifier: Development Status :: 3 - Alpha +Classifier: Topic :: Utilities +Classifier: License :: OSI Approved :: BSD License +Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: 3.9 +Classifier: Programming Language :: Python :: 3.10 +Classifier: Programming Language :: Python :: 3.11 +Classifier: Programming Language :: Python :: 3.12 +License-File: LICENSE.txt +Requires-Dist: pycryptodomex>=3.15.0 +Requires-Dist: pyOpenSSL>=22.0.0 +Dynamic: author +Dynamic: author-email +Dynamic: classifier +Dynamic: home-page +Dynamic: keywords +Dynamic: license +Dynamic: license-file +Dynamic: requires-dist +Dynamic: summary diff --git a/venv/Lib/site-packages/python_alipay_sdk-3.4.0.dist-info/RECORD b/venv/Lib/site-packages/python_alipay_sdk-3.4.0.dist-info/RECORD new file mode 100644 index 0000000..965d2a9 --- /dev/null +++ b/venv/Lib/site-packages/python_alipay_sdk-3.4.0.dist-info/RECORD @@ -0,0 +1,17 @@ +alipay/__init__.py,sha256=6AriJs2YvTa2bE_qfszYFQYgPWHvJ-YuQwd_N1D8UxA,31268 +alipay/__pycache__/__init__.cpython-312.pyc,, +alipay/__pycache__/compat.cpython-312.pyc,, +alipay/__pycache__/exceptions.cpython-312.pyc,, +alipay/__pycache__/loggers.cpython-312.pyc,, +alipay/__pycache__/utils.cpython-312.pyc,, +alipay/compat.py,sha256=D4I6I7uejJs3hjypeiBakdDVJ-t0XJHZkn8rl7xZ7TI,190 +alipay/exceptions.py,sha256=pcu5PToseMnlOvu6P-XzvrYvhq1B2MHFleikvGvMDRE,497 +alipay/loggers.py,sha256=U4ItVNJGQaShLxt1tn51a4aKACnQf1CMQyILE7azZiI,569 +alipay/utils.py,sha256=rH0z58ukjKmrkH4TWfdNIBGBm8I0f3RP7ZT4Zi-59e4,132 +python_alipay_sdk-3.4.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +python_alipay_sdk-3.4.0.dist-info/METADATA,sha256=NSbcOcEAoH2Q7r-iPq3qI7Rh0LMie7TbKSmRiWPvwIA,940 +python_alipay_sdk-3.4.0.dist-info/RECORD,, +python_alipay_sdk-3.4.0.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +python_alipay_sdk-3.4.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91 +python_alipay_sdk-3.4.0.dist-info/licenses/LICENSE.txt,sha256=fpHbUJbKz5mGiVE-8S1WnxcqjGFyBbtmLvKiM-90Zp0,1516 +python_alipay_sdk-3.4.0.dist-info/top_level.txt,sha256=THvOefV9I4KmLDWymGOXqqQ0md2aRPLfwgfXzFZHomk,7 diff --git a/venv/Lib/site-packages/python_alipay_sdk-3.4.0.dist-info/REQUESTED b/venv/Lib/site-packages/python_alipay_sdk-3.4.0.dist-info/REQUESTED new file mode 100644 index 0000000..e69de29 diff --git a/venv/Lib/site-packages/python_alipay_sdk-3.4.0.dist-info/WHEEL b/venv/Lib/site-packages/python_alipay_sdk-3.4.0.dist-info/WHEEL new file mode 100644 index 0000000..e7fa31b --- /dev/null +++ b/venv/Lib/site-packages/python_alipay_sdk-3.4.0.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: setuptools (80.9.0) +Root-Is-Purelib: true +Tag: py3-none-any + diff --git a/venv/Lib/site-packages/python_alipay_sdk-3.4.0.dist-info/licenses/LICENSE.txt b/venv/Lib/site-packages/python_alipay_sdk-3.4.0.dist-info/licenses/LICENSE.txt new file mode 100644 index 0000000..d869962 --- /dev/null +++ b/venv/Lib/site-packages/python_alipay_sdk-3.4.0.dist-info/licenses/LICENSE.txt @@ -0,0 +1,26 @@ +Copyright (c) 2017, fzleee@gmail.com +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +The views and conclusions contained in the software and documentation are those +of the authors and should not be interpreted as representing official policies, +either expressed or implied, of the FreeBSD Project. diff --git a/venv/Lib/site-packages/python_alipay_sdk-3.4.0.dist-info/top_level.txt b/venv/Lib/site-packages/python_alipay_sdk-3.4.0.dist-info/top_level.txt new file mode 100644 index 0000000..bd7e47c --- /dev/null +++ b/venv/Lib/site-packages/python_alipay_sdk-3.4.0.dist-info/top_level.txt @@ -0,0 +1 @@ +alipay diff --git a/venv/Lib/site-packages/python_dateutil-2.9.0.post0.dist-info/RECORD b/venv/Lib/site-packages/python_dateutil-2.9.0.post0.dist-info/RECORD index 3cff967..5560c33 100644 --- a/venv/Lib/site-packages/python_dateutil-2.9.0.post0.dist-info/RECORD +++ b/venv/Lib/site-packages/python_dateutil-2.9.0.post0.dist-info/RECORD @@ -39,6 +39,7 @@ python_dateutil-2.9.0.post0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7V python_dateutil-2.9.0.post0.dist-info/LICENSE,sha256=ugD1Gg2SgjtaHN4n2LW50jIeZ-2NqbwWPv-W1eF-V34,2889 python_dateutil-2.9.0.post0.dist-info/METADATA,sha256=qdQ22jIr6AgzL5jYgyWZjofLaTpniplp_rTPrXKabpM,8354 python_dateutil-2.9.0.post0.dist-info/RECORD,, +python_dateutil-2.9.0.post0.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 python_dateutil-2.9.0.post0.dist-info/WHEEL,sha256=-G_t0oGuE7UD0DrSpVZnq1hHMBV9DD2XkS5v7XpmTnk,110 python_dateutil-2.9.0.post0.dist-info/top_level.txt,sha256=4tjdWkhRZvF7LA_BYe_L9gB2w_p2a-z5y6ArjaRkot8,9 python_dateutil-2.9.0.post0.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1 diff --git a/venv/Lib/site-packages/python_dateutil-2.9.0.post0.dist-info/REQUESTED b/venv/Lib/site-packages/python_dateutil-2.9.0.post0.dist-info/REQUESTED new file mode 100644 index 0000000..e69de29 diff --git a/venv/Lib/site-packages/redis/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/redis/__pycache__/__init__.cpython-312.pyc index 791d2c5..7a7889f 100644 Binary files a/venv/Lib/site-packages/redis/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/redis/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/redis/__pycache__/background.cpython-312.pyc b/venv/Lib/site-packages/redis/__pycache__/background.cpython-312.pyc index 04f4dd3..882a99d 100644 Binary files a/venv/Lib/site-packages/redis/__pycache__/background.cpython-312.pyc and b/venv/Lib/site-packages/redis/__pycache__/background.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/redis/__pycache__/backoff.cpython-312.pyc b/venv/Lib/site-packages/redis/__pycache__/backoff.cpython-312.pyc index 44a8afb..3d69480 100644 Binary files a/venv/Lib/site-packages/redis/__pycache__/backoff.cpython-312.pyc and b/venv/Lib/site-packages/redis/__pycache__/backoff.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/redis/__pycache__/cache.cpython-312.pyc b/venv/Lib/site-packages/redis/__pycache__/cache.cpython-312.pyc index 8c43840..bf2725c 100644 Binary files a/venv/Lib/site-packages/redis/__pycache__/cache.cpython-312.pyc and b/venv/Lib/site-packages/redis/__pycache__/cache.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/redis/__pycache__/client.cpython-312.pyc b/venv/Lib/site-packages/redis/__pycache__/client.cpython-312.pyc index f905a75..4266028 100644 Binary files a/venv/Lib/site-packages/redis/__pycache__/client.cpython-312.pyc and b/venv/Lib/site-packages/redis/__pycache__/client.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/redis/__pycache__/cluster.cpython-312.pyc b/venv/Lib/site-packages/redis/__pycache__/cluster.cpython-312.pyc index 035673f..d51f8ec 100644 Binary files a/venv/Lib/site-packages/redis/__pycache__/cluster.cpython-312.pyc and b/venv/Lib/site-packages/redis/__pycache__/cluster.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/redis/__pycache__/connection.cpython-312.pyc b/venv/Lib/site-packages/redis/__pycache__/connection.cpython-312.pyc index 5584e8d..83d8dc0 100644 Binary files a/venv/Lib/site-packages/redis/__pycache__/connection.cpython-312.pyc and b/venv/Lib/site-packages/redis/__pycache__/connection.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/redis/__pycache__/crc.cpython-312.pyc b/venv/Lib/site-packages/redis/__pycache__/crc.cpython-312.pyc index 6e6bd89..7ede285 100644 Binary files a/venv/Lib/site-packages/redis/__pycache__/crc.cpython-312.pyc and b/venv/Lib/site-packages/redis/__pycache__/crc.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/redis/__pycache__/credentials.cpython-312.pyc b/venv/Lib/site-packages/redis/__pycache__/credentials.cpython-312.pyc index 1cd3536..56c126b 100644 Binary files a/venv/Lib/site-packages/redis/__pycache__/credentials.cpython-312.pyc and b/venv/Lib/site-packages/redis/__pycache__/credentials.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/redis/__pycache__/data_structure.cpython-312.pyc b/venv/Lib/site-packages/redis/__pycache__/data_structure.cpython-312.pyc index 82f75f8..d0d6378 100644 Binary files a/venv/Lib/site-packages/redis/__pycache__/data_structure.cpython-312.pyc and b/venv/Lib/site-packages/redis/__pycache__/data_structure.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/redis/__pycache__/event.cpython-312.pyc b/venv/Lib/site-packages/redis/__pycache__/event.cpython-312.pyc index d8c58c2..4294428 100644 Binary files a/venv/Lib/site-packages/redis/__pycache__/event.cpython-312.pyc and b/venv/Lib/site-packages/redis/__pycache__/event.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/redis/__pycache__/exceptions.cpython-312.pyc b/venv/Lib/site-packages/redis/__pycache__/exceptions.cpython-312.pyc index 0432b05..4803f70 100644 Binary files a/venv/Lib/site-packages/redis/__pycache__/exceptions.cpython-312.pyc and b/venv/Lib/site-packages/redis/__pycache__/exceptions.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/redis/__pycache__/lock.cpython-312.pyc b/venv/Lib/site-packages/redis/__pycache__/lock.cpython-312.pyc index 22a1238..da4f7f9 100644 Binary files a/venv/Lib/site-packages/redis/__pycache__/lock.cpython-312.pyc and b/venv/Lib/site-packages/redis/__pycache__/lock.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/redis/__pycache__/maint_notifications.cpython-312.pyc b/venv/Lib/site-packages/redis/__pycache__/maint_notifications.cpython-312.pyc index bd1fdb7..f6a358e 100644 Binary files a/venv/Lib/site-packages/redis/__pycache__/maint_notifications.cpython-312.pyc and b/venv/Lib/site-packages/redis/__pycache__/maint_notifications.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/redis/__pycache__/ocsp.cpython-312.pyc b/venv/Lib/site-packages/redis/__pycache__/ocsp.cpython-312.pyc index 30016bf..17e4689 100644 Binary files a/venv/Lib/site-packages/redis/__pycache__/ocsp.cpython-312.pyc and b/venv/Lib/site-packages/redis/__pycache__/ocsp.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/redis/__pycache__/retry.cpython-312.pyc b/venv/Lib/site-packages/redis/__pycache__/retry.cpython-312.pyc index edafad9..c093fee 100644 Binary files a/venv/Lib/site-packages/redis/__pycache__/retry.cpython-312.pyc and b/venv/Lib/site-packages/redis/__pycache__/retry.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/redis/__pycache__/sentinel.cpython-312.pyc b/venv/Lib/site-packages/redis/__pycache__/sentinel.cpython-312.pyc index bc29a62..fcceed2 100644 Binary files a/venv/Lib/site-packages/redis/__pycache__/sentinel.cpython-312.pyc and b/venv/Lib/site-packages/redis/__pycache__/sentinel.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/redis/__pycache__/typing.cpython-312.pyc b/venv/Lib/site-packages/redis/__pycache__/typing.cpython-312.pyc index 2c0178c..a8e5b09 100644 Binary files a/venv/Lib/site-packages/redis/__pycache__/typing.cpython-312.pyc and b/venv/Lib/site-packages/redis/__pycache__/typing.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/redis/__pycache__/utils.cpython-312.pyc b/venv/Lib/site-packages/redis/__pycache__/utils.cpython-312.pyc index 68ab538..24b463c 100644 Binary files a/venv/Lib/site-packages/redis/__pycache__/utils.cpython-312.pyc and b/venv/Lib/site-packages/redis/__pycache__/utils.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/redis/_parsers/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/redis/_parsers/__pycache__/__init__.cpython-312.pyc index bec85b3..c5a45c4 100644 Binary files a/venv/Lib/site-packages/redis/_parsers/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/redis/_parsers/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/redis/_parsers/__pycache__/base.cpython-312.pyc b/venv/Lib/site-packages/redis/_parsers/__pycache__/base.cpython-312.pyc index ea0df1c..8064513 100644 Binary files a/venv/Lib/site-packages/redis/_parsers/__pycache__/base.cpython-312.pyc and b/venv/Lib/site-packages/redis/_parsers/__pycache__/base.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/redis/_parsers/__pycache__/commands.cpython-312.pyc b/venv/Lib/site-packages/redis/_parsers/__pycache__/commands.cpython-312.pyc index 241f5df..8797d0f 100644 Binary files a/venv/Lib/site-packages/redis/_parsers/__pycache__/commands.cpython-312.pyc and b/venv/Lib/site-packages/redis/_parsers/__pycache__/commands.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/redis/_parsers/__pycache__/encoders.cpython-312.pyc b/venv/Lib/site-packages/redis/_parsers/__pycache__/encoders.cpython-312.pyc index 1ef0424..77b2513 100644 Binary files a/venv/Lib/site-packages/redis/_parsers/__pycache__/encoders.cpython-312.pyc and b/venv/Lib/site-packages/redis/_parsers/__pycache__/encoders.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/redis/_parsers/__pycache__/helpers.cpython-312.pyc b/venv/Lib/site-packages/redis/_parsers/__pycache__/helpers.cpython-312.pyc index f9e94db..c8b31b7 100644 Binary files a/venv/Lib/site-packages/redis/_parsers/__pycache__/helpers.cpython-312.pyc and b/venv/Lib/site-packages/redis/_parsers/__pycache__/helpers.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/redis/_parsers/__pycache__/hiredis.cpython-312.pyc b/venv/Lib/site-packages/redis/_parsers/__pycache__/hiredis.cpython-312.pyc index e267f0b..12a3b64 100644 Binary files a/venv/Lib/site-packages/redis/_parsers/__pycache__/hiredis.cpython-312.pyc and b/venv/Lib/site-packages/redis/_parsers/__pycache__/hiredis.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/redis/_parsers/__pycache__/resp2.cpython-312.pyc b/venv/Lib/site-packages/redis/_parsers/__pycache__/resp2.cpython-312.pyc index d344884..18fd1fa 100644 Binary files a/venv/Lib/site-packages/redis/_parsers/__pycache__/resp2.cpython-312.pyc and b/venv/Lib/site-packages/redis/_parsers/__pycache__/resp2.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/redis/_parsers/__pycache__/resp3.cpython-312.pyc b/venv/Lib/site-packages/redis/_parsers/__pycache__/resp3.cpython-312.pyc index afb9a8c..4050582 100644 Binary files a/venv/Lib/site-packages/redis/_parsers/__pycache__/resp3.cpython-312.pyc and b/venv/Lib/site-packages/redis/_parsers/__pycache__/resp3.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/redis/_parsers/__pycache__/socket.cpython-312.pyc b/venv/Lib/site-packages/redis/_parsers/__pycache__/socket.cpython-312.pyc index baf671a..bdd6669 100644 Binary files a/venv/Lib/site-packages/redis/_parsers/__pycache__/socket.cpython-312.pyc and b/venv/Lib/site-packages/redis/_parsers/__pycache__/socket.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/redis/asyncio/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/redis/asyncio/__pycache__/__init__.cpython-312.pyc index 38cc884..3faa611 100644 Binary files a/venv/Lib/site-packages/redis/asyncio/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/redis/asyncio/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/redis/asyncio/__pycache__/client.cpython-312.pyc b/venv/Lib/site-packages/redis/asyncio/__pycache__/client.cpython-312.pyc index a38f1db..9f05111 100644 Binary files a/venv/Lib/site-packages/redis/asyncio/__pycache__/client.cpython-312.pyc and b/venv/Lib/site-packages/redis/asyncio/__pycache__/client.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/redis/asyncio/__pycache__/cluster.cpython-312.pyc b/venv/Lib/site-packages/redis/asyncio/__pycache__/cluster.cpython-312.pyc index b58e36e..a58a1d7 100644 Binary files a/venv/Lib/site-packages/redis/asyncio/__pycache__/cluster.cpython-312.pyc and b/venv/Lib/site-packages/redis/asyncio/__pycache__/cluster.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/redis/asyncio/__pycache__/connection.cpython-312.pyc b/venv/Lib/site-packages/redis/asyncio/__pycache__/connection.cpython-312.pyc index f0c5648..47de61c 100644 Binary files a/venv/Lib/site-packages/redis/asyncio/__pycache__/connection.cpython-312.pyc and b/venv/Lib/site-packages/redis/asyncio/__pycache__/connection.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/redis/asyncio/__pycache__/lock.cpython-312.pyc b/venv/Lib/site-packages/redis/asyncio/__pycache__/lock.cpython-312.pyc index acf450e..719106b 100644 Binary files a/venv/Lib/site-packages/redis/asyncio/__pycache__/lock.cpython-312.pyc and b/venv/Lib/site-packages/redis/asyncio/__pycache__/lock.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/redis/asyncio/__pycache__/retry.cpython-312.pyc b/venv/Lib/site-packages/redis/asyncio/__pycache__/retry.cpython-312.pyc index 1ce0fd8..e7f6c8e 100644 Binary files a/venv/Lib/site-packages/redis/asyncio/__pycache__/retry.cpython-312.pyc and b/venv/Lib/site-packages/redis/asyncio/__pycache__/retry.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/redis/asyncio/__pycache__/sentinel.cpython-312.pyc b/venv/Lib/site-packages/redis/asyncio/__pycache__/sentinel.cpython-312.pyc index 90287d1..c8038b3 100644 Binary files a/venv/Lib/site-packages/redis/asyncio/__pycache__/sentinel.cpython-312.pyc and b/venv/Lib/site-packages/redis/asyncio/__pycache__/sentinel.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/redis/asyncio/__pycache__/utils.cpython-312.pyc b/venv/Lib/site-packages/redis/asyncio/__pycache__/utils.cpython-312.pyc index 1ab40d3..9f0f6fa 100644 Binary files a/venv/Lib/site-packages/redis/asyncio/__pycache__/utils.cpython-312.pyc and b/venv/Lib/site-packages/redis/asyncio/__pycache__/utils.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/redis/asyncio/http/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/redis/asyncio/http/__pycache__/__init__.cpython-312.pyc index f7aa1b9..2708efa 100644 Binary files a/venv/Lib/site-packages/redis/asyncio/http/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/redis/asyncio/http/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/redis/asyncio/http/__pycache__/http_client.cpython-312.pyc b/venv/Lib/site-packages/redis/asyncio/http/__pycache__/http_client.cpython-312.pyc index 29dd374..76a291f 100644 Binary files a/venv/Lib/site-packages/redis/asyncio/http/__pycache__/http_client.cpython-312.pyc and b/venv/Lib/site-packages/redis/asyncio/http/__pycache__/http_client.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/redis/asyncio/multidb/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/redis/asyncio/multidb/__pycache__/__init__.cpython-312.pyc index cd96afd..6350396 100644 Binary files a/venv/Lib/site-packages/redis/asyncio/multidb/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/redis/asyncio/multidb/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/redis/asyncio/multidb/__pycache__/client.cpython-312.pyc b/venv/Lib/site-packages/redis/asyncio/multidb/__pycache__/client.cpython-312.pyc index 44262c1..87e8eb8 100644 Binary files a/venv/Lib/site-packages/redis/asyncio/multidb/__pycache__/client.cpython-312.pyc and b/venv/Lib/site-packages/redis/asyncio/multidb/__pycache__/client.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/redis/asyncio/multidb/__pycache__/command_executor.cpython-312.pyc b/venv/Lib/site-packages/redis/asyncio/multidb/__pycache__/command_executor.cpython-312.pyc index 58214b7..f6dbc69 100644 Binary files a/venv/Lib/site-packages/redis/asyncio/multidb/__pycache__/command_executor.cpython-312.pyc and b/venv/Lib/site-packages/redis/asyncio/multidb/__pycache__/command_executor.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/redis/asyncio/multidb/__pycache__/config.cpython-312.pyc b/venv/Lib/site-packages/redis/asyncio/multidb/__pycache__/config.cpython-312.pyc index d5dbcaa..cc1dc07 100644 Binary files a/venv/Lib/site-packages/redis/asyncio/multidb/__pycache__/config.cpython-312.pyc and b/venv/Lib/site-packages/redis/asyncio/multidb/__pycache__/config.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/redis/asyncio/multidb/__pycache__/database.cpython-312.pyc b/venv/Lib/site-packages/redis/asyncio/multidb/__pycache__/database.cpython-312.pyc index 19b0649..92f9da7 100644 Binary files a/venv/Lib/site-packages/redis/asyncio/multidb/__pycache__/database.cpython-312.pyc and b/venv/Lib/site-packages/redis/asyncio/multidb/__pycache__/database.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/redis/asyncio/multidb/__pycache__/event.cpython-312.pyc b/venv/Lib/site-packages/redis/asyncio/multidb/__pycache__/event.cpython-312.pyc index a9d6d92..a2a24fb 100644 Binary files a/venv/Lib/site-packages/redis/asyncio/multidb/__pycache__/event.cpython-312.pyc and b/venv/Lib/site-packages/redis/asyncio/multidb/__pycache__/event.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/redis/asyncio/multidb/__pycache__/failover.cpython-312.pyc b/venv/Lib/site-packages/redis/asyncio/multidb/__pycache__/failover.cpython-312.pyc index 00070c5..0717c93 100644 Binary files a/venv/Lib/site-packages/redis/asyncio/multidb/__pycache__/failover.cpython-312.pyc and b/venv/Lib/site-packages/redis/asyncio/multidb/__pycache__/failover.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/redis/asyncio/multidb/__pycache__/failure_detector.cpython-312.pyc b/venv/Lib/site-packages/redis/asyncio/multidb/__pycache__/failure_detector.cpython-312.pyc index 18d0146..22dc90c 100644 Binary files a/venv/Lib/site-packages/redis/asyncio/multidb/__pycache__/failure_detector.cpython-312.pyc and b/venv/Lib/site-packages/redis/asyncio/multidb/__pycache__/failure_detector.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/redis/asyncio/multidb/__pycache__/healthcheck.cpython-312.pyc b/venv/Lib/site-packages/redis/asyncio/multidb/__pycache__/healthcheck.cpython-312.pyc index c639f12..19678ba 100644 Binary files a/venv/Lib/site-packages/redis/asyncio/multidb/__pycache__/healthcheck.cpython-312.pyc and b/venv/Lib/site-packages/redis/asyncio/multidb/__pycache__/healthcheck.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/redis/auth/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/redis/auth/__pycache__/__init__.cpython-312.pyc index a2e7a36..9919bb4 100644 Binary files a/venv/Lib/site-packages/redis/auth/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/redis/auth/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/redis/auth/__pycache__/err.cpython-312.pyc b/venv/Lib/site-packages/redis/auth/__pycache__/err.cpython-312.pyc index a48b033..b47f478 100644 Binary files a/venv/Lib/site-packages/redis/auth/__pycache__/err.cpython-312.pyc and b/venv/Lib/site-packages/redis/auth/__pycache__/err.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/redis/auth/__pycache__/idp.cpython-312.pyc b/venv/Lib/site-packages/redis/auth/__pycache__/idp.cpython-312.pyc index 9cec1df..2eacfc8 100644 Binary files a/venv/Lib/site-packages/redis/auth/__pycache__/idp.cpython-312.pyc and b/venv/Lib/site-packages/redis/auth/__pycache__/idp.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/redis/auth/__pycache__/token.cpython-312.pyc b/venv/Lib/site-packages/redis/auth/__pycache__/token.cpython-312.pyc index 03516dd..5cd0b25 100644 Binary files a/venv/Lib/site-packages/redis/auth/__pycache__/token.cpython-312.pyc and b/venv/Lib/site-packages/redis/auth/__pycache__/token.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/redis/auth/__pycache__/token_manager.cpython-312.pyc b/venv/Lib/site-packages/redis/auth/__pycache__/token_manager.cpython-312.pyc index 2f26df6..39b1194 100644 Binary files a/venv/Lib/site-packages/redis/auth/__pycache__/token_manager.cpython-312.pyc and b/venv/Lib/site-packages/redis/auth/__pycache__/token_manager.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/redis/commands/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/redis/commands/__pycache__/__init__.cpython-312.pyc index e01bebf..f7a5f67 100644 Binary files a/venv/Lib/site-packages/redis/commands/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/redis/commands/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/redis/commands/__pycache__/cluster.cpython-312.pyc b/venv/Lib/site-packages/redis/commands/__pycache__/cluster.cpython-312.pyc index 33b96ad..39bda40 100644 Binary files a/venv/Lib/site-packages/redis/commands/__pycache__/cluster.cpython-312.pyc and b/venv/Lib/site-packages/redis/commands/__pycache__/cluster.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/redis/commands/__pycache__/core.cpython-312.pyc b/venv/Lib/site-packages/redis/commands/__pycache__/core.cpython-312.pyc index 56e4b24..ed16806 100644 Binary files a/venv/Lib/site-packages/redis/commands/__pycache__/core.cpython-312.pyc and b/venv/Lib/site-packages/redis/commands/__pycache__/core.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/redis/commands/__pycache__/helpers.cpython-312.pyc b/venv/Lib/site-packages/redis/commands/__pycache__/helpers.cpython-312.pyc index 1b5cc65..16bd3a0 100644 Binary files a/venv/Lib/site-packages/redis/commands/__pycache__/helpers.cpython-312.pyc and b/venv/Lib/site-packages/redis/commands/__pycache__/helpers.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/redis/commands/__pycache__/policies.cpython-312.pyc b/venv/Lib/site-packages/redis/commands/__pycache__/policies.cpython-312.pyc index 8f78579..26469a1 100644 Binary files a/venv/Lib/site-packages/redis/commands/__pycache__/policies.cpython-312.pyc and b/venv/Lib/site-packages/redis/commands/__pycache__/policies.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/redis/commands/__pycache__/redismodules.cpython-312.pyc b/venv/Lib/site-packages/redis/commands/__pycache__/redismodules.cpython-312.pyc index 5c7990a..802ef6f 100644 Binary files a/venv/Lib/site-packages/redis/commands/__pycache__/redismodules.cpython-312.pyc and b/venv/Lib/site-packages/redis/commands/__pycache__/redismodules.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/redis/commands/__pycache__/sentinel.cpython-312.pyc b/venv/Lib/site-packages/redis/commands/__pycache__/sentinel.cpython-312.pyc index 482f8d6..5bceecc 100644 Binary files a/venv/Lib/site-packages/redis/commands/__pycache__/sentinel.cpython-312.pyc and b/venv/Lib/site-packages/redis/commands/__pycache__/sentinel.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/redis/commands/bf/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/redis/commands/bf/__pycache__/__init__.cpython-312.pyc index 091841d..0dd1bdb 100644 Binary files a/venv/Lib/site-packages/redis/commands/bf/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/redis/commands/bf/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/redis/commands/bf/__pycache__/commands.cpython-312.pyc b/venv/Lib/site-packages/redis/commands/bf/__pycache__/commands.cpython-312.pyc index 5a6f792..2e1dab3 100644 Binary files a/venv/Lib/site-packages/redis/commands/bf/__pycache__/commands.cpython-312.pyc and b/venv/Lib/site-packages/redis/commands/bf/__pycache__/commands.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/redis/commands/bf/__pycache__/info.cpython-312.pyc b/venv/Lib/site-packages/redis/commands/bf/__pycache__/info.cpython-312.pyc index bf113ea..3de6efb 100644 Binary files a/venv/Lib/site-packages/redis/commands/bf/__pycache__/info.cpython-312.pyc and b/venv/Lib/site-packages/redis/commands/bf/__pycache__/info.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/redis/commands/json/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/redis/commands/json/__pycache__/__init__.cpython-312.pyc index 72711be..d535984 100644 Binary files a/venv/Lib/site-packages/redis/commands/json/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/redis/commands/json/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/redis/commands/json/__pycache__/_util.cpython-312.pyc b/venv/Lib/site-packages/redis/commands/json/__pycache__/_util.cpython-312.pyc index d0553d3..fa118d2 100644 Binary files a/venv/Lib/site-packages/redis/commands/json/__pycache__/_util.cpython-312.pyc and b/venv/Lib/site-packages/redis/commands/json/__pycache__/_util.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/redis/commands/json/__pycache__/commands.cpython-312.pyc b/venv/Lib/site-packages/redis/commands/json/__pycache__/commands.cpython-312.pyc index 30affdc..4fe1be4 100644 Binary files a/venv/Lib/site-packages/redis/commands/json/__pycache__/commands.cpython-312.pyc and b/venv/Lib/site-packages/redis/commands/json/__pycache__/commands.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/redis/commands/json/__pycache__/decoders.cpython-312.pyc b/venv/Lib/site-packages/redis/commands/json/__pycache__/decoders.cpython-312.pyc index 6e73c56..7b3ad18 100644 Binary files a/venv/Lib/site-packages/redis/commands/json/__pycache__/decoders.cpython-312.pyc and b/venv/Lib/site-packages/redis/commands/json/__pycache__/decoders.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/redis/commands/json/__pycache__/path.cpython-312.pyc b/venv/Lib/site-packages/redis/commands/json/__pycache__/path.cpython-312.pyc index 85e2ac8..35a3595 100644 Binary files a/venv/Lib/site-packages/redis/commands/json/__pycache__/path.cpython-312.pyc and b/venv/Lib/site-packages/redis/commands/json/__pycache__/path.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/redis/commands/search/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/redis/commands/search/__pycache__/__init__.cpython-312.pyc index c0fd762..da842b0 100644 Binary files a/venv/Lib/site-packages/redis/commands/search/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/redis/commands/search/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/redis/commands/search/__pycache__/_util.cpython-312.pyc b/venv/Lib/site-packages/redis/commands/search/__pycache__/_util.cpython-312.pyc index b5b386b..e209b83 100644 Binary files a/venv/Lib/site-packages/redis/commands/search/__pycache__/_util.cpython-312.pyc and b/venv/Lib/site-packages/redis/commands/search/__pycache__/_util.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/redis/commands/search/__pycache__/aggregation.cpython-312.pyc b/venv/Lib/site-packages/redis/commands/search/__pycache__/aggregation.cpython-312.pyc index 11e6302..24e040a 100644 Binary files a/venv/Lib/site-packages/redis/commands/search/__pycache__/aggregation.cpython-312.pyc and b/venv/Lib/site-packages/redis/commands/search/__pycache__/aggregation.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/redis/commands/search/__pycache__/commands.cpython-312.pyc b/venv/Lib/site-packages/redis/commands/search/__pycache__/commands.cpython-312.pyc index 7818539..19f6b21 100644 Binary files a/venv/Lib/site-packages/redis/commands/search/__pycache__/commands.cpython-312.pyc and b/venv/Lib/site-packages/redis/commands/search/__pycache__/commands.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/redis/commands/search/__pycache__/dialect.cpython-312.pyc b/venv/Lib/site-packages/redis/commands/search/__pycache__/dialect.cpython-312.pyc index 5a33d58..86915c4 100644 Binary files a/venv/Lib/site-packages/redis/commands/search/__pycache__/dialect.cpython-312.pyc and b/venv/Lib/site-packages/redis/commands/search/__pycache__/dialect.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/redis/commands/search/__pycache__/document.cpython-312.pyc b/venv/Lib/site-packages/redis/commands/search/__pycache__/document.cpython-312.pyc index 65d2227..ac65432 100644 Binary files a/venv/Lib/site-packages/redis/commands/search/__pycache__/document.cpython-312.pyc and b/venv/Lib/site-packages/redis/commands/search/__pycache__/document.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/redis/commands/search/__pycache__/field.cpython-312.pyc b/venv/Lib/site-packages/redis/commands/search/__pycache__/field.cpython-312.pyc index a6eb2e0..f5fe1b3 100644 Binary files a/venv/Lib/site-packages/redis/commands/search/__pycache__/field.cpython-312.pyc and b/venv/Lib/site-packages/redis/commands/search/__pycache__/field.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/redis/commands/search/__pycache__/hybrid_query.cpython-312.pyc b/venv/Lib/site-packages/redis/commands/search/__pycache__/hybrid_query.cpython-312.pyc index 7eaa991..6598132 100644 Binary files a/venv/Lib/site-packages/redis/commands/search/__pycache__/hybrid_query.cpython-312.pyc and b/venv/Lib/site-packages/redis/commands/search/__pycache__/hybrid_query.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/redis/commands/search/__pycache__/hybrid_result.cpython-312.pyc b/venv/Lib/site-packages/redis/commands/search/__pycache__/hybrid_result.cpython-312.pyc index 5d7dd84..3bf6fad 100644 Binary files a/venv/Lib/site-packages/redis/commands/search/__pycache__/hybrid_result.cpython-312.pyc and b/venv/Lib/site-packages/redis/commands/search/__pycache__/hybrid_result.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/redis/commands/search/__pycache__/index_definition.cpython-312.pyc b/venv/Lib/site-packages/redis/commands/search/__pycache__/index_definition.cpython-312.pyc index b77d2a7..2d1b095 100644 Binary files a/venv/Lib/site-packages/redis/commands/search/__pycache__/index_definition.cpython-312.pyc and b/venv/Lib/site-packages/redis/commands/search/__pycache__/index_definition.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/redis/commands/search/__pycache__/profile_information.cpython-312.pyc b/venv/Lib/site-packages/redis/commands/search/__pycache__/profile_information.cpython-312.pyc index 0fda8bf..e3a541d 100644 Binary files a/venv/Lib/site-packages/redis/commands/search/__pycache__/profile_information.cpython-312.pyc and b/venv/Lib/site-packages/redis/commands/search/__pycache__/profile_information.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/redis/commands/search/__pycache__/query.cpython-312.pyc b/venv/Lib/site-packages/redis/commands/search/__pycache__/query.cpython-312.pyc index e7f25f5..df8cce5 100644 Binary files a/venv/Lib/site-packages/redis/commands/search/__pycache__/query.cpython-312.pyc and b/venv/Lib/site-packages/redis/commands/search/__pycache__/query.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/redis/commands/search/__pycache__/querystring.cpython-312.pyc b/venv/Lib/site-packages/redis/commands/search/__pycache__/querystring.cpython-312.pyc index 6725ef9..94f8b09 100644 Binary files a/venv/Lib/site-packages/redis/commands/search/__pycache__/querystring.cpython-312.pyc and b/venv/Lib/site-packages/redis/commands/search/__pycache__/querystring.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/redis/commands/search/__pycache__/reducers.cpython-312.pyc b/venv/Lib/site-packages/redis/commands/search/__pycache__/reducers.cpython-312.pyc index a29a7a9..de432c0 100644 Binary files a/venv/Lib/site-packages/redis/commands/search/__pycache__/reducers.cpython-312.pyc and b/venv/Lib/site-packages/redis/commands/search/__pycache__/reducers.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/redis/commands/search/__pycache__/result.cpython-312.pyc b/venv/Lib/site-packages/redis/commands/search/__pycache__/result.cpython-312.pyc index 21bacf9..7e5a00b 100644 Binary files a/venv/Lib/site-packages/redis/commands/search/__pycache__/result.cpython-312.pyc and b/venv/Lib/site-packages/redis/commands/search/__pycache__/result.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/redis/commands/search/__pycache__/suggestion.cpython-312.pyc b/venv/Lib/site-packages/redis/commands/search/__pycache__/suggestion.cpython-312.pyc index 462c2ad..9170693 100644 Binary files a/venv/Lib/site-packages/redis/commands/search/__pycache__/suggestion.cpython-312.pyc and b/venv/Lib/site-packages/redis/commands/search/__pycache__/suggestion.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/redis/commands/timeseries/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/redis/commands/timeseries/__pycache__/__init__.cpython-312.pyc index fc12d0f..c995773 100644 Binary files a/venv/Lib/site-packages/redis/commands/timeseries/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/redis/commands/timeseries/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/redis/commands/timeseries/__pycache__/commands.cpython-312.pyc b/venv/Lib/site-packages/redis/commands/timeseries/__pycache__/commands.cpython-312.pyc index db06f42..0304981 100644 Binary files a/venv/Lib/site-packages/redis/commands/timeseries/__pycache__/commands.cpython-312.pyc and b/venv/Lib/site-packages/redis/commands/timeseries/__pycache__/commands.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/redis/commands/timeseries/__pycache__/info.cpython-312.pyc b/venv/Lib/site-packages/redis/commands/timeseries/__pycache__/info.cpython-312.pyc index 78fa60f..f71d06b 100644 Binary files a/venv/Lib/site-packages/redis/commands/timeseries/__pycache__/info.cpython-312.pyc and b/venv/Lib/site-packages/redis/commands/timeseries/__pycache__/info.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/redis/commands/timeseries/__pycache__/utils.cpython-312.pyc b/venv/Lib/site-packages/redis/commands/timeseries/__pycache__/utils.cpython-312.pyc index 5f32012..9eec24e 100644 Binary files a/venv/Lib/site-packages/redis/commands/timeseries/__pycache__/utils.cpython-312.pyc and b/venv/Lib/site-packages/redis/commands/timeseries/__pycache__/utils.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/redis/commands/vectorset/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/redis/commands/vectorset/__pycache__/__init__.cpython-312.pyc index d43dd68..83d0866 100644 Binary files a/venv/Lib/site-packages/redis/commands/vectorset/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/redis/commands/vectorset/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/redis/commands/vectorset/__pycache__/commands.cpython-312.pyc b/venv/Lib/site-packages/redis/commands/vectorset/__pycache__/commands.cpython-312.pyc index bdebe3d..724fdb7 100644 Binary files a/venv/Lib/site-packages/redis/commands/vectorset/__pycache__/commands.cpython-312.pyc and b/venv/Lib/site-packages/redis/commands/vectorset/__pycache__/commands.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/redis/commands/vectorset/__pycache__/utils.cpython-312.pyc b/venv/Lib/site-packages/redis/commands/vectorset/__pycache__/utils.cpython-312.pyc index a32a9a7..507a951 100644 Binary files a/venv/Lib/site-packages/redis/commands/vectorset/__pycache__/utils.cpython-312.pyc and b/venv/Lib/site-packages/redis/commands/vectorset/__pycache__/utils.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/redis/http/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/redis/http/__pycache__/__init__.cpython-312.pyc index 2e34596..b901b71 100644 Binary files a/venv/Lib/site-packages/redis/http/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/redis/http/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/redis/http/__pycache__/http_client.cpython-312.pyc b/venv/Lib/site-packages/redis/http/__pycache__/http_client.cpython-312.pyc index 4d98d0d..395bc61 100644 Binary files a/venv/Lib/site-packages/redis/http/__pycache__/http_client.cpython-312.pyc and b/venv/Lib/site-packages/redis/http/__pycache__/http_client.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/redis/multidb/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/redis/multidb/__pycache__/__init__.cpython-312.pyc index 8985c62..aee5656 100644 Binary files a/venv/Lib/site-packages/redis/multidb/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/redis/multidb/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/redis/multidb/__pycache__/circuit.cpython-312.pyc b/venv/Lib/site-packages/redis/multidb/__pycache__/circuit.cpython-312.pyc index 1d9a6ee..c75ae5f 100644 Binary files a/venv/Lib/site-packages/redis/multidb/__pycache__/circuit.cpython-312.pyc and b/venv/Lib/site-packages/redis/multidb/__pycache__/circuit.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/redis/multidb/__pycache__/client.cpython-312.pyc b/venv/Lib/site-packages/redis/multidb/__pycache__/client.cpython-312.pyc index f563896..76e8bbd 100644 Binary files a/venv/Lib/site-packages/redis/multidb/__pycache__/client.cpython-312.pyc and b/venv/Lib/site-packages/redis/multidb/__pycache__/client.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/redis/multidb/__pycache__/command_executor.cpython-312.pyc b/venv/Lib/site-packages/redis/multidb/__pycache__/command_executor.cpython-312.pyc index 40661fb..ee36a5e 100644 Binary files a/venv/Lib/site-packages/redis/multidb/__pycache__/command_executor.cpython-312.pyc and b/venv/Lib/site-packages/redis/multidb/__pycache__/command_executor.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/redis/multidb/__pycache__/config.cpython-312.pyc b/venv/Lib/site-packages/redis/multidb/__pycache__/config.cpython-312.pyc index dc2d607..58958af 100644 Binary files a/venv/Lib/site-packages/redis/multidb/__pycache__/config.cpython-312.pyc and b/venv/Lib/site-packages/redis/multidb/__pycache__/config.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/redis/multidb/__pycache__/database.cpython-312.pyc b/venv/Lib/site-packages/redis/multidb/__pycache__/database.cpython-312.pyc index f2d14cb..c50acf1 100644 Binary files a/venv/Lib/site-packages/redis/multidb/__pycache__/database.cpython-312.pyc and b/venv/Lib/site-packages/redis/multidb/__pycache__/database.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/redis/multidb/__pycache__/event.cpython-312.pyc b/venv/Lib/site-packages/redis/multidb/__pycache__/event.cpython-312.pyc index 5e1e6f0..3627735 100644 Binary files a/venv/Lib/site-packages/redis/multidb/__pycache__/event.cpython-312.pyc and b/venv/Lib/site-packages/redis/multidb/__pycache__/event.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/redis/multidb/__pycache__/exception.cpython-312.pyc b/venv/Lib/site-packages/redis/multidb/__pycache__/exception.cpython-312.pyc index b981d97..8a787d2 100644 Binary files a/venv/Lib/site-packages/redis/multidb/__pycache__/exception.cpython-312.pyc and b/venv/Lib/site-packages/redis/multidb/__pycache__/exception.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/redis/multidb/__pycache__/failover.cpython-312.pyc b/venv/Lib/site-packages/redis/multidb/__pycache__/failover.cpython-312.pyc index cfe448c..c8e2929 100644 Binary files a/venv/Lib/site-packages/redis/multidb/__pycache__/failover.cpython-312.pyc and b/venv/Lib/site-packages/redis/multidb/__pycache__/failover.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/redis/multidb/__pycache__/failure_detector.cpython-312.pyc b/venv/Lib/site-packages/redis/multidb/__pycache__/failure_detector.cpython-312.pyc index e30798a..fcc9c7a 100644 Binary files a/venv/Lib/site-packages/redis/multidb/__pycache__/failure_detector.cpython-312.pyc and b/venv/Lib/site-packages/redis/multidb/__pycache__/failure_detector.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/redis/multidb/__pycache__/healthcheck.cpython-312.pyc b/venv/Lib/site-packages/redis/multidb/__pycache__/healthcheck.cpython-312.pyc index be9f46b..94284c0 100644 Binary files a/venv/Lib/site-packages/redis/multidb/__pycache__/healthcheck.cpython-312.pyc and b/venv/Lib/site-packages/redis/multidb/__pycache__/healthcheck.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/requests/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/requests/__pycache__/__init__.cpython-312.pyc index 9377949..9d62ac1 100644 Binary files a/venv/Lib/site-packages/requests/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/requests/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/requests/__pycache__/__version__.cpython-312.pyc b/venv/Lib/site-packages/requests/__pycache__/__version__.cpython-312.pyc index df0e377..96071f5 100644 Binary files a/venv/Lib/site-packages/requests/__pycache__/__version__.cpython-312.pyc and b/venv/Lib/site-packages/requests/__pycache__/__version__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/requests/__pycache__/_internal_utils.cpython-312.pyc b/venv/Lib/site-packages/requests/__pycache__/_internal_utils.cpython-312.pyc index 4167edb..ea9218d 100644 Binary files a/venv/Lib/site-packages/requests/__pycache__/_internal_utils.cpython-312.pyc and b/venv/Lib/site-packages/requests/__pycache__/_internal_utils.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/requests/__pycache__/adapters.cpython-312.pyc b/venv/Lib/site-packages/requests/__pycache__/adapters.cpython-312.pyc index 8f4e103..1d32580 100644 Binary files a/venv/Lib/site-packages/requests/__pycache__/adapters.cpython-312.pyc and b/venv/Lib/site-packages/requests/__pycache__/adapters.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/requests/__pycache__/api.cpython-312.pyc b/venv/Lib/site-packages/requests/__pycache__/api.cpython-312.pyc index 8eeb922..128d864 100644 Binary files a/venv/Lib/site-packages/requests/__pycache__/api.cpython-312.pyc and b/venv/Lib/site-packages/requests/__pycache__/api.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/requests/__pycache__/auth.cpython-312.pyc b/venv/Lib/site-packages/requests/__pycache__/auth.cpython-312.pyc index ec3a6bb..b9a9ec6 100644 Binary files a/venv/Lib/site-packages/requests/__pycache__/auth.cpython-312.pyc and b/venv/Lib/site-packages/requests/__pycache__/auth.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/requests/__pycache__/certs.cpython-312.pyc b/venv/Lib/site-packages/requests/__pycache__/certs.cpython-312.pyc index 8198cfe..b542cd4 100644 Binary files a/venv/Lib/site-packages/requests/__pycache__/certs.cpython-312.pyc and b/venv/Lib/site-packages/requests/__pycache__/certs.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/requests/__pycache__/compat.cpython-312.pyc b/venv/Lib/site-packages/requests/__pycache__/compat.cpython-312.pyc index e1c40b8..ee35b57 100644 Binary files a/venv/Lib/site-packages/requests/__pycache__/compat.cpython-312.pyc and b/venv/Lib/site-packages/requests/__pycache__/compat.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/requests/__pycache__/cookies.cpython-312.pyc b/venv/Lib/site-packages/requests/__pycache__/cookies.cpython-312.pyc index 227051d..748cca9 100644 Binary files a/venv/Lib/site-packages/requests/__pycache__/cookies.cpython-312.pyc and b/venv/Lib/site-packages/requests/__pycache__/cookies.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/requests/__pycache__/exceptions.cpython-312.pyc b/venv/Lib/site-packages/requests/__pycache__/exceptions.cpython-312.pyc index 327830b..01c87de 100644 Binary files a/venv/Lib/site-packages/requests/__pycache__/exceptions.cpython-312.pyc and b/venv/Lib/site-packages/requests/__pycache__/exceptions.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/requests/__pycache__/help.cpython-312.pyc b/venv/Lib/site-packages/requests/__pycache__/help.cpython-312.pyc index 4564d44..fc437ec 100644 Binary files a/venv/Lib/site-packages/requests/__pycache__/help.cpython-312.pyc and b/venv/Lib/site-packages/requests/__pycache__/help.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/requests/__pycache__/hooks.cpython-312.pyc b/venv/Lib/site-packages/requests/__pycache__/hooks.cpython-312.pyc index e1b5408..827ad1b 100644 Binary files a/venv/Lib/site-packages/requests/__pycache__/hooks.cpython-312.pyc and b/venv/Lib/site-packages/requests/__pycache__/hooks.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/requests/__pycache__/models.cpython-312.pyc b/venv/Lib/site-packages/requests/__pycache__/models.cpython-312.pyc index e6d3dee..8d767d5 100644 Binary files a/venv/Lib/site-packages/requests/__pycache__/models.cpython-312.pyc and b/venv/Lib/site-packages/requests/__pycache__/models.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/requests/__pycache__/packages.cpython-312.pyc b/venv/Lib/site-packages/requests/__pycache__/packages.cpython-312.pyc index 679b341..e1b5fe7 100644 Binary files a/venv/Lib/site-packages/requests/__pycache__/packages.cpython-312.pyc and b/venv/Lib/site-packages/requests/__pycache__/packages.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/requests/__pycache__/sessions.cpython-312.pyc b/venv/Lib/site-packages/requests/__pycache__/sessions.cpython-312.pyc index fdb10cc..ed5f18a 100644 Binary files a/venv/Lib/site-packages/requests/__pycache__/sessions.cpython-312.pyc and b/venv/Lib/site-packages/requests/__pycache__/sessions.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/requests/__pycache__/status_codes.cpython-312.pyc b/venv/Lib/site-packages/requests/__pycache__/status_codes.cpython-312.pyc index e81c260..54e8963 100644 Binary files a/venv/Lib/site-packages/requests/__pycache__/status_codes.cpython-312.pyc and b/venv/Lib/site-packages/requests/__pycache__/status_codes.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/requests/__pycache__/structures.cpython-312.pyc b/venv/Lib/site-packages/requests/__pycache__/structures.cpython-312.pyc index 1721453..e6e1cc2 100644 Binary files a/venv/Lib/site-packages/requests/__pycache__/structures.cpython-312.pyc and b/venv/Lib/site-packages/requests/__pycache__/structures.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/requests/__pycache__/utils.cpython-312.pyc b/venv/Lib/site-packages/requests/__pycache__/utils.cpython-312.pyc index 2e75ed8..1804460 100644 Binary files a/venv/Lib/site-packages/requests/__pycache__/utils.cpython-312.pyc and b/venv/Lib/site-packages/requests/__pycache__/utils.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/rust/Cargo.toml b/venv/Lib/site-packages/rust/Cargo.toml deleted file mode 100644 index 9eb165a..0000000 --- a/venv/Lib/site-packages/rust/Cargo.toml +++ /dev/null @@ -1,35 +0,0 @@ -[package] -name = "cryptography-rust" -version.workspace = true -authors.workspace = true -edition.workspace = true -publish.workspace = true -rust-version.workspace = true - -[dependencies] -once_cell = "1" -cfg-if = "1" -pyo3.workspace = true -asn1.workspace = true -cryptography-cffi = { path = "cryptography-cffi" } -cryptography-keepalive = { path = "cryptography-keepalive" } -cryptography-key-parsing = { path = "cryptography-key-parsing" } -cryptography-x509 = { path = "cryptography-x509" } -cryptography-x509-verification = { path = "cryptography-x509-verification" } -cryptography-openssl = { path = "cryptography-openssl" } -pem = { version = "3", default-features = false } -openssl = "0.10.68" -openssl-sys = "0.9.104" -foreign-types-shared = "0.1" -self_cell = "1" - -[features] -extension-module = ["pyo3/extension-module"] -default = ["extension-module"] - -[lib] -name = "cryptography_rust" -crate-type = ["cdylib"] - -[lints.rust] -unexpected_cfgs = { level = "warn", check-cfg = ['cfg(CRYPTOGRAPHY_OPENSSL_300_OR_GREATER)', 'cfg(CRYPTOGRAPHY_OPENSSL_309_OR_GREATER)', 'cfg(CRYPTOGRAPHY_OPENSSL_320_OR_GREATER)', 'cfg(CRYPTOGRAPHY_IS_LIBRESSL)', 'cfg(CRYPTOGRAPHY_IS_BORINGSSL)', 'cfg(CRYPTOGRAPHY_OSSLCONF, values("OPENSSL_NO_IDEA", "OPENSSL_NO_CAST", "OPENSSL_NO_BF", "OPENSSL_NO_CAMELLIA", "OPENSSL_NO_SEED", "OPENSSL_NO_SM4"))'] } diff --git a/venv/Lib/site-packages/rust/cryptography-cffi/Cargo.toml b/venv/Lib/site-packages/rust/cryptography-cffi/Cargo.toml deleted file mode 100644 index 9408de8..0000000 --- a/venv/Lib/site-packages/rust/cryptography-cffi/Cargo.toml +++ /dev/null @@ -1,17 +0,0 @@ -[package] -name = "cryptography-cffi" -version.workspace = true -authors.workspace = true -edition.workspace = true -publish.workspace = true -rust-version.workspace = true - -[dependencies] -pyo3.workspace = true -openssl-sys = "0.9.104" - -[build-dependencies] -cc = "1.2.1" - -[lints.rust] -unexpected_cfgs = { level = "warn", check-cfg = ['cfg(python_implementation, values("CPython", "PyPy"))'] } diff --git a/venv/Lib/site-packages/rust/cryptography-keepalive/Cargo.toml b/venv/Lib/site-packages/rust/cryptography-keepalive/Cargo.toml deleted file mode 100644 index baf8d93..0000000 --- a/venv/Lib/site-packages/rust/cryptography-keepalive/Cargo.toml +++ /dev/null @@ -1,10 +0,0 @@ -[package] -name = "cryptography-keepalive" -version.workspace = true -authors.workspace = true -edition.workspace = true -publish.workspace = true -rust-version.workspace = true - -[dependencies] -pyo3.workspace = true diff --git a/venv/Lib/site-packages/rust/cryptography-key-parsing/Cargo.toml b/venv/Lib/site-packages/rust/cryptography-key-parsing/Cargo.toml deleted file mode 100644 index 9b96b73..0000000 --- a/venv/Lib/site-packages/rust/cryptography-key-parsing/Cargo.toml +++ /dev/null @@ -1,17 +0,0 @@ -[package] -name = "cryptography-key-parsing" -version.workspace = true -authors.workspace = true -edition.workspace = true -publish.workspace = true -rust-version.workspace = true - -[dependencies] -asn1.workspace = true -cfg-if = "1" -openssl = "0.10.68" -openssl-sys = "0.9.104" -cryptography-x509 = { path = "../cryptography-x509" } - -[lints.rust] -unexpected_cfgs = { level = "warn", check-cfg = ['cfg(CRYPTOGRAPHY_IS_LIBRESSL)', 'cfg(CRYPTOGRAPHY_IS_BORINGSSL)'] } diff --git a/venv/Lib/site-packages/rust/cryptography-openssl/Cargo.toml b/venv/Lib/site-packages/rust/cryptography-openssl/Cargo.toml deleted file mode 100644 index 3d4c17e..0000000 --- a/venv/Lib/site-packages/rust/cryptography-openssl/Cargo.toml +++ /dev/null @@ -1,17 +0,0 @@ -[package] -name = "cryptography-openssl" -version.workspace = true -authors.workspace = true -edition.workspace = true -publish.workspace = true -rust-version.workspace = true - -[dependencies] -cfg-if = "1" -openssl = "0.10.68" -ffi = { package = "openssl-sys", version = "0.9.101" } -foreign-types = "0.3" -foreign-types-shared = "0.1" - -[lints.rust] -unexpected_cfgs = { level = "warn", check-cfg = ['cfg(CRYPTOGRAPHY_OPENSSL_300_OR_GREATER)', 'cfg(CRYPTOGRAPHY_OPENSSL_320_OR_GREATER)', 'cfg(CRYPTOGRAPHY_IS_LIBRESSL)', 'cfg(CRYPTOGRAPHY_IS_BORINGSSL)'] } diff --git a/venv/Lib/site-packages/rust/cryptography-x509-verification/Cargo.toml b/venv/Lib/site-packages/rust/cryptography-x509-verification/Cargo.toml deleted file mode 100644 index 2cc2ff4..0000000 --- a/venv/Lib/site-packages/rust/cryptography-x509-verification/Cargo.toml +++ /dev/null @@ -1,16 +0,0 @@ -[package] -name = "cryptography-x509-verification" -version.workspace = true -authors.workspace = true -edition.workspace = true -publish.workspace = true -rust-version.workspace = true - -[dependencies] -asn1.workspace = true -cryptography-x509 = { path = "../cryptography-x509" } -cryptography-key-parsing = { path = "../cryptography-key-parsing" } -once_cell = "1" - -[dev-dependencies] -pem = { version = "3", default-features = false } diff --git a/venv/Lib/site-packages/rust/cryptography-x509/Cargo.toml b/venv/Lib/site-packages/rust/cryptography-x509/Cargo.toml deleted file mode 100644 index 03f2c26..0000000 --- a/venv/Lib/site-packages/rust/cryptography-x509/Cargo.toml +++ /dev/null @@ -1,11 +0,0 @@ -[package] -name = "cryptography-x509" -version = "0.1.0" -authors = ["The cryptography developers "] -edition = "2021" -publish = false -# This specifies the MSRV -rust-version = "1.65.0" - -[dependencies] -asn1.workspace = true diff --git a/venv/Lib/site-packages/s3transfer-0.16.0.dist-info/RECORD b/venv/Lib/site-packages/s3transfer-0.16.0.dist-info/RECORD index abb1ade..f30a2c7 100644 --- a/venv/Lib/site-packages/s3transfer-0.16.0.dist-info/RECORD +++ b/venv/Lib/site-packages/s3transfer-0.16.0.dist-info/RECORD @@ -3,6 +3,7 @@ s3transfer-0.16.0.dist-info/LICENSE.txt,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6 s3transfer-0.16.0.dist-info/METADATA,sha256=_LcTgyfAuvl8xAHWrQ4CWdqsa0V0x0RR8YJyi33P_NY,1740 s3transfer-0.16.0.dist-info/NOTICE.txt,sha256=2DVOD6f7di2nvAVKimd0oLMQ37vHgAY5PuVzoOV2ErU,83 s3transfer-0.16.0.dist-info/RECORD,, +s3transfer-0.16.0.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 s3transfer-0.16.0.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91 s3transfer-0.16.0.dist-info/top_level.txt,sha256=cT7JDso1VWzQGJXAXImnyI6JUK_Fw7zjNFsigiwIsNk,11 s3transfer/__init__.py,sha256=CXlM3vAIEKMxqikAwz6i3dW5W1Hq3U6VfyB-HgBWfbI,29558 diff --git a/venv/Lib/site-packages/s3transfer-0.16.0.dist-info/REQUESTED b/venv/Lib/site-packages/s3transfer-0.16.0.dist-info/REQUESTED new file mode 100644 index 0000000..e69de29 diff --git a/venv/Lib/site-packages/s3transfer/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/s3transfer/__pycache__/__init__.cpython-312.pyc index c59dfd8..1a324ee 100644 Binary files a/venv/Lib/site-packages/s3transfer/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/s3transfer/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/s3transfer/__pycache__/bandwidth.cpython-312.pyc b/venv/Lib/site-packages/s3transfer/__pycache__/bandwidth.cpython-312.pyc index d504d9f..b1fdd29 100644 Binary files a/venv/Lib/site-packages/s3transfer/__pycache__/bandwidth.cpython-312.pyc and b/venv/Lib/site-packages/s3transfer/__pycache__/bandwidth.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/s3transfer/__pycache__/compat.cpython-312.pyc b/venv/Lib/site-packages/s3transfer/__pycache__/compat.cpython-312.pyc index 5230335..8dc20df 100644 Binary files a/venv/Lib/site-packages/s3transfer/__pycache__/compat.cpython-312.pyc and b/venv/Lib/site-packages/s3transfer/__pycache__/compat.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/s3transfer/__pycache__/constants.cpython-312.pyc b/venv/Lib/site-packages/s3transfer/__pycache__/constants.cpython-312.pyc index 5120536..cab509a 100644 Binary files a/venv/Lib/site-packages/s3transfer/__pycache__/constants.cpython-312.pyc and b/venv/Lib/site-packages/s3transfer/__pycache__/constants.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/s3transfer/__pycache__/copies.cpython-312.pyc b/venv/Lib/site-packages/s3transfer/__pycache__/copies.cpython-312.pyc index 8d4754b..4379474 100644 Binary files a/venv/Lib/site-packages/s3transfer/__pycache__/copies.cpython-312.pyc and b/venv/Lib/site-packages/s3transfer/__pycache__/copies.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/s3transfer/__pycache__/crt.cpython-312.pyc b/venv/Lib/site-packages/s3transfer/__pycache__/crt.cpython-312.pyc index b0c6960..f45c0bc 100644 Binary files a/venv/Lib/site-packages/s3transfer/__pycache__/crt.cpython-312.pyc and b/venv/Lib/site-packages/s3transfer/__pycache__/crt.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/s3transfer/__pycache__/delete.cpython-312.pyc b/venv/Lib/site-packages/s3transfer/__pycache__/delete.cpython-312.pyc index 6b21554..c71f7cd 100644 Binary files a/venv/Lib/site-packages/s3transfer/__pycache__/delete.cpython-312.pyc and b/venv/Lib/site-packages/s3transfer/__pycache__/delete.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/s3transfer/__pycache__/download.cpython-312.pyc b/venv/Lib/site-packages/s3transfer/__pycache__/download.cpython-312.pyc index 09e00fb..9eb9d7d 100644 Binary files a/venv/Lib/site-packages/s3transfer/__pycache__/download.cpython-312.pyc and b/venv/Lib/site-packages/s3transfer/__pycache__/download.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/s3transfer/__pycache__/exceptions.cpython-312.pyc b/venv/Lib/site-packages/s3transfer/__pycache__/exceptions.cpython-312.pyc index c7f7d73..95e9533 100644 Binary files a/venv/Lib/site-packages/s3transfer/__pycache__/exceptions.cpython-312.pyc and b/venv/Lib/site-packages/s3transfer/__pycache__/exceptions.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/s3transfer/__pycache__/futures.cpython-312.pyc b/venv/Lib/site-packages/s3transfer/__pycache__/futures.cpython-312.pyc index 8de3f10..fdf0020 100644 Binary files a/venv/Lib/site-packages/s3transfer/__pycache__/futures.cpython-312.pyc and b/venv/Lib/site-packages/s3transfer/__pycache__/futures.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/s3transfer/__pycache__/manager.cpython-312.pyc b/venv/Lib/site-packages/s3transfer/__pycache__/manager.cpython-312.pyc index 31ee18e..7d6794c 100644 Binary files a/venv/Lib/site-packages/s3transfer/__pycache__/manager.cpython-312.pyc and b/venv/Lib/site-packages/s3transfer/__pycache__/manager.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/s3transfer/__pycache__/processpool.cpython-312.pyc b/venv/Lib/site-packages/s3transfer/__pycache__/processpool.cpython-312.pyc index 5efaee9..be1855a 100644 Binary files a/venv/Lib/site-packages/s3transfer/__pycache__/processpool.cpython-312.pyc and b/venv/Lib/site-packages/s3transfer/__pycache__/processpool.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/s3transfer/__pycache__/subscribers.cpython-312.pyc b/venv/Lib/site-packages/s3transfer/__pycache__/subscribers.cpython-312.pyc index 5e0e85d..e3482d1 100644 Binary files a/venv/Lib/site-packages/s3transfer/__pycache__/subscribers.cpython-312.pyc and b/venv/Lib/site-packages/s3transfer/__pycache__/subscribers.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/s3transfer/__pycache__/tasks.cpython-312.pyc b/venv/Lib/site-packages/s3transfer/__pycache__/tasks.cpython-312.pyc index 1290d66..efec35d 100644 Binary files a/venv/Lib/site-packages/s3transfer/__pycache__/tasks.cpython-312.pyc and b/venv/Lib/site-packages/s3transfer/__pycache__/tasks.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/s3transfer/__pycache__/upload.cpython-312.pyc b/venv/Lib/site-packages/s3transfer/__pycache__/upload.cpython-312.pyc index 882d74a..d0daeb0 100644 Binary files a/venv/Lib/site-packages/s3transfer/__pycache__/upload.cpython-312.pyc and b/venv/Lib/site-packages/s3transfer/__pycache__/upload.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/s3transfer/__pycache__/utils.cpython-312.pyc b/venv/Lib/site-packages/s3transfer/__pycache__/utils.cpython-312.pyc index bb37682..8d19b81 100644 Binary files a/venv/Lib/site-packages/s3transfer/__pycache__/utils.cpython-312.pyc and b/venv/Lib/site-packages/s3transfer/__pycache__/utils.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/six-1.17.0.dist-info/RECORD b/venv/Lib/site-packages/six-1.17.0.dist-info/RECORD index 4b6617d..3ce5a49 100644 --- a/venv/Lib/site-packages/six-1.17.0.dist-info/RECORD +++ b/venv/Lib/site-packages/six-1.17.0.dist-info/RECORD @@ -3,6 +3,7 @@ six-1.17.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQ six-1.17.0.dist-info/LICENSE,sha256=Q3W6IOK5xsTnytKUCmKP2Q6VzD1Q7pKq51VxXYuh-9A,1066 six-1.17.0.dist-info/METADATA,sha256=ViBCB4wnUlSfbYp8htvF3XCAiKe-bYBnLsewcQC3JGg,1658 six-1.17.0.dist-info/RECORD,, +six-1.17.0.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 six-1.17.0.dist-info/WHEEL,sha256=pxeNX5JdtCe58PUSYP9upmc7jdRPgvT0Gm9kb1SHlVw,109 six-1.17.0.dist-info/top_level.txt,sha256=_iVH_iYEtEXnD8nYGQYpYFUvkUW9sEO1GYbkeKSAais,4 six.py,sha256=xRyR9wPT1LNpbJI8tf7CE-BeddkhU5O--sfy-mo5BN8,34703 diff --git a/venv/Lib/site-packages/six-1.17.0.dist-info/REQUESTED b/venv/Lib/site-packages/six-1.17.0.dist-info/REQUESTED new file mode 100644 index 0000000..e69de29 diff --git a/venv/Lib/site-packages/sqlalchemy-2.0.45.dist-info/RECORD b/venv/Lib/site-packages/sqlalchemy-2.0.45.dist-info/RECORD index 78cf9c0..7edac4d 100644 --- a/venv/Lib/site-packages/sqlalchemy-2.0.45.dist-info/RECORD +++ b/venv/Lib/site-packages/sqlalchemy-2.0.45.dist-info/RECORD @@ -1,6 +1,7 @@ sqlalchemy-2.0.45.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 sqlalchemy-2.0.45.dist-info/METADATA,sha256=YO_6jksv3MyLjQLwMaF2g1ryAOZmUGU0mSzyDiX8SaU,9790 sqlalchemy-2.0.45.dist-info/RECORD,, +sqlalchemy-2.0.45.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 sqlalchemy-2.0.45.dist-info/WHEEL,sha256=8UP9x9puWI0P1V_d7K2oMTBqfeLNm21CTzZ_Ptr0NXU,101 sqlalchemy-2.0.45.dist-info/licenses/LICENSE,sha256=EaDEEc4Kj89UgMeGJS1_hW8v_-Ozo7Z1Vsc0AX892Ko,1119 sqlalchemy-2.0.45.dist-info/top_level.txt,sha256=rp-ZgB7D8G11ivXON5VGPjupT1voYmWqkciDt5Uaw_Q,11 diff --git a/venv/Lib/site-packages/sqlalchemy-2.0.45.dist-info/REQUESTED b/venv/Lib/site-packages/sqlalchemy-2.0.45.dist-info/REQUESTED new file mode 100644 index 0000000..e69de29 diff --git a/venv/Lib/site-packages/sqlalchemy/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/__pycache__/__init__.cpython-312.pyc index 5204dad..31a7c07 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/__pycache__/events.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/__pycache__/events.cpython-312.pyc index bddaa9a..5181fd0 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/__pycache__/events.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/__pycache__/events.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/__pycache__/exc.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/__pycache__/exc.cpython-312.pyc index 1d211ad..8edffe2 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/__pycache__/exc.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/__pycache__/exc.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/__pycache__/inspection.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/__pycache__/inspection.cpython-312.pyc index 27b8aa7..9230104 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/__pycache__/inspection.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/__pycache__/inspection.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/__pycache__/log.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/__pycache__/log.cpython-312.pyc index 20afab7..4cca8c6 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/__pycache__/log.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/__pycache__/log.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/__pycache__/schema.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/__pycache__/schema.cpython-312.pyc index 3cbc124..e243458 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/__pycache__/schema.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/__pycache__/schema.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/__pycache__/types.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/__pycache__/types.cpython-312.pyc index f8007ce..e7a5ed8 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/__pycache__/types.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/__pycache__/types.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/connectors/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/connectors/__pycache__/__init__.cpython-312.pyc index 2e592bf..aac9ee6 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/connectors/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/connectors/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/connectors/__pycache__/aioodbc.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/connectors/__pycache__/aioodbc.cpython-312.pyc index c3fd6d7..20151ff 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/connectors/__pycache__/aioodbc.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/connectors/__pycache__/aioodbc.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/connectors/__pycache__/asyncio.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/connectors/__pycache__/asyncio.cpython-312.pyc index 2c8b283..30d6616 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/connectors/__pycache__/asyncio.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/connectors/__pycache__/asyncio.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/connectors/__pycache__/pyodbc.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/connectors/__pycache__/pyodbc.cpython-312.pyc index 8e26845..dfd6e54 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/connectors/__pycache__/pyodbc.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/connectors/__pycache__/pyodbc.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/cyextension/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/cyextension/__pycache__/__init__.cpython-312.pyc index 6f48273..6f52703 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/cyextension/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/cyextension/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/__pycache__/__init__.cpython-312.pyc index 125c888..be69477 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/__pycache__/_typing.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/__pycache__/_typing.cpython-312.pyc index 2467ae4..3529ae4 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/__pycache__/_typing.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/__pycache__/_typing.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/mssql/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/mssql/__pycache__/__init__.cpython-312.pyc index dda2773..17673e7 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/mssql/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/mssql/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/mssql/__pycache__/aioodbc.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/mssql/__pycache__/aioodbc.cpython-312.pyc index 5b5653d..6c5d821 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/mssql/__pycache__/aioodbc.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/mssql/__pycache__/aioodbc.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/mssql/__pycache__/base.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/mssql/__pycache__/base.cpython-312.pyc index 9f470af..ac2dfdc 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/mssql/__pycache__/base.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/mssql/__pycache__/base.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/mssql/__pycache__/information_schema.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/mssql/__pycache__/information_schema.cpython-312.pyc index b13ad8f..72b2182 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/mssql/__pycache__/information_schema.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/mssql/__pycache__/information_schema.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/mssql/__pycache__/json.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/mssql/__pycache__/json.cpython-312.pyc index c28f672..21f8fce 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/mssql/__pycache__/json.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/mssql/__pycache__/json.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/mssql/__pycache__/provision.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/mssql/__pycache__/provision.cpython-312.pyc index fe2534c..455316a 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/mssql/__pycache__/provision.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/mssql/__pycache__/provision.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/mssql/__pycache__/pymssql.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/mssql/__pycache__/pymssql.cpython-312.pyc index 1e8ddad..3936939 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/mssql/__pycache__/pymssql.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/mssql/__pycache__/pymssql.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/mssql/__pycache__/pyodbc.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/mssql/__pycache__/pyodbc.cpython-312.pyc index aec7e50..520838f 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/mssql/__pycache__/pyodbc.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/mssql/__pycache__/pyodbc.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/__init__.cpython-312.pyc index c1c57d5..0f164a9 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/aiomysql.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/aiomysql.cpython-312.pyc index 151f443..c97734a 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/aiomysql.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/aiomysql.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/asyncmy.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/asyncmy.cpython-312.pyc index 70c6225..61e2308 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/asyncmy.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/asyncmy.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/base.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/base.cpython-312.pyc index ce89ef1..ea374f3 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/base.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/base.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/cymysql.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/cymysql.cpython-312.pyc index 39e7cc1..1a9ec6f 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/cymysql.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/cymysql.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/dml.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/dml.cpython-312.pyc index a3fe742..8265568 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/dml.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/dml.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/enumerated.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/enumerated.cpython-312.pyc index 74a6284..5cdd56d 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/enumerated.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/enumerated.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/expression.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/expression.cpython-312.pyc index 8f0e764..8d6a21b 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/expression.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/expression.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/json.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/json.cpython-312.pyc index d80da65..6b620c6 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/json.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/json.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/mariadb.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/mariadb.cpython-312.pyc index 7316bd8..52f29be 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/mariadb.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/mariadb.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/mariadbconnector.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/mariadbconnector.cpython-312.pyc index 6267bf8..a83ed7d 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/mariadbconnector.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/mariadbconnector.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/mysqlconnector.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/mysqlconnector.cpython-312.pyc index 1f90f05..0b3d891 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/mysqlconnector.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/mysqlconnector.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/mysqldb.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/mysqldb.cpython-312.pyc index 49d5ba6..ea375ce 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/mysqldb.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/mysqldb.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/provision.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/provision.cpython-312.pyc index ad79a78..7475b39 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/provision.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/provision.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/pymysql.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/pymysql.cpython-312.pyc index e021176..31b5a87 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/pymysql.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/pymysql.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/pyodbc.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/pyodbc.cpython-312.pyc index f3e453f..a146bc5 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/pyodbc.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/pyodbc.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/reflection.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/reflection.cpython-312.pyc index c031e61..a736079 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/reflection.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/reflection.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/reserved_words.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/reserved_words.cpython-312.pyc index 43f758a..ef14300 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/reserved_words.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/reserved_words.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/types.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/types.cpython-312.pyc index 2d0dac4..e7ce630 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/types.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/mysql/__pycache__/types.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/oracle/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/oracle/__pycache__/__init__.cpython-312.pyc index a12f460..2232db4 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/oracle/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/oracle/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/oracle/__pycache__/base.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/oracle/__pycache__/base.cpython-312.pyc index 5f18c5a..70c6c6a 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/oracle/__pycache__/base.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/oracle/__pycache__/base.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/oracle/__pycache__/cx_oracle.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/oracle/__pycache__/cx_oracle.cpython-312.pyc index 177ec07..51d7123 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/oracle/__pycache__/cx_oracle.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/oracle/__pycache__/cx_oracle.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/oracle/__pycache__/dictionary.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/oracle/__pycache__/dictionary.cpython-312.pyc index 526e8a6..7979ce9 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/oracle/__pycache__/dictionary.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/oracle/__pycache__/dictionary.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/oracle/__pycache__/oracledb.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/oracle/__pycache__/oracledb.cpython-312.pyc index ebd7bba..8332143 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/oracle/__pycache__/oracledb.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/oracle/__pycache__/oracledb.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/oracle/__pycache__/provision.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/oracle/__pycache__/provision.cpython-312.pyc index d4bef77..00a0762 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/oracle/__pycache__/provision.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/oracle/__pycache__/provision.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/oracle/__pycache__/types.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/oracle/__pycache__/types.cpython-312.pyc index b8410b7..51e1ba6 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/oracle/__pycache__/types.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/oracle/__pycache__/types.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/oracle/__pycache__/vector.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/oracle/__pycache__/vector.cpython-312.pyc index 42a0f9b..ee51b13 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/oracle/__pycache__/vector.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/oracle/__pycache__/vector.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/__init__.cpython-312.pyc index 0657b4d..c4f002c 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/_psycopg_common.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/_psycopg_common.cpython-312.pyc index 3664ba5..c3a9611 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/_psycopg_common.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/_psycopg_common.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/array.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/array.cpython-312.pyc index f19ffe6..54981f3 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/array.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/array.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/asyncpg.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/asyncpg.cpython-312.pyc index ca65191..535b354 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/asyncpg.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/asyncpg.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/base.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/base.cpython-312.pyc index d29a80d..362d389 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/base.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/base.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/dml.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/dml.cpython-312.pyc index d0daafa..ca97136 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/dml.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/dml.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/ext.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/ext.cpython-312.pyc index 79e6506..e6db937 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/ext.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/ext.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/hstore.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/hstore.cpython-312.pyc index acd92da..d8e4c31 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/hstore.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/hstore.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/json.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/json.cpython-312.pyc index 862e725..a78ed6a 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/json.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/json.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/named_types.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/named_types.cpython-312.pyc index f4141e7..c236daa 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/named_types.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/named_types.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/operators.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/operators.cpython-312.pyc index 49b5861..daf6eef 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/operators.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/operators.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/pg8000.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/pg8000.cpython-312.pyc index 9e5826e..aa9434d 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/pg8000.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/pg8000.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/pg_catalog.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/pg_catalog.cpython-312.pyc index d9987cf..e04ad33 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/pg_catalog.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/pg_catalog.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/provision.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/provision.cpython-312.pyc index e5139d8..b7f1438 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/provision.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/provision.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/psycopg.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/psycopg.cpython-312.pyc index f2dbeee..bd51c3a 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/psycopg.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/psycopg.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/psycopg2.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/psycopg2.cpython-312.pyc index a619a63..74f131e 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/psycopg2.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/psycopg2.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/psycopg2cffi.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/psycopg2cffi.cpython-312.pyc index 1ae7c9f..1f64649 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/psycopg2cffi.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/psycopg2cffi.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/ranges.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/ranges.cpython-312.pyc index c8555f1..260c218 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/ranges.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/ranges.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/types.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/types.cpython-312.pyc index bf7717e..a850e1f 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/types.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/postgresql/__pycache__/types.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/sqlite/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/sqlite/__pycache__/__init__.cpython-312.pyc index 92535bb..33d1c41 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/sqlite/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/sqlite/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/sqlite/__pycache__/aiosqlite.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/sqlite/__pycache__/aiosqlite.cpython-312.pyc index 73638a3..4f859df 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/sqlite/__pycache__/aiosqlite.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/sqlite/__pycache__/aiosqlite.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/sqlite/__pycache__/base.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/sqlite/__pycache__/base.cpython-312.pyc index 5922699..2673490 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/sqlite/__pycache__/base.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/sqlite/__pycache__/base.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/sqlite/__pycache__/dml.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/sqlite/__pycache__/dml.cpython-312.pyc index da02ef4..aab39ef 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/sqlite/__pycache__/dml.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/sqlite/__pycache__/dml.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/sqlite/__pycache__/json.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/sqlite/__pycache__/json.cpython-312.pyc index 93fe7f0..5d7f5bd 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/sqlite/__pycache__/json.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/sqlite/__pycache__/json.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/sqlite/__pycache__/provision.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/sqlite/__pycache__/provision.cpython-312.pyc index 033e71e..c9cd82e 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/sqlite/__pycache__/provision.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/sqlite/__pycache__/provision.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/sqlite/__pycache__/pysqlcipher.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/sqlite/__pycache__/pysqlcipher.cpython-312.pyc index f4384a6..3412123 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/sqlite/__pycache__/pysqlcipher.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/sqlite/__pycache__/pysqlcipher.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/dialects/sqlite/__pycache__/pysqlite.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/dialects/sqlite/__pycache__/pysqlite.cpython-312.pyc index cbbd29e..60bdd43 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/dialects/sqlite/__pycache__/pysqlite.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/dialects/sqlite/__pycache__/pysqlite.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/__init__.cpython-312.pyc index 5aa5672..abfc338 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/_py_processors.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/_py_processors.cpython-312.pyc index d9d8dde..64848fa 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/_py_processors.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/_py_processors.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/_py_row.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/_py_row.cpython-312.pyc index 6877173..62f9d2f 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/_py_row.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/_py_row.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/_py_util.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/_py_util.cpython-312.pyc index 4458805..5a46d50 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/_py_util.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/_py_util.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/base.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/base.cpython-312.pyc index e6baf02..d701117 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/base.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/base.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/characteristics.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/characteristics.cpython-312.pyc index 5d56eb3..805dea5 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/characteristics.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/characteristics.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/create.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/create.cpython-312.pyc index f77c4d1..49d1e85 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/create.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/create.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/cursor.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/cursor.cpython-312.pyc index e4f9b21..056be8c 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/cursor.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/cursor.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/default.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/default.cpython-312.pyc index fd3345e..7841dc7 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/default.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/default.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/events.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/events.cpython-312.pyc index ce6866a..8203888 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/events.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/events.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/interfaces.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/interfaces.cpython-312.pyc index 3972ab6..dfc058e 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/interfaces.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/interfaces.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/mock.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/mock.cpython-312.pyc index cde1ece..403aa1a 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/mock.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/mock.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/processors.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/processors.cpython-312.pyc index 2f476ab..0d0209f 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/processors.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/processors.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/reflection.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/reflection.cpython-312.pyc index 245f6a0..caadd26 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/reflection.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/reflection.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/result.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/result.cpython-312.pyc index 20f2106..2ca80a7 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/result.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/result.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/row.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/row.cpython-312.pyc index ebdf03c..3a09c6d 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/row.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/row.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/strategies.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/strategies.cpython-312.pyc index 20bf8a5..e54e974 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/strategies.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/strategies.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/url.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/url.cpython-312.pyc index ee6501a..2e99017 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/url.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/url.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/util.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/util.cpython-312.pyc index 5b2c0ac..4f8fab3 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/util.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/engine/__pycache__/util.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/event/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/event/__pycache__/__init__.cpython-312.pyc index 8591939..101a9c5 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/event/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/event/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/event/__pycache__/api.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/event/__pycache__/api.cpython-312.pyc index 9b78b0c..2a7c280 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/event/__pycache__/api.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/event/__pycache__/api.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/event/__pycache__/attr.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/event/__pycache__/attr.cpython-312.pyc index 0223f3d..9bb6209 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/event/__pycache__/attr.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/event/__pycache__/attr.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/event/__pycache__/base.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/event/__pycache__/base.cpython-312.pyc index 0d7d9da..b12635f 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/event/__pycache__/base.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/event/__pycache__/base.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/event/__pycache__/legacy.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/event/__pycache__/legacy.cpython-312.pyc index 90f3a2b..e9b4961 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/event/__pycache__/legacy.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/event/__pycache__/legacy.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/event/__pycache__/registry.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/event/__pycache__/registry.cpython-312.pyc index dec38e5..72d416a 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/event/__pycache__/registry.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/event/__pycache__/registry.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/ext/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/ext/__pycache__/__init__.cpython-312.pyc index 4b386d5..c910b93 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/ext/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/ext/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/ext/__pycache__/associationproxy.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/ext/__pycache__/associationproxy.cpython-312.pyc index 94c5b82..99eb5c1 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/ext/__pycache__/associationproxy.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/ext/__pycache__/associationproxy.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/ext/__pycache__/automap.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/ext/__pycache__/automap.cpython-312.pyc index ac3194c..0f4bb21 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/ext/__pycache__/automap.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/ext/__pycache__/automap.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/ext/__pycache__/baked.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/ext/__pycache__/baked.cpython-312.pyc index 7675917..2bd20d7 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/ext/__pycache__/baked.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/ext/__pycache__/baked.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/ext/__pycache__/compiler.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/ext/__pycache__/compiler.cpython-312.pyc index a05e1a0..4819dc8 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/ext/__pycache__/compiler.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/ext/__pycache__/compiler.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/ext/__pycache__/horizontal_shard.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/ext/__pycache__/horizontal_shard.cpython-312.pyc index d1fac64..6eaba78 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/ext/__pycache__/horizontal_shard.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/ext/__pycache__/horizontal_shard.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/ext/__pycache__/hybrid.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/ext/__pycache__/hybrid.cpython-312.pyc index f7175e4..ff7ac09 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/ext/__pycache__/hybrid.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/ext/__pycache__/hybrid.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/ext/__pycache__/indexable.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/ext/__pycache__/indexable.cpython-312.pyc index 260b0f3..8c279f8 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/ext/__pycache__/indexable.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/ext/__pycache__/indexable.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/ext/__pycache__/instrumentation.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/ext/__pycache__/instrumentation.cpython-312.pyc index aaf2190..03cadf9 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/ext/__pycache__/instrumentation.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/ext/__pycache__/instrumentation.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/ext/__pycache__/mutable.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/ext/__pycache__/mutable.cpython-312.pyc index 38296f0..832be20 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/ext/__pycache__/mutable.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/ext/__pycache__/mutable.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/ext/__pycache__/orderinglist.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/ext/__pycache__/orderinglist.cpython-312.pyc index fa80d37..ad1b71b 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/ext/__pycache__/orderinglist.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/ext/__pycache__/orderinglist.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/ext/__pycache__/serializer.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/ext/__pycache__/serializer.cpython-312.pyc index 76cb68e..89f0657 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/ext/__pycache__/serializer.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/ext/__pycache__/serializer.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/ext/asyncio/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/ext/asyncio/__pycache__/__init__.cpython-312.pyc index fdfd099..16195e6 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/ext/asyncio/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/ext/asyncio/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/ext/asyncio/__pycache__/base.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/ext/asyncio/__pycache__/base.cpython-312.pyc index 981e753..5b6c2e3 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/ext/asyncio/__pycache__/base.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/ext/asyncio/__pycache__/base.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/ext/asyncio/__pycache__/engine.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/ext/asyncio/__pycache__/engine.cpython-312.pyc index de2a17b..fd451bb 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/ext/asyncio/__pycache__/engine.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/ext/asyncio/__pycache__/engine.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/ext/asyncio/__pycache__/exc.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/ext/asyncio/__pycache__/exc.cpython-312.pyc index 42f98f8..819c88a 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/ext/asyncio/__pycache__/exc.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/ext/asyncio/__pycache__/exc.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/ext/asyncio/__pycache__/result.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/ext/asyncio/__pycache__/result.cpython-312.pyc index 0504097..69ce336 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/ext/asyncio/__pycache__/result.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/ext/asyncio/__pycache__/result.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/ext/asyncio/__pycache__/scoping.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/ext/asyncio/__pycache__/scoping.cpython-312.pyc index 99905fc..9f77151 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/ext/asyncio/__pycache__/scoping.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/ext/asyncio/__pycache__/scoping.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/ext/asyncio/__pycache__/session.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/ext/asyncio/__pycache__/session.cpython-312.pyc index eb0490f..fbe2b7a 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/ext/asyncio/__pycache__/session.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/ext/asyncio/__pycache__/session.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/ext/declarative/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/ext/declarative/__pycache__/__init__.cpython-312.pyc index bf45b29..5b866ea 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/ext/declarative/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/ext/declarative/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/ext/declarative/__pycache__/extensions.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/ext/declarative/__pycache__/extensions.cpython-312.pyc index a9925d7..fda82d3 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/ext/declarative/__pycache__/extensions.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/ext/declarative/__pycache__/extensions.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/ext/mypy/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/ext/mypy/__pycache__/__init__.cpython-312.pyc index 17407bf..c170baa 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/ext/mypy/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/ext/mypy/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/ext/mypy/__pycache__/apply.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/ext/mypy/__pycache__/apply.cpython-312.pyc index 9965cc4..8b394eb 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/ext/mypy/__pycache__/apply.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/ext/mypy/__pycache__/apply.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/ext/mypy/__pycache__/decl_class.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/ext/mypy/__pycache__/decl_class.cpython-312.pyc index 6bf2bb5..5881c64 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/ext/mypy/__pycache__/decl_class.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/ext/mypy/__pycache__/decl_class.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/ext/mypy/__pycache__/infer.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/ext/mypy/__pycache__/infer.cpython-312.pyc index 64c42ff..3f3704e 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/ext/mypy/__pycache__/infer.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/ext/mypy/__pycache__/infer.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/ext/mypy/__pycache__/names.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/ext/mypy/__pycache__/names.cpython-312.pyc index 3eca80a..6f4a30c 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/ext/mypy/__pycache__/names.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/ext/mypy/__pycache__/names.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/ext/mypy/__pycache__/plugin.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/ext/mypy/__pycache__/plugin.cpython-312.pyc index ed7f472..c25627f 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/ext/mypy/__pycache__/plugin.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/ext/mypy/__pycache__/plugin.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/ext/mypy/__pycache__/util.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/ext/mypy/__pycache__/util.cpython-312.pyc index f92e8fd..8f0b299 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/ext/mypy/__pycache__/util.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/ext/mypy/__pycache__/util.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/future/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/future/__pycache__/__init__.cpython-312.pyc index 05b2533..10887b7 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/future/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/future/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/future/__pycache__/engine.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/future/__pycache__/engine.cpython-312.pyc index 41db880..0136646 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/future/__pycache__/engine.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/future/__pycache__/engine.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/__init__.cpython-312.pyc index afd2ccf..1da4517 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/_orm_constructors.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/_orm_constructors.cpython-312.pyc index 062b86e..dad14f3 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/_orm_constructors.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/_orm_constructors.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/_typing.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/_typing.cpython-312.pyc index 64647ff..dd87d0a 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/_typing.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/_typing.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/attributes.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/attributes.cpython-312.pyc index ff57f0d..86824ea 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/attributes.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/attributes.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/base.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/base.cpython-312.pyc index 14f8a1d..f2a89be 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/base.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/base.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/bulk_persistence.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/bulk_persistence.cpython-312.pyc index 51707fb..cddb9da 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/bulk_persistence.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/bulk_persistence.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/clsregistry.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/clsregistry.cpython-312.pyc index 1608fbb..5413e7f 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/clsregistry.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/clsregistry.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/collections.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/collections.cpython-312.pyc index 9e6ffd9..80cea3f 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/collections.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/collections.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/context.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/context.cpython-312.pyc index 34ae55b..83e5fc4 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/context.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/context.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/decl_api.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/decl_api.cpython-312.pyc index 0be02f1..3ee0830 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/decl_api.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/decl_api.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/decl_base.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/decl_base.cpython-312.pyc index 239598d..0db0187 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/decl_base.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/decl_base.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/dependency.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/dependency.cpython-312.pyc index ad1103f..5d8b3c3 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/dependency.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/dependency.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/descriptor_props.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/descriptor_props.cpython-312.pyc index 4223973..5223e24 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/descriptor_props.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/descriptor_props.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/dynamic.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/dynamic.cpython-312.pyc index 42661c0..960badf 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/dynamic.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/dynamic.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/evaluator.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/evaluator.cpython-312.pyc index f58657e..c6c4648 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/evaluator.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/evaluator.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/events.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/events.cpython-312.pyc index 92ad21a..58bcdd4 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/events.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/events.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/exc.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/exc.cpython-312.pyc index 1c7601c..a614230 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/exc.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/exc.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/identity.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/identity.cpython-312.pyc index b6d436f..6af897c 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/identity.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/identity.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/instrumentation.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/instrumentation.cpython-312.pyc index e55d480..e52ac09 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/instrumentation.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/instrumentation.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/interfaces.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/interfaces.cpython-312.pyc index 3378ecc..812cabc 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/interfaces.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/interfaces.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/loading.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/loading.cpython-312.pyc index be87102..1b74304 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/loading.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/loading.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/mapped_collection.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/mapped_collection.cpython-312.pyc index 1fb50d3..adef070 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/mapped_collection.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/mapped_collection.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/mapper.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/mapper.cpython-312.pyc index 3623713..6290781 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/mapper.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/mapper.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/path_registry.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/path_registry.cpython-312.pyc index 1a7ae3e..a3f0e09 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/path_registry.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/path_registry.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/persistence.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/persistence.cpython-312.pyc index 3f41a37..7d9a95b 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/persistence.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/persistence.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/properties.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/properties.cpython-312.pyc index c699a3a..4441f08 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/properties.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/properties.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/query.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/query.cpython-312.pyc index 2d48cbf..287dca7 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/query.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/query.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/relationships.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/relationships.cpython-312.pyc index ea81204..d05a381 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/relationships.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/relationships.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/scoping.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/scoping.cpython-312.pyc index dae698e..94674d7 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/scoping.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/scoping.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/session.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/session.cpython-312.pyc index 78f22b1..09b7a7b 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/session.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/session.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/state.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/state.cpython-312.pyc index e786ad2..eb5f8f6 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/state.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/state.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/state_changes.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/state_changes.cpython-312.pyc index f889e72..7257184 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/state_changes.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/state_changes.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/strategies.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/strategies.cpython-312.pyc index 2f69279..1d4480d 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/strategies.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/strategies.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/strategy_options.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/strategy_options.cpython-312.pyc index ff8cc39..112fc40 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/strategy_options.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/strategy_options.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/sync.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/sync.cpython-312.pyc index 5b7e085..1f6ec2f 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/sync.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/sync.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/unitofwork.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/unitofwork.cpython-312.pyc index 1b44a6a..7cace82 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/unitofwork.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/unitofwork.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/util.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/util.cpython-312.pyc index ece5549..485fef5 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/util.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/util.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/writeonly.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/writeonly.cpython-312.pyc index 72dbd04..a66bd2e 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/writeonly.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/orm/__pycache__/writeonly.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/pool/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/pool/__pycache__/__init__.cpython-312.pyc index 9643b1d..b002e61 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/pool/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/pool/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/pool/__pycache__/base.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/pool/__pycache__/base.cpython-312.pyc index 74d73f8..f38b60a 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/pool/__pycache__/base.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/pool/__pycache__/base.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/pool/__pycache__/events.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/pool/__pycache__/events.cpython-312.pyc index 56b1872..5195bbf 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/pool/__pycache__/events.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/pool/__pycache__/events.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/pool/__pycache__/impl.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/pool/__pycache__/impl.cpython-312.pyc index 50e502f..07adec9 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/pool/__pycache__/impl.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/pool/__pycache__/impl.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/__init__.cpython-312.pyc index f4abaea..bc939df 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/_dml_constructors.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/_dml_constructors.cpython-312.pyc index 7c9b503..fbf91cc 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/_dml_constructors.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/_dml_constructors.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/_elements_constructors.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/_elements_constructors.cpython-312.pyc index 3549e5b..cd83ba8 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/_elements_constructors.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/_elements_constructors.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/_orm_types.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/_orm_types.cpython-312.pyc index 58d2367..bdd22d2 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/_orm_types.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/_orm_types.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/_py_util.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/_py_util.cpython-312.pyc index 6ef0460..d7e75ad 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/_py_util.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/_py_util.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/_selectable_constructors.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/_selectable_constructors.cpython-312.pyc index 83c7e0d..681ee50 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/_selectable_constructors.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/_selectable_constructors.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/_typing.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/_typing.cpython-312.pyc index 357a220..f87067d 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/_typing.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/_typing.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/annotation.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/annotation.cpython-312.pyc index fc8e75f..990f625 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/annotation.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/annotation.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/base.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/base.cpython-312.pyc index bd16f5d..68f87ab 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/base.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/base.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/cache_key.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/cache_key.cpython-312.pyc index 05a05eb..c5d5372 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/cache_key.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/cache_key.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/coercions.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/coercions.cpython-312.pyc index 858e689..6ac3f23 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/coercions.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/coercions.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/compiler.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/compiler.cpython-312.pyc index 377c64b..900cc7b 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/compiler.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/compiler.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/crud.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/crud.cpython-312.pyc index 89e2f06..aee0dd5 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/crud.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/crud.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/ddl.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/ddl.cpython-312.pyc index 5e9501d..fedd567 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/ddl.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/ddl.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/default_comparator.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/default_comparator.cpython-312.pyc index 3fd2523..264baac 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/default_comparator.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/default_comparator.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/dml.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/dml.cpython-312.pyc index a0a97cd..09a0322 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/dml.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/dml.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/elements.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/elements.cpython-312.pyc index 14f1951..d88f99d 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/elements.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/elements.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/events.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/events.cpython-312.pyc index 22a5175..c765574 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/events.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/events.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/expression.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/expression.cpython-312.pyc index 0c80e9c..0cefadc 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/expression.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/expression.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/functions.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/functions.cpython-312.pyc index c90d7bd..0703138 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/functions.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/functions.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/lambdas.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/lambdas.cpython-312.pyc index aa00e20..b555dea 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/lambdas.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/lambdas.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/naming.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/naming.cpython-312.pyc index 2981ef2..b52d7ca 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/naming.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/naming.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/operators.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/operators.cpython-312.pyc index f7368f4..f10b38b 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/operators.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/operators.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/roles.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/roles.cpython-312.pyc index 6108e5b..676ad34 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/roles.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/roles.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/schema.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/schema.cpython-312.pyc index 19b7cc9..9387813 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/schema.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/schema.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/selectable.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/selectable.cpython-312.pyc index 63e35f9..e4af93f 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/selectable.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/selectable.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/sqltypes.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/sqltypes.cpython-312.pyc index 7ce4142..2ddf013 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/sqltypes.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/sqltypes.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/traversals.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/traversals.cpython-312.pyc index fb8e39b..e6ec2b9 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/traversals.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/traversals.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/type_api.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/type_api.cpython-312.pyc index 686649c..fa97388 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/type_api.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/type_api.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/util.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/util.cpython-312.pyc index 5146e69..731cb58 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/util.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/util.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/visitors.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/visitors.cpython-312.pyc index b07f53e..7e54cde 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/visitors.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/sql/__pycache__/visitors.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/__init__.cpython-312.pyc index 2870138..12f8b23 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/assertions.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/assertions.cpython-312.pyc index 048de23..bb81edb 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/assertions.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/assertions.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/assertsql.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/assertsql.cpython-312.pyc index 2dde096..8caac2b 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/assertsql.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/assertsql.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/asyncio.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/asyncio.cpython-312.pyc index 3a9fc87..574e651 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/asyncio.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/asyncio.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/config.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/config.cpython-312.pyc index 3187b4b..93cac87 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/config.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/config.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/engines.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/engines.cpython-312.pyc index 123a38b..e4eb920 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/engines.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/engines.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/entities.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/entities.cpython-312.pyc index f718e5e..44400b4 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/entities.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/entities.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/exclusions.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/exclusions.cpython-312.pyc index f067ac9..d58d769 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/exclusions.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/exclusions.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/pickleable.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/pickleable.cpython-312.pyc index 6b007db..5061295 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/pickleable.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/pickleable.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/profiling.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/profiling.cpython-312.pyc index 0f16ab6..32f4a51 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/profiling.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/profiling.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/provision.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/provision.cpython-312.pyc index ee14e7d..7b0c952 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/provision.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/provision.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/requirements.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/requirements.cpython-312.pyc index ecaff98..6fa3b44 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/requirements.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/requirements.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/schema.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/schema.cpython-312.pyc index cf73a29..b896689 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/schema.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/schema.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/util.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/util.cpython-312.pyc index efbeb79..2728b0c 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/util.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/util.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/warnings.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/warnings.cpython-312.pyc index 041f7f0..53d4856 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/warnings.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/testing/__pycache__/warnings.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/testing/fixtures/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/testing/fixtures/__pycache__/__init__.cpython-312.pyc index bfb9538..96998c7 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/testing/fixtures/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/testing/fixtures/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/testing/fixtures/__pycache__/base.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/testing/fixtures/__pycache__/base.cpython-312.pyc index a6b0eb8..f6b6a52 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/testing/fixtures/__pycache__/base.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/testing/fixtures/__pycache__/base.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/testing/fixtures/__pycache__/mypy.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/testing/fixtures/__pycache__/mypy.cpython-312.pyc index 336e3b2..30ce966 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/testing/fixtures/__pycache__/mypy.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/testing/fixtures/__pycache__/mypy.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/testing/fixtures/__pycache__/orm.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/testing/fixtures/__pycache__/orm.cpython-312.pyc index f022480..3ac10d8 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/testing/fixtures/__pycache__/orm.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/testing/fixtures/__pycache__/orm.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/testing/fixtures/__pycache__/sql.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/testing/fixtures/__pycache__/sql.cpython-312.pyc index e68c914..1c54c2c 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/testing/fixtures/__pycache__/sql.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/testing/fixtures/__pycache__/sql.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/testing/plugin/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/testing/plugin/__pycache__/__init__.cpython-312.pyc index 857821d..09bf3a3 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/testing/plugin/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/testing/plugin/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/testing/plugin/__pycache__/bootstrap.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/testing/plugin/__pycache__/bootstrap.cpython-312.pyc index cc7efa4..7866a7c 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/testing/plugin/__pycache__/bootstrap.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/testing/plugin/__pycache__/bootstrap.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/testing/plugin/__pycache__/plugin_base.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/testing/plugin/__pycache__/plugin_base.cpython-312.pyc index b8b0090..87325f4 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/testing/plugin/__pycache__/plugin_base.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/testing/plugin/__pycache__/plugin_base.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/testing/plugin/__pycache__/pytestplugin.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/testing/plugin/__pycache__/pytestplugin.cpython-312.pyc index 342bb00..470882a 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/testing/plugin/__pycache__/pytestplugin.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/testing/plugin/__pycache__/pytestplugin.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/__init__.cpython-312.pyc index 6f6802d..dfe074a 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_cte.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_cte.cpython-312.pyc index c5b791b..493f55d 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_cte.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_cte.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_ddl.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_ddl.cpython-312.pyc index 3229d76..1c09f1a 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_ddl.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_ddl.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_deprecations.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_deprecations.cpython-312.pyc index b3c95b5..6f55328 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_deprecations.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_deprecations.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_dialect.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_dialect.cpython-312.pyc index c09aa58..0a4d671 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_dialect.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_dialect.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_insert.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_insert.cpython-312.pyc index 47100b4..8fa3e6e 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_insert.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_insert.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_reflection.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_reflection.cpython-312.pyc index ff94536..ea40f7e 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_reflection.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_reflection.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_results.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_results.cpython-312.pyc index 4b58c57..44e9ab4 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_results.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_results.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_rowcount.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_rowcount.cpython-312.pyc index bba3185..a6c4e9a 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_rowcount.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_rowcount.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_select.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_select.cpython-312.pyc index de8bbc0..d33207e 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_select.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_select.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_sequence.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_sequence.cpython-312.pyc index 8c73b0c..c08b3cd 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_sequence.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_sequence.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_types.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_types.cpython-312.pyc index 6e05201..f67b536 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_types.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_types.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_unicode_ddl.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_unicode_ddl.cpython-312.pyc index 922992b..667a405 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_unicode_ddl.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_unicode_ddl.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_update_delete.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_update_delete.cpython-312.pyc index c76a937..9f91ab2 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_update_delete.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/testing/suite/__pycache__/test_update_delete.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/util/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/util/__pycache__/__init__.cpython-312.pyc index a1acae0..00b6ed1 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/util/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/util/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/util/__pycache__/_collections.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/util/__pycache__/_collections.cpython-312.pyc index eb02f41..3e0d392 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/util/__pycache__/_collections.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/util/__pycache__/_collections.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/util/__pycache__/_concurrency_py3k.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/util/__pycache__/_concurrency_py3k.cpython-312.pyc index f9705fd..9d12d27 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/util/__pycache__/_concurrency_py3k.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/util/__pycache__/_concurrency_py3k.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/util/__pycache__/_has_cy.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/util/__pycache__/_has_cy.cpython-312.pyc index be09753..8db2d7a 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/util/__pycache__/_has_cy.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/util/__pycache__/_has_cy.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/util/__pycache__/_py_collections.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/util/__pycache__/_py_collections.cpython-312.pyc index 90c9d64..afe244a 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/util/__pycache__/_py_collections.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/util/__pycache__/_py_collections.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/util/__pycache__/compat.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/util/__pycache__/compat.cpython-312.pyc index f8814e5..05e67a6 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/util/__pycache__/compat.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/util/__pycache__/compat.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/util/__pycache__/concurrency.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/util/__pycache__/concurrency.cpython-312.pyc index 14c262c..77335c3 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/util/__pycache__/concurrency.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/util/__pycache__/concurrency.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/util/__pycache__/deprecations.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/util/__pycache__/deprecations.cpython-312.pyc index c8444a7..034ca34 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/util/__pycache__/deprecations.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/util/__pycache__/deprecations.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/util/__pycache__/langhelpers.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/util/__pycache__/langhelpers.cpython-312.pyc index f618e6a..fa563d6 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/util/__pycache__/langhelpers.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/util/__pycache__/langhelpers.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/util/__pycache__/preloaded.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/util/__pycache__/preloaded.cpython-312.pyc index 135784a..c7593f5 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/util/__pycache__/preloaded.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/util/__pycache__/preloaded.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/util/__pycache__/queue.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/util/__pycache__/queue.cpython-312.pyc index 67371d8..e72153e 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/util/__pycache__/queue.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/util/__pycache__/queue.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/util/__pycache__/tool_support.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/util/__pycache__/tool_support.cpython-312.pyc index 5092514..e94f4f5 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/util/__pycache__/tool_support.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/util/__pycache__/tool_support.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/util/__pycache__/topological.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/util/__pycache__/topological.cpython-312.pyc index 14a8f48..48005e7 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/util/__pycache__/topological.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/util/__pycache__/topological.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/sqlalchemy/util/__pycache__/typing.cpython-312.pyc b/venv/Lib/site-packages/sqlalchemy/util/__pycache__/typing.cpython-312.pyc index 46e8154..e2721e2 100644 Binary files a/venv/Lib/site-packages/sqlalchemy/util/__pycache__/typing.cpython-312.pyc and b/venv/Lib/site-packages/sqlalchemy/util/__pycache__/typing.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/test/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/test/__pycache__/__init__.cpython-312.pyc index 73b83f6..be8440e 100644 Binary files a/venv/Lib/site-packages/test/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/test/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/test/integration/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/test/integration/__pycache__/__init__.cpython-312.pyc index df3fef9..b5c4c4a 100644 Binary files a/venv/Lib/site-packages/test/integration/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/test/integration/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/test/integration/__pycache__/test_client.cpython-312.pyc b/venv/Lib/site-packages/test/integration/__pycache__/test_client.cpython-312.pyc index 6bf6e2a..9e01a8d 100644 Binary files a/venv/Lib/site-packages/test/integration/__pycache__/test_client.cpython-312.pyc and b/venv/Lib/site-packages/test/integration/__pycache__/test_client.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/test/unit/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/test/unit/__pycache__/__init__.cpython-312.pyc index a12eebf..a05d22e 100644 Binary files a/venv/Lib/site-packages/test/unit/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/test/unit/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/test/unit/__pycache__/test_client.cpython-312.pyc b/venv/Lib/site-packages/test/unit/__pycache__/test_client.cpython-312.pyc index ccd15e2..4f3da65 100644 Binary files a/venv/Lib/site-packages/test/unit/__pycache__/test_client.cpython-312.pyc and b/venv/Lib/site-packages/test/unit/__pycache__/test_client.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/typing_extensions-4.15.0.dist-info/RECORD b/venv/Lib/site-packages/typing_extensions-4.15.0.dist-info/RECORD index 5cbf8e7..e8e06e6 100644 --- a/venv/Lib/site-packages/typing_extensions-4.15.0.dist-info/RECORD +++ b/venv/Lib/site-packages/typing_extensions-4.15.0.dist-info/RECORD @@ -2,6 +2,7 @@ __pycache__/typing_extensions.cpython-312.pyc,, typing_extensions-4.15.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 typing_extensions-4.15.0.dist-info/METADATA,sha256=wTg3j-jxiTSsmd4GBTXFPsbBOu7WXpTDJkHafuMZKnI,3259 typing_extensions-4.15.0.dist-info/RECORD,, +typing_extensions-4.15.0.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 typing_extensions-4.15.0.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82 typing_extensions-4.15.0.dist-info/licenses/LICENSE,sha256=Oy-B_iHRgcSZxZolbI4ZaEVdZonSaaqFNzv7avQdo78,13936 typing_extensions.py,sha256=Qz0R0XDTok0usGXrwb_oSM6n49fOaFZ6tSvqLUwvftg,160429 diff --git a/venv/Lib/site-packages/typing_extensions-4.15.0.dist-info/REQUESTED b/venv/Lib/site-packages/typing_extensions-4.15.0.dist-info/REQUESTED new file mode 100644 index 0000000..e69de29 diff --git a/venv/Lib/site-packages/tzdata-2025.3.dist-info/RECORD b/venv/Lib/site-packages/tzdata-2025.3.dist-info/RECORD index 3cf5ef5..e56cbe1 100644 --- a/venv/Lib/site-packages/tzdata-2025.3.dist-info/RECORD +++ b/venv/Lib/site-packages/tzdata-2025.3.dist-info/RECORD @@ -1,6 +1,7 @@ tzdata-2025.3.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 tzdata-2025.3.dist-info/METADATA,sha256=QiXXu1WSsgB_Zls4Yk6T263TZBP7_PPB-nzYCuewh_g,1352 tzdata-2025.3.dist-info/RECORD,, +tzdata-2025.3.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 tzdata-2025.3.dist-info/WHEEL,sha256=JNWh1Fm1UdwIQV075glCn4MVuCRs0sotJIq-J6rbxCU,109 tzdata-2025.3.dist-info/licenses/LICENSE,sha256=M-jlAC01EtP8wigrmV5rrZ0zR4G5xawxhD9ASQDh87Q,592 tzdata-2025.3.dist-info/licenses/licenses/LICENSE_APACHE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357 diff --git a/venv/Lib/site-packages/tzdata-2025.3.dist-info/REQUESTED b/venv/Lib/site-packages/tzdata-2025.3.dist-info/REQUESTED new file mode 100644 index 0000000..e69de29 diff --git a/venv/Lib/site-packages/tzdata/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/tzdata/__pycache__/__init__.cpython-312.pyc index 74dcbfa..3e5bc47 100644 Binary files a/venv/Lib/site-packages/tzdata/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/tzdata/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/tzdata/zoneinfo/Africa/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/tzdata/zoneinfo/Africa/__pycache__/__init__.cpython-312.pyc index 4359877..464562e 100644 Binary files a/venv/Lib/site-packages/tzdata/zoneinfo/Africa/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/tzdata/zoneinfo/Africa/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/tzdata/zoneinfo/America/Argentina/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/tzdata/zoneinfo/America/Argentina/__pycache__/__init__.cpython-312.pyc index 1b502cc..9fa0e28 100644 Binary files a/venv/Lib/site-packages/tzdata/zoneinfo/America/Argentina/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/tzdata/zoneinfo/America/Argentina/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/tzdata/zoneinfo/America/Indiana/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/tzdata/zoneinfo/America/Indiana/__pycache__/__init__.cpython-312.pyc index d8462b1..3e3abc0 100644 Binary files a/venv/Lib/site-packages/tzdata/zoneinfo/America/Indiana/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/tzdata/zoneinfo/America/Indiana/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/tzdata/zoneinfo/America/Kentucky/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/tzdata/zoneinfo/America/Kentucky/__pycache__/__init__.cpython-312.pyc index d0f07e2..53185be 100644 Binary files a/venv/Lib/site-packages/tzdata/zoneinfo/America/Kentucky/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/tzdata/zoneinfo/America/Kentucky/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/tzdata/zoneinfo/America/North_Dakota/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/tzdata/zoneinfo/America/North_Dakota/__pycache__/__init__.cpython-312.pyc index 0ff4b51..51f26ae 100644 Binary files a/venv/Lib/site-packages/tzdata/zoneinfo/America/North_Dakota/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/tzdata/zoneinfo/America/North_Dakota/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/tzdata/zoneinfo/America/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/tzdata/zoneinfo/America/__pycache__/__init__.cpython-312.pyc index 077eb1d..20b0c0d 100644 Binary files a/venv/Lib/site-packages/tzdata/zoneinfo/America/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/tzdata/zoneinfo/America/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/tzdata/zoneinfo/Antarctica/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/tzdata/zoneinfo/Antarctica/__pycache__/__init__.cpython-312.pyc index b06e766..737326b 100644 Binary files a/venv/Lib/site-packages/tzdata/zoneinfo/Antarctica/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/tzdata/zoneinfo/Antarctica/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/tzdata/zoneinfo/Arctic/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/tzdata/zoneinfo/Arctic/__pycache__/__init__.cpython-312.pyc index 3ca89d3..45d0efb 100644 Binary files a/venv/Lib/site-packages/tzdata/zoneinfo/Arctic/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/tzdata/zoneinfo/Arctic/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/tzdata/zoneinfo/Asia/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/tzdata/zoneinfo/Asia/__pycache__/__init__.cpython-312.pyc index 4467d29..726017f 100644 Binary files a/venv/Lib/site-packages/tzdata/zoneinfo/Asia/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/tzdata/zoneinfo/Asia/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/tzdata/zoneinfo/Atlantic/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/tzdata/zoneinfo/Atlantic/__pycache__/__init__.cpython-312.pyc index 8b43d11..493aa81 100644 Binary files a/venv/Lib/site-packages/tzdata/zoneinfo/Atlantic/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/tzdata/zoneinfo/Atlantic/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/tzdata/zoneinfo/Australia/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/tzdata/zoneinfo/Australia/__pycache__/__init__.cpython-312.pyc index 8d0cbb4..bdaa737 100644 Binary files a/venv/Lib/site-packages/tzdata/zoneinfo/Australia/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/tzdata/zoneinfo/Australia/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/tzdata/zoneinfo/Brazil/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/tzdata/zoneinfo/Brazil/__pycache__/__init__.cpython-312.pyc index dd51220..694103c 100644 Binary files a/venv/Lib/site-packages/tzdata/zoneinfo/Brazil/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/tzdata/zoneinfo/Brazil/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/tzdata/zoneinfo/Canada/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/tzdata/zoneinfo/Canada/__pycache__/__init__.cpython-312.pyc index 678bdc0..c38f369 100644 Binary files a/venv/Lib/site-packages/tzdata/zoneinfo/Canada/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/tzdata/zoneinfo/Canada/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/tzdata/zoneinfo/Chile/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/tzdata/zoneinfo/Chile/__pycache__/__init__.cpython-312.pyc index b4e838e..a68e858 100644 Binary files a/venv/Lib/site-packages/tzdata/zoneinfo/Chile/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/tzdata/zoneinfo/Chile/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/tzdata/zoneinfo/Etc/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/tzdata/zoneinfo/Etc/__pycache__/__init__.cpython-312.pyc index 5ccd9cb..4960bf5 100644 Binary files a/venv/Lib/site-packages/tzdata/zoneinfo/Etc/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/tzdata/zoneinfo/Etc/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/tzdata/zoneinfo/Europe/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/tzdata/zoneinfo/Europe/__pycache__/__init__.cpython-312.pyc index 63eeac8..f90a519 100644 Binary files a/venv/Lib/site-packages/tzdata/zoneinfo/Europe/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/tzdata/zoneinfo/Europe/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/tzdata/zoneinfo/Indian/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/tzdata/zoneinfo/Indian/__pycache__/__init__.cpython-312.pyc index 54272d3..752b4f0 100644 Binary files a/venv/Lib/site-packages/tzdata/zoneinfo/Indian/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/tzdata/zoneinfo/Indian/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/tzdata/zoneinfo/Mexico/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/tzdata/zoneinfo/Mexico/__pycache__/__init__.cpython-312.pyc index fd8d5e6..3b4f899 100644 Binary files a/venv/Lib/site-packages/tzdata/zoneinfo/Mexico/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/tzdata/zoneinfo/Mexico/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/tzdata/zoneinfo/Pacific/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/tzdata/zoneinfo/Pacific/__pycache__/__init__.cpython-312.pyc index 7f2c3b5..ff3a07a 100644 Binary files a/venv/Lib/site-packages/tzdata/zoneinfo/Pacific/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/tzdata/zoneinfo/Pacific/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/tzdata/zoneinfo/US/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/tzdata/zoneinfo/US/__pycache__/__init__.cpython-312.pyc index c42cd59..8d8dcf7 100644 Binary files a/venv/Lib/site-packages/tzdata/zoneinfo/US/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/tzdata/zoneinfo/US/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/tzdata/zoneinfo/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/tzdata/zoneinfo/__pycache__/__init__.cpython-312.pyc index 21f4606..5f640dd 100644 Binary files a/venv/Lib/site-packages/tzdata/zoneinfo/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/tzdata/zoneinfo/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/tzlocal-5.3.1.dist-info/RECORD b/venv/Lib/site-packages/tzlocal-5.3.1.dist-info/RECORD index f9f1e20..d6438da 100644 --- a/venv/Lib/site-packages/tzlocal-5.3.1.dist-info/RECORD +++ b/venv/Lib/site-packages/tzlocal-5.3.1.dist-info/RECORD @@ -2,6 +2,7 @@ tzlocal-5.3.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuw tzlocal-5.3.1.dist-info/LICENSE.txt,sha256=2ZqyCa6xaq0sJckP_YPBqYHikP__dqQgoqsD4D8EG4w,1060 tzlocal-5.3.1.dist-info/METADATA,sha256=9fSrmurX5XWWl7z9_oEtOliS9NPLr90xlDjTv8kZWeQ,7589 tzlocal-5.3.1.dist-info/RECORD,, +tzlocal-5.3.1.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 tzlocal-5.3.1.dist-info/WHEEL,sha256=G16H4A3IeoQmnOrYV4ueZGKSjhipXx8zc8nu9FGlvMA,92 tzlocal-5.3.1.dist-info/top_level.txt,sha256=QR6vZWP520waETnkotApPQPyVh9VnjoYPoAVHLK1DrE,8 tzlocal/__init__.py,sha256=2OQDx61TZv_HmBl7JKKP4ATldlx5OdEXOjKXAt8rQwY,396 diff --git a/venv/Lib/site-packages/tzlocal-5.3.1.dist-info/REQUESTED b/venv/Lib/site-packages/tzlocal-5.3.1.dist-info/REQUESTED new file mode 100644 index 0000000..e69de29 diff --git a/venv/Lib/site-packages/tzlocal/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/tzlocal/__pycache__/__init__.cpython-312.pyc index 2a497d3..01e5d32 100644 Binary files a/venv/Lib/site-packages/tzlocal/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/tzlocal/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/tzlocal/__pycache__/unix.cpython-312.pyc b/venv/Lib/site-packages/tzlocal/__pycache__/unix.cpython-312.pyc index f59b431..92af317 100644 Binary files a/venv/Lib/site-packages/tzlocal/__pycache__/unix.cpython-312.pyc and b/venv/Lib/site-packages/tzlocal/__pycache__/unix.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/tzlocal/__pycache__/utils.cpython-312.pyc b/venv/Lib/site-packages/tzlocal/__pycache__/utils.cpython-312.pyc index d72068b..ae3c4da 100644 Binary files a/venv/Lib/site-packages/tzlocal/__pycache__/utils.cpython-312.pyc and b/venv/Lib/site-packages/tzlocal/__pycache__/utils.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/tzlocal/__pycache__/win32.cpython-312.pyc b/venv/Lib/site-packages/tzlocal/__pycache__/win32.cpython-312.pyc index 8cdcce3..be99ac0 100644 Binary files a/venv/Lib/site-packages/tzlocal/__pycache__/win32.cpython-312.pyc and b/venv/Lib/site-packages/tzlocal/__pycache__/win32.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/tzlocal/__pycache__/windows_tz.cpython-312.pyc b/venv/Lib/site-packages/tzlocal/__pycache__/windows_tz.cpython-312.pyc index a5f991f..52cc95e 100644 Binary files a/venv/Lib/site-packages/tzlocal/__pycache__/windows_tz.cpython-312.pyc and b/venv/Lib/site-packages/tzlocal/__pycache__/windows_tz.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/urllib3-2.6.3.dist-info/RECORD b/venv/Lib/site-packages/urllib3-2.6.3.dist-info/RECORD index 8e0de4b..77def86 100644 --- a/venv/Lib/site-packages/urllib3-2.6.3.dist-info/RECORD +++ b/venv/Lib/site-packages/urllib3-2.6.3.dist-info/RECORD @@ -1,6 +1,7 @@ urllib3-2.6.3.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 urllib3-2.6.3.dist-info/METADATA,sha256=6ROQzJr0mwGXOPHXObXNklEwwy6dPmrMCGPCHF2Ygu8,6901 urllib3-2.6.3.dist-info/RECORD,, +urllib3-2.6.3.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 urllib3-2.6.3.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87 urllib3-2.6.3.dist-info/licenses/LICENSE.txt,sha256=Ew46ZNX91dCWp1JpRjSn2d8oRGnehuVzIQAmgEHj1oY,1093 urllib3/__init__.py,sha256=JMo1tg1nIV1AeJ2vENC_Txfl0e5h6Gzl9DGVk1rWRbo,6979 diff --git a/venv/Lib/site-packages/urllib3-2.6.3.dist-info/REQUESTED b/venv/Lib/site-packages/urllib3-2.6.3.dist-info/REQUESTED new file mode 100644 index 0000000..e69de29 diff --git a/venv/Lib/site-packages/urllib3/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/urllib3/__pycache__/__init__.cpython-312.pyc index 61eeea4..b1b92d0 100644 Binary files a/venv/Lib/site-packages/urllib3/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/urllib3/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/urllib3/__pycache__/_base_connection.cpython-312.pyc b/venv/Lib/site-packages/urllib3/__pycache__/_base_connection.cpython-312.pyc index e9d9408..a982986 100644 Binary files a/venv/Lib/site-packages/urllib3/__pycache__/_base_connection.cpython-312.pyc and b/venv/Lib/site-packages/urllib3/__pycache__/_base_connection.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/urllib3/__pycache__/_collections.cpython-312.pyc b/venv/Lib/site-packages/urllib3/__pycache__/_collections.cpython-312.pyc index 6e94c83..b6b1bdc 100644 Binary files a/venv/Lib/site-packages/urllib3/__pycache__/_collections.cpython-312.pyc and b/venv/Lib/site-packages/urllib3/__pycache__/_collections.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/urllib3/__pycache__/_request_methods.cpython-312.pyc b/venv/Lib/site-packages/urllib3/__pycache__/_request_methods.cpython-312.pyc index 0fc50d8..e186714 100644 Binary files a/venv/Lib/site-packages/urllib3/__pycache__/_request_methods.cpython-312.pyc and b/venv/Lib/site-packages/urllib3/__pycache__/_request_methods.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/urllib3/__pycache__/_version.cpython-312.pyc b/venv/Lib/site-packages/urllib3/__pycache__/_version.cpython-312.pyc index 79e1e61..424d3ed 100644 Binary files a/venv/Lib/site-packages/urllib3/__pycache__/_version.cpython-312.pyc and b/venv/Lib/site-packages/urllib3/__pycache__/_version.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/urllib3/__pycache__/connection.cpython-312.pyc b/venv/Lib/site-packages/urllib3/__pycache__/connection.cpython-312.pyc index 90c5324..ac9a278 100644 Binary files a/venv/Lib/site-packages/urllib3/__pycache__/connection.cpython-312.pyc and b/venv/Lib/site-packages/urllib3/__pycache__/connection.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/urllib3/__pycache__/connectionpool.cpython-312.pyc b/venv/Lib/site-packages/urllib3/__pycache__/connectionpool.cpython-312.pyc index ec44b11..91b51a1 100644 Binary files a/venv/Lib/site-packages/urllib3/__pycache__/connectionpool.cpython-312.pyc and b/venv/Lib/site-packages/urllib3/__pycache__/connectionpool.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/urllib3/__pycache__/exceptions.cpython-312.pyc b/venv/Lib/site-packages/urllib3/__pycache__/exceptions.cpython-312.pyc index da4647f..8261261 100644 Binary files a/venv/Lib/site-packages/urllib3/__pycache__/exceptions.cpython-312.pyc and b/venv/Lib/site-packages/urllib3/__pycache__/exceptions.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/urllib3/__pycache__/fields.cpython-312.pyc b/venv/Lib/site-packages/urllib3/__pycache__/fields.cpython-312.pyc index 3925484..74dacb5 100644 Binary files a/venv/Lib/site-packages/urllib3/__pycache__/fields.cpython-312.pyc and b/venv/Lib/site-packages/urllib3/__pycache__/fields.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/urllib3/__pycache__/filepost.cpython-312.pyc b/venv/Lib/site-packages/urllib3/__pycache__/filepost.cpython-312.pyc index 88dbe0e..b9bffbe 100644 Binary files a/venv/Lib/site-packages/urllib3/__pycache__/filepost.cpython-312.pyc and b/venv/Lib/site-packages/urllib3/__pycache__/filepost.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/urllib3/__pycache__/poolmanager.cpython-312.pyc b/venv/Lib/site-packages/urllib3/__pycache__/poolmanager.cpython-312.pyc index b614782..d243a7f 100644 Binary files a/venv/Lib/site-packages/urllib3/__pycache__/poolmanager.cpython-312.pyc and b/venv/Lib/site-packages/urllib3/__pycache__/poolmanager.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/urllib3/__pycache__/response.cpython-312.pyc b/venv/Lib/site-packages/urllib3/__pycache__/response.cpython-312.pyc index a4e7304..2fc5192 100644 Binary files a/venv/Lib/site-packages/urllib3/__pycache__/response.cpython-312.pyc and b/venv/Lib/site-packages/urllib3/__pycache__/response.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/urllib3/contrib/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/urllib3/contrib/__pycache__/__init__.cpython-312.pyc index 072ed86..b15d114 100644 Binary files a/venv/Lib/site-packages/urllib3/contrib/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/urllib3/contrib/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/urllib3/contrib/__pycache__/pyopenssl.cpython-312.pyc b/venv/Lib/site-packages/urllib3/contrib/__pycache__/pyopenssl.cpython-312.pyc index 47a3245..096493c 100644 Binary files a/venv/Lib/site-packages/urllib3/contrib/__pycache__/pyopenssl.cpython-312.pyc and b/venv/Lib/site-packages/urllib3/contrib/__pycache__/pyopenssl.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/urllib3/contrib/__pycache__/socks.cpython-312.pyc b/venv/Lib/site-packages/urllib3/contrib/__pycache__/socks.cpython-312.pyc index 506e64b..f6c4806 100644 Binary files a/venv/Lib/site-packages/urllib3/contrib/__pycache__/socks.cpython-312.pyc and b/venv/Lib/site-packages/urllib3/contrib/__pycache__/socks.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/urllib3/contrib/emscripten/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/urllib3/contrib/emscripten/__pycache__/__init__.cpython-312.pyc index b955255..9c86e61 100644 Binary files a/venv/Lib/site-packages/urllib3/contrib/emscripten/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/urllib3/contrib/emscripten/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/urllib3/contrib/emscripten/__pycache__/connection.cpython-312.pyc b/venv/Lib/site-packages/urllib3/contrib/emscripten/__pycache__/connection.cpython-312.pyc index 0628b76..141655e 100644 Binary files a/venv/Lib/site-packages/urllib3/contrib/emscripten/__pycache__/connection.cpython-312.pyc and b/venv/Lib/site-packages/urllib3/contrib/emscripten/__pycache__/connection.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/urllib3/contrib/emscripten/__pycache__/fetch.cpython-312.pyc b/venv/Lib/site-packages/urllib3/contrib/emscripten/__pycache__/fetch.cpython-312.pyc index b155589..0ece754 100644 Binary files a/venv/Lib/site-packages/urllib3/contrib/emscripten/__pycache__/fetch.cpython-312.pyc and b/venv/Lib/site-packages/urllib3/contrib/emscripten/__pycache__/fetch.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/urllib3/contrib/emscripten/__pycache__/request.cpython-312.pyc b/venv/Lib/site-packages/urllib3/contrib/emscripten/__pycache__/request.cpython-312.pyc index b6ba6e9..9259a79 100644 Binary files a/venv/Lib/site-packages/urllib3/contrib/emscripten/__pycache__/request.cpython-312.pyc and b/venv/Lib/site-packages/urllib3/contrib/emscripten/__pycache__/request.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/urllib3/contrib/emscripten/__pycache__/response.cpython-312.pyc b/venv/Lib/site-packages/urllib3/contrib/emscripten/__pycache__/response.cpython-312.pyc index 2017715..f3a9cd7 100644 Binary files a/venv/Lib/site-packages/urllib3/contrib/emscripten/__pycache__/response.cpython-312.pyc and b/venv/Lib/site-packages/urllib3/contrib/emscripten/__pycache__/response.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/urllib3/http2/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/urllib3/http2/__pycache__/__init__.cpython-312.pyc index a9ab7b1..fa2d0aa 100644 Binary files a/venv/Lib/site-packages/urllib3/http2/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/urllib3/http2/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/urllib3/http2/__pycache__/connection.cpython-312.pyc b/venv/Lib/site-packages/urllib3/http2/__pycache__/connection.cpython-312.pyc index ef87f24..22f22ea 100644 Binary files a/venv/Lib/site-packages/urllib3/http2/__pycache__/connection.cpython-312.pyc and b/venv/Lib/site-packages/urllib3/http2/__pycache__/connection.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/urllib3/http2/__pycache__/probe.cpython-312.pyc b/venv/Lib/site-packages/urllib3/http2/__pycache__/probe.cpython-312.pyc index a624bd0..0ff71f4 100644 Binary files a/venv/Lib/site-packages/urllib3/http2/__pycache__/probe.cpython-312.pyc and b/venv/Lib/site-packages/urllib3/http2/__pycache__/probe.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/urllib3/util/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/urllib3/util/__pycache__/__init__.cpython-312.pyc index b1a7ef2..19be723 100644 Binary files a/venv/Lib/site-packages/urllib3/util/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/urllib3/util/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/urllib3/util/__pycache__/connection.cpython-312.pyc b/venv/Lib/site-packages/urllib3/util/__pycache__/connection.cpython-312.pyc index 748e3d9..d8aedf9 100644 Binary files a/venv/Lib/site-packages/urllib3/util/__pycache__/connection.cpython-312.pyc and b/venv/Lib/site-packages/urllib3/util/__pycache__/connection.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/urllib3/util/__pycache__/proxy.cpython-312.pyc b/venv/Lib/site-packages/urllib3/util/__pycache__/proxy.cpython-312.pyc index a3b8038..7d37550 100644 Binary files a/venv/Lib/site-packages/urllib3/util/__pycache__/proxy.cpython-312.pyc and b/venv/Lib/site-packages/urllib3/util/__pycache__/proxy.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/urllib3/util/__pycache__/request.cpython-312.pyc b/venv/Lib/site-packages/urllib3/util/__pycache__/request.cpython-312.pyc index 9b5b928..abc53fe 100644 Binary files a/venv/Lib/site-packages/urllib3/util/__pycache__/request.cpython-312.pyc and b/venv/Lib/site-packages/urllib3/util/__pycache__/request.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/urllib3/util/__pycache__/response.cpython-312.pyc b/venv/Lib/site-packages/urllib3/util/__pycache__/response.cpython-312.pyc index 1731339..203ff1c 100644 Binary files a/venv/Lib/site-packages/urllib3/util/__pycache__/response.cpython-312.pyc and b/venv/Lib/site-packages/urllib3/util/__pycache__/response.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/urllib3/util/__pycache__/retry.cpython-312.pyc b/venv/Lib/site-packages/urllib3/util/__pycache__/retry.cpython-312.pyc index dd9413d..f650848 100644 Binary files a/venv/Lib/site-packages/urllib3/util/__pycache__/retry.cpython-312.pyc and b/venv/Lib/site-packages/urllib3/util/__pycache__/retry.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/urllib3/util/__pycache__/ssl_.cpython-312.pyc b/venv/Lib/site-packages/urllib3/util/__pycache__/ssl_.cpython-312.pyc index 2ef4d60..45da14e 100644 Binary files a/venv/Lib/site-packages/urllib3/util/__pycache__/ssl_.cpython-312.pyc and b/venv/Lib/site-packages/urllib3/util/__pycache__/ssl_.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/urllib3/util/__pycache__/ssl_match_hostname.cpython-312.pyc b/venv/Lib/site-packages/urllib3/util/__pycache__/ssl_match_hostname.cpython-312.pyc index 9e59000..4d4f6b8 100644 Binary files a/venv/Lib/site-packages/urllib3/util/__pycache__/ssl_match_hostname.cpython-312.pyc and b/venv/Lib/site-packages/urllib3/util/__pycache__/ssl_match_hostname.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/urllib3/util/__pycache__/ssltransport.cpython-312.pyc b/venv/Lib/site-packages/urllib3/util/__pycache__/ssltransport.cpython-312.pyc index f3d8346..7b0eac1 100644 Binary files a/venv/Lib/site-packages/urllib3/util/__pycache__/ssltransport.cpython-312.pyc and b/venv/Lib/site-packages/urllib3/util/__pycache__/ssltransport.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/urllib3/util/__pycache__/timeout.cpython-312.pyc b/venv/Lib/site-packages/urllib3/util/__pycache__/timeout.cpython-312.pyc index 4630fe3..c8ba31e 100644 Binary files a/venv/Lib/site-packages/urllib3/util/__pycache__/timeout.cpython-312.pyc and b/venv/Lib/site-packages/urllib3/util/__pycache__/timeout.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/urllib3/util/__pycache__/url.cpython-312.pyc b/venv/Lib/site-packages/urllib3/util/__pycache__/url.cpython-312.pyc index 96ac8ec..8c0f6d2 100644 Binary files a/venv/Lib/site-packages/urllib3/util/__pycache__/url.cpython-312.pyc and b/venv/Lib/site-packages/urllib3/util/__pycache__/url.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/urllib3/util/__pycache__/util.cpython-312.pyc b/venv/Lib/site-packages/urllib3/util/__pycache__/util.cpython-312.pyc index 5e2cb10..eae2e8b 100644 Binary files a/venv/Lib/site-packages/urllib3/util/__pycache__/util.cpython-312.pyc and b/venv/Lib/site-packages/urllib3/util/__pycache__/util.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/urllib3/util/__pycache__/wait.cpython-312.pyc b/venv/Lib/site-packages/urllib3/util/__pycache__/wait.cpython-312.pyc index 37bdcd1..8769341 100644 Binary files a/venv/Lib/site-packages/urllib3/util/__pycache__/wait.cpython-312.pyc and b/venv/Lib/site-packages/urllib3/util/__pycache__/wait.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/werkzeug-3.1.5.dist-info/RECORD b/venv/Lib/site-packages/werkzeug-3.1.5.dist-info/RECORD index e354f02..2d80d35 100644 --- a/venv/Lib/site-packages/werkzeug-3.1.5.dist-info/RECORD +++ b/venv/Lib/site-packages/werkzeug-3.1.5.dist-info/RECORD @@ -1,6 +1,7 @@ werkzeug-3.1.5.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 werkzeug-3.1.5.dist-info/METADATA,sha256=cquyBL-mR52YsNXbnskxIDKQAk2ktbSgmyoyqTgesF8,4029 werkzeug-3.1.5.dist-info/RECORD,, +werkzeug-3.1.5.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 werkzeug-3.1.5.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82 werkzeug-3.1.5.dist-info/licenses/LICENSE.txt,sha256=O0nc7kEF6ze6wQ-vG-JgQI_oXSUrjp3y4JefweCUQ3s,1475 werkzeug/__init__.py,sha256=CejNWfCZKDaJ_FmshZFw8dFgjNAlu6q15ec7DwWJlM8,165 diff --git a/venv/Lib/site-packages/werkzeug-3.1.5.dist-info/REQUESTED b/venv/Lib/site-packages/werkzeug-3.1.5.dist-info/REQUESTED new file mode 100644 index 0000000..e69de29 diff --git a/venv/Lib/site-packages/werkzeug/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/werkzeug/__pycache__/__init__.cpython-312.pyc index 494fb70..b2cc3f1 100644 Binary files a/venv/Lib/site-packages/werkzeug/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/werkzeug/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/werkzeug/__pycache__/_internal.cpython-312.pyc b/venv/Lib/site-packages/werkzeug/__pycache__/_internal.cpython-312.pyc index 4cfa3a6..c2c9e0b 100644 Binary files a/venv/Lib/site-packages/werkzeug/__pycache__/_internal.cpython-312.pyc and b/venv/Lib/site-packages/werkzeug/__pycache__/_internal.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/werkzeug/__pycache__/_reloader.cpython-312.pyc b/venv/Lib/site-packages/werkzeug/__pycache__/_reloader.cpython-312.pyc index 88a0ba0..2e7f6e3 100644 Binary files a/venv/Lib/site-packages/werkzeug/__pycache__/_reloader.cpython-312.pyc and b/venv/Lib/site-packages/werkzeug/__pycache__/_reloader.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/werkzeug/__pycache__/exceptions.cpython-312.pyc b/venv/Lib/site-packages/werkzeug/__pycache__/exceptions.cpython-312.pyc index a049a86..4e63238 100644 Binary files a/venv/Lib/site-packages/werkzeug/__pycache__/exceptions.cpython-312.pyc and b/venv/Lib/site-packages/werkzeug/__pycache__/exceptions.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/werkzeug/__pycache__/formparser.cpython-312.pyc b/venv/Lib/site-packages/werkzeug/__pycache__/formparser.cpython-312.pyc index 4686832..b6358d0 100644 Binary files a/venv/Lib/site-packages/werkzeug/__pycache__/formparser.cpython-312.pyc and b/venv/Lib/site-packages/werkzeug/__pycache__/formparser.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/werkzeug/__pycache__/http.cpython-312.pyc b/venv/Lib/site-packages/werkzeug/__pycache__/http.cpython-312.pyc index d11be3e..4eec519 100644 Binary files a/venv/Lib/site-packages/werkzeug/__pycache__/http.cpython-312.pyc and b/venv/Lib/site-packages/werkzeug/__pycache__/http.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/werkzeug/__pycache__/local.cpython-312.pyc b/venv/Lib/site-packages/werkzeug/__pycache__/local.cpython-312.pyc index c46881a..7e78588 100644 Binary files a/venv/Lib/site-packages/werkzeug/__pycache__/local.cpython-312.pyc and b/venv/Lib/site-packages/werkzeug/__pycache__/local.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/werkzeug/__pycache__/security.cpython-312.pyc b/venv/Lib/site-packages/werkzeug/__pycache__/security.cpython-312.pyc index 7c4099d..81dbc70 100644 Binary files a/venv/Lib/site-packages/werkzeug/__pycache__/security.cpython-312.pyc and b/venv/Lib/site-packages/werkzeug/__pycache__/security.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/werkzeug/__pycache__/serving.cpython-312.pyc b/venv/Lib/site-packages/werkzeug/__pycache__/serving.cpython-312.pyc index d8ee3d5..e5b2787 100644 Binary files a/venv/Lib/site-packages/werkzeug/__pycache__/serving.cpython-312.pyc and b/venv/Lib/site-packages/werkzeug/__pycache__/serving.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/werkzeug/__pycache__/test.cpython-312.pyc b/venv/Lib/site-packages/werkzeug/__pycache__/test.cpython-312.pyc index f50716f..552774c 100644 Binary files a/venv/Lib/site-packages/werkzeug/__pycache__/test.cpython-312.pyc and b/venv/Lib/site-packages/werkzeug/__pycache__/test.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/werkzeug/__pycache__/testapp.cpython-312.pyc b/venv/Lib/site-packages/werkzeug/__pycache__/testapp.cpython-312.pyc index 2f89d07..56ed9e7 100644 Binary files a/venv/Lib/site-packages/werkzeug/__pycache__/testapp.cpython-312.pyc and b/venv/Lib/site-packages/werkzeug/__pycache__/testapp.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/werkzeug/__pycache__/urls.cpython-312.pyc b/venv/Lib/site-packages/werkzeug/__pycache__/urls.cpython-312.pyc index c0bc483..5d8d672 100644 Binary files a/venv/Lib/site-packages/werkzeug/__pycache__/urls.cpython-312.pyc and b/venv/Lib/site-packages/werkzeug/__pycache__/urls.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/werkzeug/__pycache__/user_agent.cpython-312.pyc b/venv/Lib/site-packages/werkzeug/__pycache__/user_agent.cpython-312.pyc index ca25d5a..ef62931 100644 Binary files a/venv/Lib/site-packages/werkzeug/__pycache__/user_agent.cpython-312.pyc and b/venv/Lib/site-packages/werkzeug/__pycache__/user_agent.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/werkzeug/__pycache__/utils.cpython-312.pyc b/venv/Lib/site-packages/werkzeug/__pycache__/utils.cpython-312.pyc index f7a8e2e..6f05b2d 100644 Binary files a/venv/Lib/site-packages/werkzeug/__pycache__/utils.cpython-312.pyc and b/venv/Lib/site-packages/werkzeug/__pycache__/utils.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/werkzeug/__pycache__/wsgi.cpython-312.pyc b/venv/Lib/site-packages/werkzeug/__pycache__/wsgi.cpython-312.pyc index f2bba9c..71aeac7 100644 Binary files a/venv/Lib/site-packages/werkzeug/__pycache__/wsgi.cpython-312.pyc and b/venv/Lib/site-packages/werkzeug/__pycache__/wsgi.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/werkzeug/datastructures/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/werkzeug/datastructures/__pycache__/__init__.cpython-312.pyc index d6d2fd0..9aabdbb 100644 Binary files a/venv/Lib/site-packages/werkzeug/datastructures/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/werkzeug/datastructures/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/werkzeug/datastructures/__pycache__/accept.cpython-312.pyc b/venv/Lib/site-packages/werkzeug/datastructures/__pycache__/accept.cpython-312.pyc index 3f0fdce..fde861f 100644 Binary files a/venv/Lib/site-packages/werkzeug/datastructures/__pycache__/accept.cpython-312.pyc and b/venv/Lib/site-packages/werkzeug/datastructures/__pycache__/accept.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/werkzeug/datastructures/__pycache__/auth.cpython-312.pyc b/venv/Lib/site-packages/werkzeug/datastructures/__pycache__/auth.cpython-312.pyc index 2b9ea10..5ef168b 100644 Binary files a/venv/Lib/site-packages/werkzeug/datastructures/__pycache__/auth.cpython-312.pyc and b/venv/Lib/site-packages/werkzeug/datastructures/__pycache__/auth.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/werkzeug/datastructures/__pycache__/cache_control.cpython-312.pyc b/venv/Lib/site-packages/werkzeug/datastructures/__pycache__/cache_control.cpython-312.pyc index 8702b8d..de3d3fc 100644 Binary files a/venv/Lib/site-packages/werkzeug/datastructures/__pycache__/cache_control.cpython-312.pyc and b/venv/Lib/site-packages/werkzeug/datastructures/__pycache__/cache_control.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/werkzeug/datastructures/__pycache__/csp.cpython-312.pyc b/venv/Lib/site-packages/werkzeug/datastructures/__pycache__/csp.cpython-312.pyc index de49d90..b3b15a2 100644 Binary files a/venv/Lib/site-packages/werkzeug/datastructures/__pycache__/csp.cpython-312.pyc and b/venv/Lib/site-packages/werkzeug/datastructures/__pycache__/csp.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/werkzeug/datastructures/__pycache__/etag.cpython-312.pyc b/venv/Lib/site-packages/werkzeug/datastructures/__pycache__/etag.cpython-312.pyc index 3d27fcd..dcd54a2 100644 Binary files a/venv/Lib/site-packages/werkzeug/datastructures/__pycache__/etag.cpython-312.pyc and b/venv/Lib/site-packages/werkzeug/datastructures/__pycache__/etag.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/werkzeug/datastructures/__pycache__/file_storage.cpython-312.pyc b/venv/Lib/site-packages/werkzeug/datastructures/__pycache__/file_storage.cpython-312.pyc index 592498e..1c7ef82 100644 Binary files a/venv/Lib/site-packages/werkzeug/datastructures/__pycache__/file_storage.cpython-312.pyc and b/venv/Lib/site-packages/werkzeug/datastructures/__pycache__/file_storage.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/werkzeug/datastructures/__pycache__/headers.cpython-312.pyc b/venv/Lib/site-packages/werkzeug/datastructures/__pycache__/headers.cpython-312.pyc index e3bf354..230a6dd 100644 Binary files a/venv/Lib/site-packages/werkzeug/datastructures/__pycache__/headers.cpython-312.pyc and b/venv/Lib/site-packages/werkzeug/datastructures/__pycache__/headers.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/werkzeug/datastructures/__pycache__/mixins.cpython-312.pyc b/venv/Lib/site-packages/werkzeug/datastructures/__pycache__/mixins.cpython-312.pyc index ca67f98..fc4b6ba 100644 Binary files a/venv/Lib/site-packages/werkzeug/datastructures/__pycache__/mixins.cpython-312.pyc and b/venv/Lib/site-packages/werkzeug/datastructures/__pycache__/mixins.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/werkzeug/datastructures/__pycache__/range.cpython-312.pyc b/venv/Lib/site-packages/werkzeug/datastructures/__pycache__/range.cpython-312.pyc index 279d893..7f13a10 100644 Binary files a/venv/Lib/site-packages/werkzeug/datastructures/__pycache__/range.cpython-312.pyc and b/venv/Lib/site-packages/werkzeug/datastructures/__pycache__/range.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/werkzeug/datastructures/__pycache__/structures.cpython-312.pyc b/venv/Lib/site-packages/werkzeug/datastructures/__pycache__/structures.cpython-312.pyc index d992516..c16d8e4 100644 Binary files a/venv/Lib/site-packages/werkzeug/datastructures/__pycache__/structures.cpython-312.pyc and b/venv/Lib/site-packages/werkzeug/datastructures/__pycache__/structures.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/werkzeug/debug/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/werkzeug/debug/__pycache__/__init__.cpython-312.pyc index 6808f14..32ae24f 100644 Binary files a/venv/Lib/site-packages/werkzeug/debug/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/werkzeug/debug/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/werkzeug/debug/__pycache__/console.cpython-312.pyc b/venv/Lib/site-packages/werkzeug/debug/__pycache__/console.cpython-312.pyc index f3b6f3b..ad0db44 100644 Binary files a/venv/Lib/site-packages/werkzeug/debug/__pycache__/console.cpython-312.pyc and b/venv/Lib/site-packages/werkzeug/debug/__pycache__/console.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/werkzeug/debug/__pycache__/repr.cpython-312.pyc b/venv/Lib/site-packages/werkzeug/debug/__pycache__/repr.cpython-312.pyc index 3deff86..fc203e5 100644 Binary files a/venv/Lib/site-packages/werkzeug/debug/__pycache__/repr.cpython-312.pyc and b/venv/Lib/site-packages/werkzeug/debug/__pycache__/repr.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/werkzeug/debug/__pycache__/tbtools.cpython-312.pyc b/venv/Lib/site-packages/werkzeug/debug/__pycache__/tbtools.cpython-312.pyc index bce9c30..b9195b0 100644 Binary files a/venv/Lib/site-packages/werkzeug/debug/__pycache__/tbtools.cpython-312.pyc and b/venv/Lib/site-packages/werkzeug/debug/__pycache__/tbtools.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/werkzeug/middleware/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/werkzeug/middleware/__pycache__/__init__.cpython-312.pyc index 82d1110..ff52820 100644 Binary files a/venv/Lib/site-packages/werkzeug/middleware/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/werkzeug/middleware/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/werkzeug/middleware/__pycache__/dispatcher.cpython-312.pyc b/venv/Lib/site-packages/werkzeug/middleware/__pycache__/dispatcher.cpython-312.pyc index 4929ab4..c8499bd 100644 Binary files a/venv/Lib/site-packages/werkzeug/middleware/__pycache__/dispatcher.cpython-312.pyc and b/venv/Lib/site-packages/werkzeug/middleware/__pycache__/dispatcher.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/werkzeug/middleware/__pycache__/http_proxy.cpython-312.pyc b/venv/Lib/site-packages/werkzeug/middleware/__pycache__/http_proxy.cpython-312.pyc index ca240a2..f6752ea 100644 Binary files a/venv/Lib/site-packages/werkzeug/middleware/__pycache__/http_proxy.cpython-312.pyc and b/venv/Lib/site-packages/werkzeug/middleware/__pycache__/http_proxy.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/werkzeug/middleware/__pycache__/lint.cpython-312.pyc b/venv/Lib/site-packages/werkzeug/middleware/__pycache__/lint.cpython-312.pyc index dcff44e..939dd08 100644 Binary files a/venv/Lib/site-packages/werkzeug/middleware/__pycache__/lint.cpython-312.pyc and b/venv/Lib/site-packages/werkzeug/middleware/__pycache__/lint.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/werkzeug/middleware/__pycache__/profiler.cpython-312.pyc b/venv/Lib/site-packages/werkzeug/middleware/__pycache__/profiler.cpython-312.pyc index 7b4d992..3b0df01 100644 Binary files a/venv/Lib/site-packages/werkzeug/middleware/__pycache__/profiler.cpython-312.pyc and b/venv/Lib/site-packages/werkzeug/middleware/__pycache__/profiler.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/werkzeug/middleware/__pycache__/proxy_fix.cpython-312.pyc b/venv/Lib/site-packages/werkzeug/middleware/__pycache__/proxy_fix.cpython-312.pyc index 2d1ff20..a98a002 100644 Binary files a/venv/Lib/site-packages/werkzeug/middleware/__pycache__/proxy_fix.cpython-312.pyc and b/venv/Lib/site-packages/werkzeug/middleware/__pycache__/proxy_fix.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/werkzeug/middleware/__pycache__/shared_data.cpython-312.pyc b/venv/Lib/site-packages/werkzeug/middleware/__pycache__/shared_data.cpython-312.pyc index d18a79d..04d8530 100644 Binary files a/venv/Lib/site-packages/werkzeug/middleware/__pycache__/shared_data.cpython-312.pyc and b/venv/Lib/site-packages/werkzeug/middleware/__pycache__/shared_data.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/werkzeug/routing/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/werkzeug/routing/__pycache__/__init__.cpython-312.pyc index feeecde..e0e1a9d 100644 Binary files a/venv/Lib/site-packages/werkzeug/routing/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/werkzeug/routing/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/werkzeug/routing/__pycache__/converters.cpython-312.pyc b/venv/Lib/site-packages/werkzeug/routing/__pycache__/converters.cpython-312.pyc index 3cb0540..aae2fba 100644 Binary files a/venv/Lib/site-packages/werkzeug/routing/__pycache__/converters.cpython-312.pyc and b/venv/Lib/site-packages/werkzeug/routing/__pycache__/converters.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/werkzeug/routing/__pycache__/exceptions.cpython-312.pyc b/venv/Lib/site-packages/werkzeug/routing/__pycache__/exceptions.cpython-312.pyc index 294657d..44253ca 100644 Binary files a/venv/Lib/site-packages/werkzeug/routing/__pycache__/exceptions.cpython-312.pyc and b/venv/Lib/site-packages/werkzeug/routing/__pycache__/exceptions.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/werkzeug/routing/__pycache__/map.cpython-312.pyc b/venv/Lib/site-packages/werkzeug/routing/__pycache__/map.cpython-312.pyc index fa9d877..0c06377 100644 Binary files a/venv/Lib/site-packages/werkzeug/routing/__pycache__/map.cpython-312.pyc and b/venv/Lib/site-packages/werkzeug/routing/__pycache__/map.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/werkzeug/routing/__pycache__/matcher.cpython-312.pyc b/venv/Lib/site-packages/werkzeug/routing/__pycache__/matcher.cpython-312.pyc index 3af73cd..5d3e687 100644 Binary files a/venv/Lib/site-packages/werkzeug/routing/__pycache__/matcher.cpython-312.pyc and b/venv/Lib/site-packages/werkzeug/routing/__pycache__/matcher.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/werkzeug/routing/__pycache__/rules.cpython-312.pyc b/venv/Lib/site-packages/werkzeug/routing/__pycache__/rules.cpython-312.pyc index 5073a9d..1c613ce 100644 Binary files a/venv/Lib/site-packages/werkzeug/routing/__pycache__/rules.cpython-312.pyc and b/venv/Lib/site-packages/werkzeug/routing/__pycache__/rules.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/werkzeug/sansio/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/werkzeug/sansio/__pycache__/__init__.cpython-312.pyc index 10e642e..992e03d 100644 Binary files a/venv/Lib/site-packages/werkzeug/sansio/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/werkzeug/sansio/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/werkzeug/sansio/__pycache__/http.cpython-312.pyc b/venv/Lib/site-packages/werkzeug/sansio/__pycache__/http.cpython-312.pyc index 1352102..021cf4d 100644 Binary files a/venv/Lib/site-packages/werkzeug/sansio/__pycache__/http.cpython-312.pyc and b/venv/Lib/site-packages/werkzeug/sansio/__pycache__/http.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/werkzeug/sansio/__pycache__/multipart.cpython-312.pyc b/venv/Lib/site-packages/werkzeug/sansio/__pycache__/multipart.cpython-312.pyc index 8d38105..c8ff5e0 100644 Binary files a/venv/Lib/site-packages/werkzeug/sansio/__pycache__/multipart.cpython-312.pyc and b/venv/Lib/site-packages/werkzeug/sansio/__pycache__/multipart.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/werkzeug/sansio/__pycache__/request.cpython-312.pyc b/venv/Lib/site-packages/werkzeug/sansio/__pycache__/request.cpython-312.pyc index f760c1c..bf15dcc 100644 Binary files a/venv/Lib/site-packages/werkzeug/sansio/__pycache__/request.cpython-312.pyc and b/venv/Lib/site-packages/werkzeug/sansio/__pycache__/request.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/werkzeug/sansio/__pycache__/response.cpython-312.pyc b/venv/Lib/site-packages/werkzeug/sansio/__pycache__/response.cpython-312.pyc index d2935f2..e20fa87 100644 Binary files a/venv/Lib/site-packages/werkzeug/sansio/__pycache__/response.cpython-312.pyc and b/venv/Lib/site-packages/werkzeug/sansio/__pycache__/response.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/werkzeug/sansio/__pycache__/utils.cpython-312.pyc b/venv/Lib/site-packages/werkzeug/sansio/__pycache__/utils.cpython-312.pyc index b0eff31..3b83145 100644 Binary files a/venv/Lib/site-packages/werkzeug/sansio/__pycache__/utils.cpython-312.pyc and b/venv/Lib/site-packages/werkzeug/sansio/__pycache__/utils.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/werkzeug/wrappers/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/werkzeug/wrappers/__pycache__/__init__.cpython-312.pyc index 621bb75..75d3148 100644 Binary files a/venv/Lib/site-packages/werkzeug/wrappers/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/werkzeug/wrappers/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/werkzeug/wrappers/__pycache__/request.cpython-312.pyc b/venv/Lib/site-packages/werkzeug/wrappers/__pycache__/request.cpython-312.pyc index 407f746..70135bf 100644 Binary files a/venv/Lib/site-packages/werkzeug/wrappers/__pycache__/request.cpython-312.pyc and b/venv/Lib/site-packages/werkzeug/wrappers/__pycache__/request.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/werkzeug/wrappers/__pycache__/response.cpython-312.pyc b/venv/Lib/site-packages/werkzeug/wrappers/__pycache__/response.cpython-312.pyc index de0413e..fad94cc 100644 Binary files a/venv/Lib/site-packages/werkzeug/wrappers/__pycache__/response.cpython-312.pyc and b/venv/Lib/site-packages/werkzeug/wrappers/__pycache__/response.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/yarl-1.22.0.dist-info/RECORD b/venv/Lib/site-packages/yarl-1.22.0.dist-info/RECORD index f87588b..6b090d6 100644 --- a/venv/Lib/site-packages/yarl-1.22.0.dist-info/RECORD +++ b/venv/Lib/site-packages/yarl-1.22.0.dist-info/RECORD @@ -1,6 +1,7 @@ yarl-1.22.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 yarl-1.22.0.dist-info/METADATA,sha256=mGnUBDeH_AIy84ehLyO_STPVAUJky2pUaGVD0FdTq0E,77596 yarl-1.22.0.dist-info/RECORD,, +yarl-1.22.0.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 yarl-1.22.0.dist-info/WHEEL,sha256=8UP9x9puWI0P1V_d7K2oMTBqfeLNm21CTzZ_Ptr0NXU,101 yarl-1.22.0.dist-info/licenses/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358 yarl-1.22.0.dist-info/licenses/NOTICE,sha256=VtasbIEFwKUTBMIdsGDjYa-ajqCvmnXCOcKLXRNpODg,609 diff --git a/venv/Lib/site-packages/yarl-1.22.0.dist-info/REQUESTED b/venv/Lib/site-packages/yarl-1.22.0.dist-info/REQUESTED new file mode 100644 index 0000000..e69de29 diff --git a/venv/Lib/site-packages/yarl/__pycache__/__init__.cpython-312.pyc b/venv/Lib/site-packages/yarl/__pycache__/__init__.cpython-312.pyc index 3dc0fc3..988d4c6 100644 Binary files a/venv/Lib/site-packages/yarl/__pycache__/__init__.cpython-312.pyc and b/venv/Lib/site-packages/yarl/__pycache__/__init__.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/yarl/__pycache__/_parse.cpython-312.pyc b/venv/Lib/site-packages/yarl/__pycache__/_parse.cpython-312.pyc index a210fc6..b5e02ad 100644 Binary files a/venv/Lib/site-packages/yarl/__pycache__/_parse.cpython-312.pyc and b/venv/Lib/site-packages/yarl/__pycache__/_parse.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/yarl/__pycache__/_path.cpython-312.pyc b/venv/Lib/site-packages/yarl/__pycache__/_path.cpython-312.pyc index d8524f9..f2539b6 100644 Binary files a/venv/Lib/site-packages/yarl/__pycache__/_path.cpython-312.pyc and b/venv/Lib/site-packages/yarl/__pycache__/_path.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/yarl/__pycache__/_query.cpython-312.pyc b/venv/Lib/site-packages/yarl/__pycache__/_query.cpython-312.pyc index 29cbc4d..5b75352 100644 Binary files a/venv/Lib/site-packages/yarl/__pycache__/_query.cpython-312.pyc and b/venv/Lib/site-packages/yarl/__pycache__/_query.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/yarl/__pycache__/_quoters.cpython-312.pyc b/venv/Lib/site-packages/yarl/__pycache__/_quoters.cpython-312.pyc index 4ad967a..f87a294 100644 Binary files a/venv/Lib/site-packages/yarl/__pycache__/_quoters.cpython-312.pyc and b/venv/Lib/site-packages/yarl/__pycache__/_quoters.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/yarl/__pycache__/_quoting.cpython-312.pyc b/venv/Lib/site-packages/yarl/__pycache__/_quoting.cpython-312.pyc index 3428e16..af03472 100644 Binary files a/venv/Lib/site-packages/yarl/__pycache__/_quoting.cpython-312.pyc and b/venv/Lib/site-packages/yarl/__pycache__/_quoting.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/yarl/__pycache__/_quoting_py.cpython-312.pyc b/venv/Lib/site-packages/yarl/__pycache__/_quoting_py.cpython-312.pyc index a5e11d4..89fee1b 100644 Binary files a/venv/Lib/site-packages/yarl/__pycache__/_quoting_py.cpython-312.pyc and b/venv/Lib/site-packages/yarl/__pycache__/_quoting_py.cpython-312.pyc differ diff --git a/venv/Lib/site-packages/yarl/__pycache__/_url.cpython-312.pyc b/venv/Lib/site-packages/yarl/__pycache__/_url.cpython-312.pyc index f904000..2d11787 100644 Binary files a/venv/Lib/site-packages/yarl/__pycache__/_url.cpython-312.pyc and b/venv/Lib/site-packages/yarl/__pycache__/_url.cpython-312.pyc differ diff --git a/venv/Scripts/__pycache__/jp.cpython-312.pyc b/venv/Scripts/__pycache__/jp.cpython-312.pyc index 9e1a7d8..3be62b2 100644 Binary files a/venv/Scripts/__pycache__/jp.cpython-312.pyc and b/venv/Scripts/__pycache__/jp.cpython-312.pyc differ diff --git a/venv/Scripts/activate b/venv/Scripts/activate index dabd17c..b639a35 100644 --- a/venv/Scripts/activate +++ b/venv/Scripts/activate @@ -39,10 +39,10 @@ deactivate nondestructive if [ "${OSTYPE:-}" = "cygwin" ] || [ "${OSTYPE:-}" = "msys" ] ; then # transform D:\path\to\venv to /d/path/to/venv on MSYS # and to /cygdrive/d/path/to/venv on Cygwin - export VIRTUAL_ENV=$(cygpath "D:\google\venv") + export VIRTUAL_ENV=$(cygpath "E:\ai_v\venv") else # use the path as-is - export VIRTUAL_ENV="D:\google\venv" + export VIRTUAL_ENV="E:\ai_v\venv" fi _OLD_VIRTUAL_PATH="$PATH" diff --git a/venv/Scripts/activate.bat b/venv/Scripts/activate.bat index c4ee543..2fac4e1 100644 --- a/venv/Scripts/activate.bat +++ b/venv/Scripts/activate.bat @@ -8,7 +8,7 @@ if defined _OLD_CODEPAGE ( "%SystemRoot%\System32\chcp.com" 65001 > nul ) -set VIRTUAL_ENV=D:\google\venv +set VIRTUAL_ENV=E:\ai_v\venv if not defined PROMPT set PROMPT=$P$G diff --git a/venv/Scripts/flask.exe b/venv/Scripts/flask.exe index b6e64f1..fc23faa 100644 Binary files a/venv/Scripts/flask.exe and b/venv/Scripts/flask.exe differ diff --git a/venv/Scripts/jp.py b/venv/Scripts/jp.py index 064eec2..e186703 100644 --- a/venv/Scripts/jp.py +++ b/venv/Scripts/jp.py @@ -1,4 +1,4 @@ -#!D:\google\venv\Scripts\python.exe +#!E:\ai_v\venv\Scripts\python.exe import sys import json diff --git a/venv/Scripts/normalizer.exe b/venv/Scripts/normalizer.exe index f23f2e1..86e5675 100644 Binary files a/venv/Scripts/normalizer.exe and b/venv/Scripts/normalizer.exe differ diff --git a/venv/Scripts/pip.exe b/venv/Scripts/pip.exe index 3596df9..daef577 100644 Binary files a/venv/Scripts/pip.exe and b/venv/Scripts/pip.exe differ diff --git a/venv/Scripts/pip3.12.exe b/venv/Scripts/pip3.12.exe index 3596df9..daef577 100644 Binary files a/venv/Scripts/pip3.12.exe and b/venv/Scripts/pip3.12.exe differ diff --git a/venv/Scripts/pip3.exe b/venv/Scripts/pip3.exe index 3596df9..daef577 100644 Binary files a/venv/Scripts/pip3.exe and b/venv/Scripts/pip3.exe differ diff --git a/venv/pyvenv.cfg b/venv/pyvenv.cfg index 5099ef9..bfdce8e 100644 --- a/venv/pyvenv.cfg +++ b/venv/pyvenv.cfg @@ -1,5 +1,5 @@ -home = C:\Users\24024\AppData\Local\Programs\Python\Python312 +home = C:\Users\Administrator\AppData\Local\Programs\Python\Python312 include-system-site-packages = false version = 3.12.3 -executable = D:\google\venv\Scripts\python.exe -command = D:\google\venv\Scripts\python.exe -m venv D:\google\venv +executable = C:\Users\Administrator\AppData\Local\Programs\Python\Python312\python.exe +command = C:\Users\Administrator\AppData\Local\Programs\Python\Python312\python.exe -m venv --clear E:\ai_v\venv