Skip to content

Commit

Permalink
Add support for mariadb's auth_ed25519
Browse files Browse the repository at this point in the history
Include #791 [1] into the current release of PyMySQL to
support mariadb's auth_ed25519.

This patch can be dropped once the PR have landed upstream
(currently depending on a new release of pynacl).

[1] PyMySQL/PyMySQL#791

Related-Bug: #1868454
  • Loading branch information
dciabrin committed Mar 30, 2020
1 parent 8976cf4 commit 7314b9d
Show file tree
Hide file tree
Showing 3 changed files with 114 additions and 3 deletions.
92 changes: 92 additions & 0 deletions auth_ed25519.patch
@@ -0,0 +1,92 @@
# taken from https://github.com/PyMySQL/PyMySQL/pull/791/commits
# stripped the patches for tests and development files

From: Damien Ciabrini <damien.ciabrini@gmail.com>
Date: Tue, 4 Jun 2019 09:28:29 +0200
Subject: [PATCH] Support for MariaDB's auth_ed25519 authentication plugin
(#786)

diff --git a/pymysql/_auth.py b/pymysql/_auth.py
index aa082dfe..0a09de4e 100644
--- a/pymysql/_auth.py
+++ b/pymysql/_auth.py
@@ -114,6 +114,66 @@ def _hash_password_323(password):
return struct.pack(">LL", r1, r2)


+# MariaDB's client_ed25519-plugin
+# https://mariadb.com/kb/en/library/connection/#client_ed25519-plugin
+
+_nacl_bindings = False
+
+
+def _init_nacl():
+ global _nacl_bindings
+ try:
+ from nacl import bindings
+ _nacl_bindings = bindings
+ except ImportError:
+ raise RuntimeError("'pynacl' package is required for ed25519_password auth method")
+
+
+def _scalar_clamp(s32):
+ ba = bytearray(s32)
+ ba0 = bytes(bytearray([ba[0] & 248]))
+ ba31 = bytes(bytearray([(ba[31] & 127) | 64]))
+ return ba0 + bytes(s32[1:31]) + ba31
+
+
+def ed25519_password(password, scramble):
+ """Sign a random scramble with elliptic curve Ed25519.
+
+ Secret and public key are derived from password.
+ """
+ # variable names based on rfc8032 section-5.1.6
+ #
+ if not _nacl_bindings:
+ _init_nacl()
+
+ # h = SHA512(password)
+ h = hashlib.sha512(password).digest()
+
+ # s = prune(first_half(h))
+ s = _scalar_clamp(h[:32])
+
+ # r = SHA512(second_half(h) || M)
+ r = hashlib.sha512(h[32:] + scramble).digest()
+
+ # R = encoded point [r]B
+ r = _nacl_bindings.crypto_core_ed25519_scalar_reduce(r)
+ R = _nacl_bindings.crypto_scalarmult_ed25519_base_noclamp(r)
+
+ # A = encoded point [s]B
+ A = _nacl_bindings.crypto_scalarmult_ed25519_base_noclamp(s)
+
+ # k = SHA512(R || A || M)
+ k = hashlib.sha512(R + A + scramble).digest()
+
+ # S = (k * s + r) mod L
+ k = _nacl_bindings.crypto_core_ed25519_scalar_reduce(k)
+ ks = _nacl_bindings.crypto_core_ed25519_scalar_mul(k, s)
+ S = _nacl_bindings.crypto_core_ed25519_scalar_add(ks, r)
+
+ # signature = R || S
+ return R + S
+
+
# sha256_password


diff --git a/pymysql/connections.py b/pymysql/connections.py
index d9ade9a2..df092929 100644
--- a/pymysql/connections.py
+++ b/pymysql/connections.py
@@ -889,6 +889,8 @@ def _process_auth(self, plugin_name, auth_packet):
return _auth.sha256_password_auth(self, auth_packet)
elif plugin_name == b"mysql_native_password":
data = _auth.scramble_native_password(self.password, auth_packet.read_all())
+ elif plugin_name == b'client_ed25519':
+ data = _auth.ed25519_password(self.password, auth_packet.read_all())
elif plugin_name == b"mysql_old_password":
data = _auth.scramble_old_password(self.password, auth_packet.read_all()) + b'\0'
elif plugin_name == b"mysql_clear_password":
23 changes: 21 additions & 2 deletions python-PyMySQL.spec
Expand Up @@ -2,23 +2,29 @@

%if 0%{?fedora} || 0%{?rhel} > 7
%global with_python3 1
%else
%global with_python2 1
%endif

Name: python-%{pypi_name}
Version: 0.9.2
Release: 2%{?dist}
Version: 0.9.3
Release: 2%{?dist}.rdo.1
Summary: Pure-Python MySQL client library

License: MIT
URL: https://pypi.python.org/pypi/%{pypi_name}/
Source0: https://files.pythonhosted.org/packages/source/P/PyMySQL/PyMySQL-%{version}.tar.gz

Patch1: auth_ed25519.patch

BuildArch: noarch

%if 0%{?with_python2}
# for python2
BuildRequires: python2-devel
BuildRequires: python2-setuptools
BuildRequires: python2-cryptography
%endif

%if 0%{?with_python3}
# for python3
Expand All @@ -33,6 +39,7 @@ to be a drop-in replacement for MySQLdb and work on CPython, PyPy, IronPython
and Jython.


%if 0%{?with_python2}
%package -n python2-%{pypi_name}
Summary: Pure-Python MySQL client library
Requires: python2-cryptography
Expand All @@ -42,6 +49,7 @@ Requires: python2-cryptography
This package contains a pure-Python MySQL client library. The goal of PyMySQL is
to be a drop-in replacement for MySQLdb and work on CPython, PyPy, IronPython
and Jython.
%endif

%if 0%{?with_python3}
%package -n python%{python3_pkgversion}-%{pypi_name}
Expand All @@ -58,24 +66,29 @@ and Jython.

%prep
%setup -qn %{pypi_name}-%{version}
%patch1 -p1
rm -rf %{pypi_name}.egg-info
# Remove tests files so they are not installed globally.
rm -rf tests


%build
%if 0%{?with_python2}
%py2_build
%endif
%if 0%{?with_python3}
%py3_build
%endif


%install
%if 0%{?with_python2}
%py2_install
# Remove shebang
#for lib in %{buildroot}%{python2_sitelib}/pymysql/tests/thirdparty/test_MySQLdb/*.py; do
# sed -i '1{\@^#!/usr/bin/env python@d}' $lib
#done
%endif

%if 0%{?with_python3}
%py3_install
Expand All @@ -90,11 +103,13 @@ rm -rf tests
# Tests cannot be launch on koji, they require a mysqldb running.


%if 0%{?with_python2}
%files -n python2-%{pypi_name}
%license LICENSE
%doc README.rst
%{python2_sitelib}/%{pypi_name}-%{version}-py%{python2_version}.egg-info/
%{python2_sitelib}/pymysql/
%endif

%if 0%{?with_python3}
%files -n python%{python3_pkgversion}-%{pypi_name}
Expand All @@ -105,6 +120,10 @@ rm -rf tests
%endif

%changelog
* Fri Mar 27 2020 Damien Ciabrini <dciabrin@redhat.com> - 0.9.3-2.rdo.1
- Aligned to Fedora 32 version
- Added support for mariadb auth_ed25519 (#791)

* Fri Jul 13 2018 Fedora Release Engineering <releng@fedoraproject.org> - 0.9.2-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_29_Mass_Rebuild

Expand Down
2 changes: 1 addition & 1 deletion sources
@@ -1 +1 @@
SHA512 (PyMySQL-0.9.2.tar.gz) = 4918802808fb12417db682831290adfa5a785ca34da5674b7a8ccc7c942a1de424c3085282912df326131e978daf771d71c6b33aeb3cb2590c70b5ff6e557b07
SHA512 (PyMySQL-0.9.3.tar.gz) = 2056bc4aca7a600ca50214b399edc6f3068b288c426aecb115db148f645b0ec7e9a1a7134cf67f39d4820ea59a925dc1ce3ed0e383fb5e16e0651e87449824f9

0 comments on commit 7314b9d

Please sign in to comment.