[DEL] Delete pygost
This commit is contained in:
parent
8c7a8c9675
commit
f56f450fdf
@ -1,9 +1,8 @@
|
||||
import threading
|
||||
import os
|
||||
import pygost.gost3412 as gost
|
||||
|
||||
# from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
|
||||
# from cryptography.hazmat.backends import default_backend
|
||||
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
|
||||
from cryptography.hazmat.backends import default_backend
|
||||
|
||||
erasing_methods = {
|
||||
"2 прохода": {
|
||||
@ -32,17 +31,12 @@ erasing_methods = {
|
||||
|
||||
def get_random_bytes(size):
|
||||
seed=os.urandom(32)
|
||||
# backend = default_backend()
|
||||
# cipher = Cipher(algorithms.AES(seed), modes.CTR(b'\0'*16), backend=backend)
|
||||
# encryptor = cipher.encryptor()
|
||||
|
||||
backend = default_backend()
|
||||
cipher = Cipher(algorithms.AES(seed), modes.CTR(b'\0'*16), backend=backend)
|
||||
encryptor = cipher.encryptor()
|
||||
nulls=b'\0'*(size)
|
||||
enc = gost.GOST3412Kuznechik(seed)
|
||||
rounds = int(size / 32)
|
||||
data = b''
|
||||
for i in range(512):
|
||||
data += enc.encrypt(nulls)
|
||||
return data
|
||||
|
||||
return encryptor.update(nulls)
|
||||
|
||||
class Drive():
|
||||
|
||||
|
||||
@ -1 +0,0 @@
|
||||
* Sergey Matveev <stargrave@stargrave.org>
|
||||
@ -1,674 +0,0 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
the GNU General Public License is intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. You must make sure that they, too, receive
|
||||
or can get the source code. And you must show them these terms so they
|
||||
know their rights.
|
||||
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Use with the GNU Affero General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU Affero General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
<program> Copyright (C) <year> <name of author>
|
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, your program's commands
|
||||
might be different; for a GUI interface, you would use an "about box".
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
The GNU General Public License does not permit incorporating your program
|
||||
into proprietary programs. If your program is a subroutine library, you
|
||||
may consider it more useful to permit linking proprietary applications with
|
||||
the library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
||||
@ -1,24 +0,0 @@
|
||||
Frequently asked questions
|
||||
**************************
|
||||
|
||||
My signature is not validated by other implementations. What is wrong?
|
||||
|
||||
Try to reverse it ('sign[::-1]'). Try to swap its halves
|
||||
('sign[len(sign)/2:] + sign[:len(sign)/2]'). Try to reverse its
|
||||
swapped halves too.
|
||||
|
||||
It is GOST: do you expect serialization unification?!
|
||||
|
||||
My signature is *still* not validated by other implementations!
|
||||
|
||||
Try to reverse digest you are signing/verifying ('dgst[::-1]').
|
||||
|
||||
It is GOST: do you expect serialization unification?!
|
||||
|
||||
Everything above did not help me. Does PyGOST sucks?
|
||||
|
||||
No way! You still have not tried to reverse your binary private
|
||||
key, public key and swap its halves.
|
||||
|
||||
It is GOST: do you expect serialization unification?!
|
||||
|
||||
@ -1,43 +0,0 @@
|
||||
Download
|
||||
********
|
||||
|
||||
No additional dependencies except Python 2.7/3.x interpreter are
|
||||
required.
|
||||
|
||||
Preferable way is to download tarball with the signature:
|
||||
|
||||
$ [fetch|wget] http://www.pygost.cypherpunks.ru/pygost-5.13.tar.zst
|
||||
$ [fetch|wget] http://www.pygost.cypherpunks.ru/pygost-5.13.tar.zst.{asc,sig}
|
||||
[verify signature]
|
||||
$ zstd -d < pygost-5.13.tar.zst | tar xf -
|
||||
$ cd pygost-5.13
|
||||
$ python setup.py install
|
||||
|
||||
You can obtain releases source code prepared tarballs on
|
||||
<http://www.pygost.cypherpunks.ru/>. You *have to* verify downloaded
|
||||
tarballs authenticity to be sure that you retrieved trusted and
|
||||
untampered software. There are two options:
|
||||
|
||||
OpenPGP (https://www.openpgp.org/) '.asc' signature
|
||||
Use GNU Privacy Guard (https://www.gnupg.org/) free software
|
||||
implementation. For the very first time it is necessary to get
|
||||
signing public key and import it. It is provided here
|
||||
(PUBKEY-PGP.asc), but you should check alternate resources.
|
||||
|
||||
pub rsa2048/0xE6FD1269CD0C009E 2016-09-13
|
||||
F55A 7619 3A0C 323A A031 0E6B E6FD 1269 CD0C 009E
|
||||
uid PyGOST releases <pygost at cypherpunks dot ru>
|
||||
|
||||
$ gpg --auto-key-locate dane --locate-keys pygost at cypherpunks dot ru
|
||||
$ gpg --auto-key-locate wkd --locate-keys pygost at cypherpunks dot ru
|
||||
|
||||
OpenSSH (https://www.openssh.com/) '.sig' signature
|
||||
Public key (PUBKEY-SSH.pub) and its OpenPGP signature
|
||||
(PUBKEY-SSH.pub.asc) made with the key above. Its fingerprint:
|
||||
'SHA256:/Z3T/T2sXaaunefAL6tz3ZykHTDYIMh5TLd9Hh9mxlU'.
|
||||
|
||||
$ ssh-keygen -Y verify -f PUBKEY-SSH.pub -I pygost@cypherpunks.ru -n file \
|
||||
-s pygost-5.13.tar.zst.sig < pygost-5.13.tar.zst
|
||||
|
||||
You can obtain development source code with 'git clone
|
||||
git://git.cypherpunks.ru/pygost.git'.
|
||||
@ -1,8 +0,0 @@
|
||||
include AUTHORS
|
||||
include COPYING
|
||||
include FAQ
|
||||
include INSTALL
|
||||
include NEWS
|
||||
include README
|
||||
include THANKS
|
||||
include VERSION
|
||||
271
pygost-5.13/NEWS
271
pygost-5.13/NEWS
@ -1,271 +0,0 @@
|
||||
News
|
||||
****
|
||||
|
||||
*5.13*
|
||||
Ability to use masked 34.10 private keys.
|
||||
|
||||
*5.12*
|
||||
Fixed incorrect digest calculation when using
|
||||
'GOST34112012*.update()' method.
|
||||
|
||||
*5.11*
|
||||
'gost34112012''s 'update()'/'digest()' methods are streaming now -
|
||||
they do not store the whole data in memory.
|
||||
|
||||
*5.10*
|
||||
Added ISO 10126 'pygost.gost3413.(un)pad_iso10126' padding support.
|
||||
|
||||
*5.9*
|
||||
Fixed 'wrap.wrap_cryptopro', that ignored Sbox for key
|
||||
diversification.
|
||||
|
||||
*5.8*
|
||||
Added human-readable name of the curve in 'GOST3410Curve.name'.
|
||||
|
||||
*5.7*
|
||||
Fixed MGM ignoring of the set tag size.
|
||||
|
||||
*5.6*
|
||||
Fixed lint errors for previous release.
|
||||
|
||||
*5.5*
|
||||
More 34.10 curve parameters aliases:
|
||||
id-tc26-gost-3410-2012-256-paramSetA -> id-tc26-gost-3410-12-256-paramSetA
|
||||
id-tc26-gost-3410-2012-256-paramSetB -> id-tc26-gost-3410-12-256-paramSetB
|
||||
id-tc26-gost-3410-2012-256-paramSetC -> id-tc26-gost-3410-12-256-paramSetC
|
||||
id-tc26-gost-3410-2012-256-paramSetD -> id-tc26-gost-3410-12-256-paramSetD
|
||||
id-tc26-gost-3410-2012-512-paramSetTest -> id-tc26-gost-3410-12-512-paramSetTest
|
||||
id-tc26-gost-3410-2012-512-paramSetA -> id-tc26-gost-3410-12-512-paramSetA
|
||||
id-tc26-gost-3410-2012-512-paramSetB -> id-tc26-gost-3410-12-512-paramSetB
|
||||
id-tc26-gost-3410-2012-512-paramSetC -> id-tc26-gost-3410-12-512-paramSetC
|
||||
|
||||
*5.4*
|
||||
'gost3410.prv_marshal' helper can make private keys that are in
|
||||
curve's Q field, for better compatibility with some
|
||||
implementations.
|
||||
|
||||
*5.3*
|
||||
* More than 4 times speed increase of 'gost34112012'.
|
||||
* 'asn1schemas/cert-selfsigned-example.py' optionally can issue
|
||||
CA signed child certificate.
|
||||
|
||||
*5.2*
|
||||
* 'GOST3410Curve' has '.contains(point)' method for checking if
|
||||
point is on the curve.
|
||||
* 'gost3410_vko' functions check if remote peer's public key is
|
||||
on the curve.
|
||||
* Small typing stubs fixes.
|
||||
|
||||
*5.1*
|
||||
Small typing stubs fixes.
|
||||
|
||||
*5.0*
|
||||
* Backward incompatible removing of misleading and excess 'mode'
|
||||
keyword argument from all 'gost3410*' related functions.
|
||||
Point/key sizes are determined by looking at curve's
|
||||
parameters size.
|
||||
* 'asn1schemas/cert-selfsigned-example.py' optionally can create
|
||||
CA certificate.
|
||||
|
||||
*4.9*
|
||||
* *Fixed* nasty bug with Edwards curves using in 34.10-VKO
|
||||
functions: curve's cofactor has not been used
|
||||
* CTR-ACPKM mode of operation
|
||||
* OMAC-ACPKM-Master moder of operation
|
||||
* KExp15/KImp15 key export/import functions
|
||||
* KDF_GOSTR3411_2012_256, KDF_TREE_GOSTR3411_2012_256
|
||||
* KEG export key generation function
|
||||
|
||||
*4.8*
|
||||
MGM AEAD mode for 64 and 128 bit ciphers.
|
||||
|
||||
*4.7*
|
||||
Removed 'gost28147.addmod' for simplicity.
|
||||
|
||||
*4.6*
|
||||
Fix invalid 'gost28147.addmod''s behaviour with much bigger values
|
||||
than the modulo.
|
||||
|
||||
*4.5*
|
||||
Fixed digest endianness and more RFC4491bis conformance in
|
||||
'asn1schemas/cert-selfsigned-example.py' certificate's.
|
||||
|
||||
*4.4*
|
||||
* 'id-tc26-gost-3410-2012-512-paramSetTest' curve
|
||||
* Simple FAQ
|
||||
* More test vectors for 34.10-2012
|
||||
* More X.509, PKCS #10 and corresponding ASN.1 helper structures
|
||||
|
||||
*4.3*
|
||||
Dummy release with fixed 'pygost.__version__'.
|
||||
|
||||
*4.2*
|
||||
* 'pygost.gost3410.sign' accepts predefined random data used for
|
||||
k/r generation
|
||||
* More test vectors for 34.10-2012
|
||||
|
||||
*4.1*
|
||||
* PEP-396 compatible module's '__version__'
|
||||
* Curve parameters aliases:
|
||||
id-GostR3410-2001-CryptoPro-XchA-ParamSet -> id-GostR3410-2001-CryptoPro-A-ParamSet
|
||||
id-GostR3410-2001-CryptoPro-XchB-ParamSet -> id-GostR3410-2001-CryptoPro-C-ParamSet
|
||||
id-tc26-gost-3410-2012-256-paramSetB -> id-GostR3410-2001-CryptoPro-A-ParamSet
|
||||
id-tc26-gost-3410-2012-256-paramSetC -> id-GostR3410-2001-CryptoPro-B-ParamSet
|
||||
id-tc26-gost-3410-2012-256-paramSetD -> id-GostR3410-2001-CryptoPro-C-ParamSet
|
||||
* Forbid any later GNU GPL version autousage (project's licence
|
||||
now is GNU GPLv3 only)
|
||||
|
||||
*4.0*
|
||||
* 34.10-2012 TC26 twisted Edwards curve related parameters
|
||||
* Coordinates conversion from twisted Edwards to Weierstrass
|
||||
form and vice versa
|
||||
* More test vectors
|
||||
* Backward incompatible Sbox and curves parameters renaming, to
|
||||
comply with OIDs identifying them:
|
||||
Gost2814789_TestParamSet -> id-Gost28147-89-TestParamSet
|
||||
Gost28147_CryptoProParamSetA -> id-Gost28147-89-CryptoPro-A-ParamSet
|
||||
Gost28147_CryptoProParamSetB -> id-Gost28147-89-CryptoPro-B-ParamSet
|
||||
Gost28147_CryptoProParamSetC -> id-Gost28147-89-CryptoPro-C-ParamSet
|
||||
Gost28147_CryptoProParamSetD -> id-Gost28147-89-CryptoPro-D-ParamSet
|
||||
Gost28147_tc26_ParamZ -> id-tc26-gost-28147-param-Z
|
||||
GostR3411_94_TestParamSet -> id-GostR3411-94-TestParamSet
|
||||
GostR3411_94_CryptoProParamSet -> id-GostR3411-94-CryptoProParamSet
|
||||
|
||||
GostR3410_2001_TestParamSet -> id-GostR3410-2001-TestParamSet
|
||||
GostR3410_2001_CryptoPro_A_ParamSet -> id-GostR3410-2001-CryptoPro-A-ParamSet
|
||||
GostR3410_2001_CryptoPro_B_ParamSet -> id-GostR3410-2001-CryptoPro-B-ParamSet
|
||||
GostR3410_2001_CryptoPro_C_ParamSet -> id-GostR3410-2001-CryptoPro-C-ParamSet
|
||||
GostR3410_2001_CryptoPro_XchA_ParamSet -> id-GostR3410-2001-CryptoPro-XchA-ParamSet
|
||||
GostR3410_2001_CryptoPro_XchB_ParamSet -> id-GostR3410-2001-CryptoPro-XchB-ParamSet
|
||||
GostR3410_2012_TC26_256_ParamSetA -> id-tc26-gost-3410-2012-256-paramSetA
|
||||
GostR3410_2012_TC26_ParamSetA -> id-tc26-gost-3410-12-512-paramSetA
|
||||
GostR3410_2012_TC26_ParamSetB -> id-tc26-gost-3410-12-512-paramSetB
|
||||
GostR3410_2012_TC26_ParamSetC -> id-tc26-gost-3410-2012-512-paramSetC
|
||||
* Backward incompatible 'GOST3410Curve' initialization: all
|
||||
parameters are passed not as big-endian encoded binaries, but
|
||||
as integers
|
||||
* Backward incompatible change: 'gost3410.CURVE_PARAMS' is
|
||||
disappeared. 'gost3410.CURVES' dictionary holds already
|
||||
initialized 'GOST3410Curve'. Just use
|
||||
'CURVES["id-tc26-gost-3410-12-512-paramSetA"]' instead of
|
||||
'GOST3410Curve(*CURVE_PARAMS["id-tc26-gost-3410-12-512-paramSetA"])'
|
||||
|
||||
*3.15*
|
||||
* Licence changed back to GNU GPLv3+. GNU LGPLv3+ licenced
|
||||
versions are not available anymore
|
||||
* More ASN.1-based test vectors (PyDERASN
|
||||
(http://www.pyderasn.cypherpunks.ru/) dependency required)
|
||||
|
||||
*3.14*
|
||||
Add missing typing stubs related to previous release.
|
||||
|
||||
*3.13*
|
||||
* Ability to explicitly specify used 28147-89 Sbox in
|
||||
'pygost.wrap.*' functions
|
||||
* Ability to use key meshing in 28147-89 CBC mode
|
||||
|
||||
*3.12*
|
||||
* Added mode argument to 'pygost.gost3410_vko.kek_34102012256',
|
||||
because 256-bit private keys can be used with that algorithm
|
||||
too.
|
||||
* Fix incorrect degree sanitizing in
|
||||
'pygost.gost3410.GOST3410Curve.exp' preventing using of
|
||||
'UKM=1' in 'pygost.gost3410_vko.kek_*' functions.
|
||||
|
||||
*3.11*
|
||||
Fixed PEP247 typing stub with invalid hexdigest method.
|
||||
|
||||
*3.10*
|
||||
Additional missing 34.11-* typing stubs.
|
||||
|
||||
*3.9*
|
||||
Add missing 34.11-2012 PBKDF2 typing stub.
|
||||
|
||||
*3.8*
|
||||
* 34.11-2012 based PBKDF2 function added
|
||||
* 34.13-2015 does not require double blocksized IVs
|
||||
|
||||
*3.7*
|
||||
Fixed 34.13-2015 OFB bug with IVs longer than 2 blocks.
|
||||
|
||||
*3.6*
|
||||
Fixed source files installation during 'setup.py install'
|
||||
invocation.
|
||||
|
||||
*3.5*
|
||||
Dummy release: added long description in package metadata.
|
||||
|
||||
*3.4*
|
||||
* Small mypy stubs related fixes
|
||||
* Licence changed from GNU GPLv3+ to GNU LGPLv3+
|
||||
|
||||
*3.3*
|
||||
* 'GOST3412Kuz' renamed to 'GOST3412Kuznechik'
|
||||
* 'GOST3412Magma' implements GOST R 34.12-2015 Magma 64-bit
|
||||
block cipher
|
||||
|
||||
*3.2*
|
||||
34.13-2015 block cipher modes of operation implementations.
|
||||
|
||||
*3.1*
|
||||
Fixed mypy stubs related to PEP247-successors.
|
||||
|
||||
*3.0*
|
||||
* 'gost3411_94' renamed to 'gost341194'
|
||||
* 'gost3411_2012' renamed and split to 'gost34112012256',
|
||||
'gost34112012512'
|
||||
* 'GOST34112012' split to 'GOST34112012256', 'GOST34112012512'
|
||||
* 'gost3410.kek' moved to separate 'gost3410_vko.kek_34102001'
|
||||
* VKO GOST R 34.10-2012 appeared in 'gost3410_vko', with test
|
||||
vectors
|
||||
* 34.11-94 digest is reversed, to be compatible with HMAC and
|
||||
PBKDF2 test vectors describe in TC26 documents
|
||||
* 34.11-94 PBKDF2 test vectors added
|
||||
* 'gost3410.prv_unmarshal', 'gost3410.pub_marshal',
|
||||
'gost3410.pub_unmarshal' helpers added, removing the need of
|
||||
'x509' module at all
|
||||
* 'gost3410.verify' requires '(pubX, pubY)' tuple, instead of
|
||||
two separate 'pubX', 'pubY' arguments
|
||||
* 34.11-94 based PBKDF2 function added
|
||||
|
||||
*2.4*
|
||||
Fixed 34.13 mypy stub.
|
||||
|
||||
*2.3*
|
||||
Typo and pylint fixes.
|
||||
|
||||
*2.2*
|
||||
GOST R 34.13-2015 padding methods.
|
||||
|
||||
*2.1*
|
||||
Documentation and supplementary files refactoring.
|
||||
|
||||
*2.0*
|
||||
PEP-0247 compatible hashers and MAC.
|
||||
|
||||
*1.0*
|
||||
* Ability to specify curve in pygost.x509 module
|
||||
* Ability to use 34.10-2012 in pygost.x509 functions
|
||||
* Renamed classes and modules:
|
||||
pygost.gost3410.SIZE_34100 -> pygost.gost3410.SIZE_3410_2001
|
||||
pygost.gost3410.SIZE_34112 -> pygost.gost3410.SIZE_3410_2012
|
||||
pygost.gost3411_12.GOST341112 -> pygost.gost3411_2012.GOST34112012
|
||||
|
||||
*0.16*
|
||||
34.10-2012 TC26 curve parameters.
|
||||
|
||||
*0.15*
|
||||
PEP-0484 static typing hints.
|
||||
|
||||
*0.14*
|
||||
34.10-2012 workability fix.
|
||||
|
||||
*0.13*
|
||||
Python3 compatibility.
|
||||
|
||||
*0.11*
|
||||
GOST R 34.12-2015 Кузнечик (Kuznechik) implementation.
|
||||
|
||||
*0.10*
|
||||
CryptoPro and GOST key wrapping, CryptoPro key meshing.
|
||||
|
||||
@ -1,96 +0,0 @@
|
||||
Metadata-Version: 2.1
|
||||
Name: pygost
|
||||
Version: 5.13
|
||||
Summary: Pure Python GOST cryptographic functions library
|
||||
Home-page: http://www.pygost.cypherpunks.ru/
|
||||
Author: Sergey Matveev
|
||||
Author-email: stargrave@stargrave.org
|
||||
License: GPLv3
|
||||
Platform: UNKNOWN
|
||||
Classifier: Development Status :: 5 - Production/Stable
|
||||
Classifier: Intended Audience :: Developers
|
||||
Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
|
||||
Classifier: Natural Language :: English
|
||||
Classifier: Operating System :: OS Independent
|
||||
Classifier: Programming Language :: Python :: 2
|
||||
Classifier: Programming Language :: Python :: 3
|
||||
Classifier: Topic :: Security :: Cryptography
|
||||
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
||||
License-File: COPYING
|
||||
License-File: AUTHORS
|
||||
|
||||
Pure Python 2.7/3.x GOST cryptographic functions library.
|
||||
|
||||
GOST is GOvernment STandard of Russian Federation (and Soviet Union).
|
||||
|
||||
* GOST 28147-89 (RFC 5830) block cipher with ECB, CNT (CTR), CFB, MAC,
|
||||
CBC (RFC 4357) modes of operation
|
||||
* various 28147-89-related S-boxes included
|
||||
* GOST R 34.11-94 hash function (RFC 5831)
|
||||
* GOST R 34.11-94 based PBKDF2 function
|
||||
* GOST R 34.11-2012 Стрибог (Streebog) hash function (RFC 6986)
|
||||
* GOST R 34.11-2012 based PBKDF2 function (Р 50.1.111-2016)
|
||||
* GOST R 34.10-2001 (RFC 5832) public key signature function
|
||||
* GOST R 34.10-2012 (RFC 7091) public key signature function
|
||||
* various 34.10 curve parameters included
|
||||
* Coordinates conversion from twisted Edwards to Weierstrass form and
|
||||
vice versa
|
||||
* VKO GOST R 34.10-2001 key agreement function (RFC 4357)
|
||||
* VKO GOST R 34.10-2012 key agreement function (RFC 7836)
|
||||
* 28147-89 and CryptoPro key wrapping (RFC 4357)
|
||||
* 28147-89 CryptoPro key meshing for CFB and CBC modes (RFC 4357)
|
||||
* RFC 4491 (using GOST algorithms with X.509) compatibility helpers
|
||||
* GOST R 34.12-2015 128-bit block cipher Кузнечик (Kuznechik) (RFC 7801)
|
||||
* GOST R 34.12-2015 64-bit block cipher Магма (Magma)
|
||||
* GOST R 34.13-2015 padding methods and block cipher modes of operation
|
||||
(ECB, CTR, OFB, CBC, CFB, MAC), ISO 10126 padding
|
||||
* MGM AEAD mode for 64 and 128 bit ciphers (RFC 9058)
|
||||
* CTR-ACPKM, OMAC-ACPKM-Master modes of operation (Р 1323565.1.017-2018)
|
||||
* KExp15/KImp15 key export/import functions (Р 1323565.1.017-2018)
|
||||
* KDF_GOSTR3411_2012_256, KDF_TREE_GOSTR3411_2012_256 (Р 50.1.113-2016)
|
||||
* KEG export key generation function (Р 1323565.1.020-2018)
|
||||
* PEP247-compatible hash/MAC functions
|
||||
|
||||
Known problems: low performance and non time-constant calculations.
|
||||
|
||||
Example 34.10-2012 keypair generation, signing and verifying:
|
||||
|
||||
>>> from pygost.gost3410 import CURVES
|
||||
>>> curve = CURVES["id-tc26-gost-3410-12-512-paramSetA"]
|
||||
>>> from os import urandom
|
||||
>>> prv_raw = urandom(64)
|
||||
>>> from pygost.gost3410 import prv_unmarshal
|
||||
>>> from pygost.gost3410 import prv_marshal
|
||||
>>> prv = prv_unmarshal(prv_raw)
|
||||
>>> prv_raw = prv_marshal(curve, prv)
|
||||
>>> from pygost.gost3410 import public_key
|
||||
>>> pub = public_key(curve, prv)
|
||||
>>> from pygost.gost3410 import pub_marshal
|
||||
>>> from pygost.utils import hexenc
|
||||
>>> print "Public key is:", hexenc(pub_marshal(pub))
|
||||
>>> from pygost import gost34112012512
|
||||
>>> data_for_signing = b"some data"
|
||||
>>> dgst = gost34112012512.new(data_for_signing).digest()
|
||||
>>> from pygost.gost3410 import sign
|
||||
>>> signature = sign(curve, prv, dgst)
|
||||
>>> from pygost.gost3410 import verify
|
||||
>>> verify(curve, pub, dgst, signature)
|
||||
True
|
||||
|
||||
Other examples can be found in docstrings and unittests.
|
||||
Example self-signed X.509 certificate creation can be found in
|
||||
pygost/asn1schemas/cert-selfsigned-example.py.
|
||||
|
||||
PyGOST is free software: see the file COPYING for copying conditions.
|
||||
|
||||
PyGOST'es home page is: http://www.pygost.cypherpunks.ru/
|
||||
You can read about GOST algorithms more: http://www.gost.cypherpunks.ru/
|
||||
|
||||
Please send questions, bug reports and patches to
|
||||
http://lists.cypherpunks.ru/gost.html mailing list.
|
||||
Announcements also go to this mailing list.
|
||||
|
||||
Development Git source code repository currently is located here:
|
||||
http://www.git.cypherpunks.ru/?p=pygost.git;a=summary
|
||||
|
||||
|
||||
@ -1,73 +0,0 @@
|
||||
Pure Python 2.7/3.x GOST cryptographic functions library.
|
||||
|
||||
GOST is GOvernment STandard of Russian Federation (and Soviet Union).
|
||||
|
||||
* GOST 28147-89 (RFC 5830) block cipher with ECB, CNT (CTR), CFB, MAC,
|
||||
CBC (RFC 4357) modes of operation
|
||||
* various 28147-89-related S-boxes included
|
||||
* GOST R 34.11-94 hash function (RFC 5831)
|
||||
* GOST R 34.11-94 based PBKDF2 function
|
||||
* GOST R 34.11-2012 Стрибог (Streebog) hash function (RFC 6986)
|
||||
* GOST R 34.11-2012 based PBKDF2 function (Р 50.1.111-2016)
|
||||
* GOST R 34.10-2001 (RFC 5832) public key signature function
|
||||
* GOST R 34.10-2012 (RFC 7091) public key signature function
|
||||
* various 34.10 curve parameters included
|
||||
* Coordinates conversion from twisted Edwards to Weierstrass form and
|
||||
vice versa
|
||||
* VKO GOST R 34.10-2001 key agreement function (RFC 4357)
|
||||
* VKO GOST R 34.10-2012 key agreement function (RFC 7836)
|
||||
* 28147-89 and CryptoPro key wrapping (RFC 4357)
|
||||
* 28147-89 CryptoPro key meshing for CFB and CBC modes (RFC 4357)
|
||||
* RFC 4491 (using GOST algorithms with X.509) compatibility helpers
|
||||
* GOST R 34.12-2015 128-bit block cipher Кузнечик (Kuznechik) (RFC 7801)
|
||||
* GOST R 34.12-2015 64-bit block cipher Магма (Magma)
|
||||
* GOST R 34.13-2015 padding methods and block cipher modes of operation
|
||||
(ECB, CTR, OFB, CBC, CFB, MAC), ISO 10126 padding
|
||||
* MGM AEAD mode for 64 and 128 bit ciphers (RFC 9058)
|
||||
* CTR-ACPKM, OMAC-ACPKM-Master modes of operation (Р 1323565.1.017-2018)
|
||||
* KExp15/KImp15 key export/import functions (Р 1323565.1.017-2018)
|
||||
* KDF_GOSTR3411_2012_256, KDF_TREE_GOSTR3411_2012_256 (Р 50.1.113-2016)
|
||||
* KEG export key generation function (Р 1323565.1.020-2018)
|
||||
* PEP247-compatible hash/MAC functions
|
||||
|
||||
Known problems: low performance and non time-constant calculations.
|
||||
|
||||
Example 34.10-2012 keypair generation, signing and verifying:
|
||||
|
||||
>>> from pygost.gost3410 import CURVES
|
||||
>>> curve = CURVES["id-tc26-gost-3410-12-512-paramSetA"]
|
||||
>>> from os import urandom
|
||||
>>> prv_raw = urandom(64)
|
||||
>>> from pygost.gost3410 import prv_unmarshal
|
||||
>>> from pygost.gost3410 import prv_marshal
|
||||
>>> prv = prv_unmarshal(prv_raw)
|
||||
>>> prv_raw = prv_marshal(curve, prv)
|
||||
>>> from pygost.gost3410 import public_key
|
||||
>>> pub = public_key(curve, prv)
|
||||
>>> from pygost.gost3410 import pub_marshal
|
||||
>>> from pygost.utils import hexenc
|
||||
>>> print "Public key is:", hexenc(pub_marshal(pub))
|
||||
>>> from pygost import gost34112012512
|
||||
>>> data_for_signing = b"some data"
|
||||
>>> dgst = gost34112012512.new(data_for_signing).digest()
|
||||
>>> from pygost.gost3410 import sign
|
||||
>>> signature = sign(curve, prv, dgst)
|
||||
>>> from pygost.gost3410 import verify
|
||||
>>> verify(curve, pub, dgst, signature)
|
||||
True
|
||||
|
||||
Other examples can be found in docstrings and unittests.
|
||||
Example self-signed X.509 certificate creation can be found in
|
||||
pygost/asn1schemas/cert-selfsigned-example.py.
|
||||
|
||||
PyGOST is free software: see the file COPYING for copying conditions.
|
||||
|
||||
PyGOST'es home page is: http://www.pygost.cypherpunks.ru/
|
||||
You can read about GOST algorithms more: http://www.gost.cypherpunks.ru/
|
||||
|
||||
Please send questions, bug reports and patches to
|
||||
http://lists.cypherpunks.ru/gost.html mailing list.
|
||||
Announcements also go to this mailing list.
|
||||
|
||||
Development Git source code repository currently is located here:
|
||||
http://www.git.cypherpunks.ru/?p=pygost.git;a=summary
|
||||
@ -1,8 +0,0 @@
|
||||
There are people deserving to be thanked for helping this project:
|
||||
|
||||
* Dmitry Eremin-Solenikov <dbaryshkov at gmail dot com> for his
|
||||
suggestions of TK26 standards usage as a base point for serialized
|
||||
structures representation
|
||||
* Alexander Lodin <lodin.alex@gmail.com> for finding bug in 34.13-2015
|
||||
OFB mode with IVs longer than 2 blocks
|
||||
* Efimov Vasiliy for adding and testing of CBC-mode key meshing
|
||||
@ -1 +0,0 @@
|
||||
5.13
|
||||
@ -1,6 +0,0 @@
|
||||
"""Pure Python GOST cryptographic functions library.
|
||||
|
||||
PyGOST is free software: see the file COPYING for copying conditions.
|
||||
"""
|
||||
|
||||
__version__ = "5.13"
|
||||
@ -1,18 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
"""DANE's SPKI hash calculator
|
||||
"""
|
||||
|
||||
from base64 import standard_b64decode
|
||||
from hashlib import sha256
|
||||
import sys
|
||||
|
||||
from pygost.asn1schemas.x509 import Certificate
|
||||
|
||||
|
||||
lines = sys.stdin.read().split("-----")
|
||||
idx = lines.index("BEGIN CERTIFICATE")
|
||||
if idx == -1:
|
||||
raise ValueError("PEM has no CERTIFICATE")
|
||||
cert_raw = standard_b64decode(lines[idx + 1])
|
||||
cert = Certificate().decod(cert_raw)
|
||||
print(sha256(cert["tbsCertificate"]["subjectPublicKeyInfo"].encode()).hexdigest())
|
||||
@ -1,348 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Create example self-signed X.509 certificate
|
||||
"""
|
||||
|
||||
from argparse import ArgumentParser
|
||||
from base64 import standard_b64decode
|
||||
from base64 import standard_b64encode
|
||||
from datetime import datetime
|
||||
from datetime import timedelta
|
||||
from os import urandom
|
||||
from sys import exit as sys_exit
|
||||
from sys import stdout
|
||||
from textwrap import fill
|
||||
|
||||
from pyderasn import Any
|
||||
from pyderasn import BitString
|
||||
from pyderasn import Boolean
|
||||
from pyderasn import IA5String
|
||||
from pyderasn import Integer
|
||||
from pyderasn import OctetString
|
||||
from pyderasn import PrintableString
|
||||
from pyderasn import UTCTime
|
||||
|
||||
from pygost.asn1schemas.oids import id_at_commonName
|
||||
from pygost.asn1schemas.oids import id_at_countryName
|
||||
from pygost.asn1schemas.oids import id_ce_authorityKeyIdentifier
|
||||
from pygost.asn1schemas.oids import id_ce_basicConstraints
|
||||
from pygost.asn1schemas.oids import id_ce_keyUsage
|
||||
from pygost.asn1schemas.oids import id_ce_subjectAltName
|
||||
from pygost.asn1schemas.oids import id_ce_subjectKeyIdentifier
|
||||
from pygost.asn1schemas.oids import id_tc26_gost3410_2012_256
|
||||
from pygost.asn1schemas.oids import id_tc26_gost3410_2012_256_paramSetA
|
||||
from pygost.asn1schemas.oids import id_tc26_gost3410_2012_256_paramSetB
|
||||
from pygost.asn1schemas.oids import id_tc26_gost3410_2012_256_paramSetC
|
||||
from pygost.asn1schemas.oids import id_tc26_gost3410_2012_256_paramSetD
|
||||
from pygost.asn1schemas.oids import id_tc26_gost3410_2012_512
|
||||
from pygost.asn1schemas.oids import id_tc26_gost3410_2012_512_paramSetA
|
||||
from pygost.asn1schemas.oids import id_tc26_gost3410_2012_512_paramSetB
|
||||
from pygost.asn1schemas.oids import id_tc26_gost3410_2012_512_paramSetC
|
||||
from pygost.asn1schemas.oids import id_tc26_signwithdigest_gost3410_2012_256
|
||||
from pygost.asn1schemas.oids import id_tc26_signwithdigest_gost3410_2012_512
|
||||
from pygost.asn1schemas.prvkey import PrivateKey
|
||||
from pygost.asn1schemas.prvkey import PrivateKeyAlgorithmIdentifier
|
||||
from pygost.asn1schemas.prvkey import PrivateKeyInfo
|
||||
from pygost.asn1schemas.x509 import AlgorithmIdentifier
|
||||
from pygost.asn1schemas.x509 import AttributeType
|
||||
from pygost.asn1schemas.x509 import AttributeTypeAndValue
|
||||
from pygost.asn1schemas.x509 import AttributeValue
|
||||
from pygost.asn1schemas.x509 import AuthorityKeyIdentifier
|
||||
from pygost.asn1schemas.x509 import BasicConstraints
|
||||
from pygost.asn1schemas.x509 import Certificate
|
||||
from pygost.asn1schemas.x509 import CertificateSerialNumber
|
||||
from pygost.asn1schemas.x509 import Extension
|
||||
from pygost.asn1schemas.x509 import Extensions
|
||||
from pygost.asn1schemas.x509 import GeneralName
|
||||
from pygost.asn1schemas.x509 import GostR34102012PublicKeyParameters
|
||||
from pygost.asn1schemas.x509 import KeyIdentifier
|
||||
from pygost.asn1schemas.x509 import KeyUsage
|
||||
from pygost.asn1schemas.x509 import Name
|
||||
from pygost.asn1schemas.x509 import RDNSequence
|
||||
from pygost.asn1schemas.x509 import RelativeDistinguishedName
|
||||
from pygost.asn1schemas.x509 import SubjectAltName
|
||||
from pygost.asn1schemas.x509 import SubjectKeyIdentifier
|
||||
from pygost.asn1schemas.x509 import SubjectPublicKeyInfo
|
||||
from pygost.asn1schemas.x509 import TBSCertificate
|
||||
from pygost.asn1schemas.x509 import Time
|
||||
from pygost.asn1schemas.x509 import Validity
|
||||
from pygost.asn1schemas.x509 import Version
|
||||
from pygost.gost3410 import CURVES
|
||||
from pygost.gost3410 import prv_unmarshal
|
||||
from pygost.gost3410 import pub_marshal
|
||||
from pygost.gost3410 import public_key
|
||||
from pygost.gost3410 import sign
|
||||
from pygost.gost34112012256 import GOST34112012256
|
||||
from pygost.gost34112012512 import GOST34112012512
|
||||
from pygost.utils import bytes2long
|
||||
|
||||
parser = ArgumentParser(description="Self-signed X.509 certificate creator")
|
||||
parser.add_argument(
|
||||
"--ca",
|
||||
action="store_true",
|
||||
help="Enable BasicConstraints.cA",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--cn",
|
||||
required=True,
|
||||
help="Subject's CommonName",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--country",
|
||||
help="Subject's Country",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--serial",
|
||||
help="Serial number",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--ai",
|
||||
required=True,
|
||||
help="Signing algorithm: {256[ABCD],512[ABC]}",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--issue-with",
|
||||
help="Path to PEM with CA to issue the child",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--reuse-key",
|
||||
help="Path to PEM with the key to reuse",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--out-key",
|
||||
help="Path to PEM with the resulting key",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--only-key",
|
||||
action="store_true",
|
||||
help="Only generate the key",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--out-cert",
|
||||
help="Path to PEM with the resulting certificate",
|
||||
)
|
||||
args = parser.parse_args()
|
||||
AIs = {
|
||||
"256A": {
|
||||
"publicKeyParamSet": id_tc26_gost3410_2012_256_paramSetA,
|
||||
"key_algorithm": id_tc26_gost3410_2012_256,
|
||||
"prv_len": 32,
|
||||
"curve": CURVES["id-tc26-gost-3410-2012-256-paramSetA"],
|
||||
"sign_algorithm": id_tc26_signwithdigest_gost3410_2012_256,
|
||||
"hasher": GOST34112012256,
|
||||
},
|
||||
"256B": {
|
||||
"publicKeyParamSet": id_tc26_gost3410_2012_256_paramSetB,
|
||||
"key_algorithm": id_tc26_gost3410_2012_256,
|
||||
"prv_len": 32,
|
||||
"curve": CURVES["id-tc26-gost-3410-2012-256-paramSetB"],
|
||||
"sign_algorithm": id_tc26_signwithdigest_gost3410_2012_256,
|
||||
"hasher": GOST34112012256,
|
||||
},
|
||||
"256C": {
|
||||
"publicKeyParamSet": id_tc26_gost3410_2012_256_paramSetC,
|
||||
"key_algorithm": id_tc26_gost3410_2012_256,
|
||||
"prv_len": 32,
|
||||
"curve": CURVES["id-tc26-gost-3410-2012-256-paramSetC"],
|
||||
"sign_algorithm": id_tc26_signwithdigest_gost3410_2012_256,
|
||||
"hasher": GOST34112012256,
|
||||
},
|
||||
"256D": {
|
||||
"publicKeyParamSet": id_tc26_gost3410_2012_256_paramSetD,
|
||||
"key_algorithm": id_tc26_gost3410_2012_256,
|
||||
"prv_len": 32,
|
||||
"curve": CURVES["id-tc26-gost-3410-2012-256-paramSetD"],
|
||||
"sign_algorithm": id_tc26_signwithdigest_gost3410_2012_256,
|
||||
"hasher": GOST34112012256,
|
||||
},
|
||||
"512A": {
|
||||
"publicKeyParamSet": id_tc26_gost3410_2012_512_paramSetA,
|
||||
"key_algorithm": id_tc26_gost3410_2012_512,
|
||||
"prv_len": 64,
|
||||
"curve": CURVES["id-tc26-gost-3410-12-512-paramSetA"],
|
||||
"sign_algorithm": id_tc26_signwithdigest_gost3410_2012_512,
|
||||
"hasher": GOST34112012512,
|
||||
},
|
||||
"512B": {
|
||||
"publicKeyParamSet": id_tc26_gost3410_2012_512_paramSetB,
|
||||
"key_algorithm": id_tc26_gost3410_2012_512,
|
||||
"prv_len": 64,
|
||||
"curve": CURVES["id-tc26-gost-3410-12-512-paramSetB"],
|
||||
"sign_algorithm": id_tc26_signwithdigest_gost3410_2012_512,
|
||||
"hasher": GOST34112012512,
|
||||
},
|
||||
"512C": {
|
||||
"publicKeyParamSet": id_tc26_gost3410_2012_512_paramSetC,
|
||||
"key_algorithm": id_tc26_gost3410_2012_512,
|
||||
"prv_len": 64,
|
||||
"curve": CURVES["id-tc26-gost-3410-2012-512-paramSetC"],
|
||||
"sign_algorithm": id_tc26_signwithdigest_gost3410_2012_512,
|
||||
"hasher": GOST34112012512,
|
||||
},
|
||||
}
|
||||
ai = AIs[args.ai]
|
||||
|
||||
ca_prv = None
|
||||
ca_cert = None
|
||||
ca_subj = None
|
||||
ca_ai = None
|
||||
if args.issue_with is not None:
|
||||
with open(args.issue_with, "rb") as fd:
|
||||
lines = fd.read().decode("ascii").split("-----")
|
||||
idx = lines.index("BEGIN PRIVATE KEY")
|
||||
if idx == -1:
|
||||
raise ValueError("PEM has no PRIVATE KEY")
|
||||
prv_raw = standard_b64decode(lines[idx + 1])
|
||||
idx = lines.index("BEGIN CERTIFICATE")
|
||||
if idx == -1:
|
||||
raise ValueError("PEM has no CERTIFICATE")
|
||||
cert_raw = standard_b64decode(lines[idx + 1])
|
||||
pki = PrivateKeyInfo().decod(prv_raw)
|
||||
ca_prv = prv_unmarshal(bytes(OctetString().decod(bytes(pki["privateKey"]))))
|
||||
ca_cert = Certificate().decod(cert_raw)
|
||||
tbs = ca_cert["tbsCertificate"]
|
||||
ca_subj = tbs["subject"]
|
||||
curve_oid = GostR34102012PublicKeyParameters().decod(bytes(
|
||||
tbs["subjectPublicKeyInfo"]["algorithm"]["parameters"]
|
||||
))["publicKeyParamSet"]
|
||||
ca_ai = next(iter([
|
||||
params for params in AIs.values()
|
||||
if params["publicKeyParamSet"] == curve_oid
|
||||
]))
|
||||
|
||||
key_params = GostR34102012PublicKeyParameters((
|
||||
("publicKeyParamSet", ai["publicKeyParamSet"]),
|
||||
))
|
||||
|
||||
|
||||
def pem(obj):
|
||||
return fill(standard_b64encode(obj.encode()).decode("ascii"), 64)
|
||||
|
||||
|
||||
if args.reuse_key is not None:
|
||||
with open(args.reuse_key, "rb") as fd:
|
||||
lines = fd.read().decode("ascii").split("-----")
|
||||
idx = lines.index("BEGIN PRIVATE KEY")
|
||||
if idx == -1:
|
||||
raise ValueError("PEM has no PRIVATE KEY")
|
||||
prv_raw = standard_b64decode(lines[idx + 1])
|
||||
pki = PrivateKeyInfo().decod(prv_raw)
|
||||
prv = prv_unmarshal(bytes(OctetString().decod(bytes(pki["privateKey"]))))
|
||||
else:
|
||||
prv_raw = urandom(ai["prv_len"])
|
||||
out = stdout if args.out_key is None else open(args.out_key, "w")
|
||||
print("-----BEGIN PRIVATE KEY-----", file=out)
|
||||
print(pem(PrivateKeyInfo((
|
||||
("version", Integer(0)),
|
||||
("privateKeyAlgorithm", PrivateKeyAlgorithmIdentifier((
|
||||
("algorithm", ai["key_algorithm"]),
|
||||
("parameters", Any(key_params)),
|
||||
))),
|
||||
("privateKey", PrivateKey(OctetString(prv_raw).encode())),
|
||||
))), file=out)
|
||||
print("-----END PRIVATE KEY-----", file=out)
|
||||
if args.only_key:
|
||||
sys_exit()
|
||||
prv = prv_unmarshal(prv_raw)
|
||||
|
||||
curve = ai["curve"]
|
||||
pub_raw = pub_marshal(public_key(curve, prv))
|
||||
rdn = [RelativeDistinguishedName((
|
||||
AttributeTypeAndValue((
|
||||
("type", AttributeType(id_at_commonName)),
|
||||
("value", AttributeValue(PrintableString(args.cn))),
|
||||
)),
|
||||
))]
|
||||
if args.country:
|
||||
rdn.append(RelativeDistinguishedName((
|
||||
AttributeTypeAndValue((
|
||||
("type", AttributeType(id_at_countryName)),
|
||||
("value", AttributeValue(PrintableString(args.country))),
|
||||
)),
|
||||
)))
|
||||
subj = Name(("rdnSequence", RDNSequence(rdn)))
|
||||
not_before = datetime.utcnow()
|
||||
not_after = not_before + timedelta(days=365 * (10 if args.ca else 1))
|
||||
ai_sign = AlgorithmIdentifier((
|
||||
("algorithm", (ai if ca_ai is None else ca_ai)["sign_algorithm"]),
|
||||
))
|
||||
exts = [
|
||||
Extension((
|
||||
("extnID", id_ce_subjectKeyIdentifier),
|
||||
("extnValue", OctetString(
|
||||
SubjectKeyIdentifier(GOST34112012256(pub_raw).digest()[:20]).encode()
|
||||
)),
|
||||
)),
|
||||
Extension((
|
||||
("extnID", id_ce_keyUsage),
|
||||
("critical", Boolean(True)),
|
||||
("extnValue", OctetString(KeyUsage(
|
||||
("keyCertSign" if args.ca else "digitalSignature",),
|
||||
).encode())),
|
||||
)),
|
||||
]
|
||||
if args.ca:
|
||||
exts.append(Extension((
|
||||
("extnID", id_ce_basicConstraints),
|
||||
("critical", Boolean(True)),
|
||||
("extnValue", OctetString(BasicConstraints((
|
||||
("cA", Boolean(True)),
|
||||
)).encode())),
|
||||
)))
|
||||
else:
|
||||
exts.append(Extension((
|
||||
("extnID", id_ce_subjectAltName),
|
||||
("extnValue", OctetString(
|
||||
SubjectAltName((
|
||||
GeneralName(("dNSName", IA5String(args.cn))),
|
||||
)).encode()
|
||||
)),
|
||||
)))
|
||||
if ca_ai is not None:
|
||||
caKeyId = [
|
||||
bytes(SubjectKeyIdentifier().decod(bytes(ext["extnValue"])))
|
||||
for ext in ca_cert["tbsCertificate"]["extensions"]
|
||||
if ext["extnID"] == id_ce_subjectKeyIdentifier
|
||||
][0]
|
||||
exts.append(Extension((
|
||||
("extnID", id_ce_authorityKeyIdentifier),
|
||||
("extnValue", OctetString(AuthorityKeyIdentifier((
|
||||
("keyIdentifier", KeyIdentifier(caKeyId)),
|
||||
)).encode())),
|
||||
)))
|
||||
|
||||
serial = (
|
||||
bytes2long(GOST34112012256(urandom(16)).digest()[:20])
|
||||
if args.serial is None else int(args.serial)
|
||||
)
|
||||
tbs = TBSCertificate((
|
||||
("version", Version("v3")),
|
||||
("serialNumber", CertificateSerialNumber(serial)),
|
||||
("signature", ai_sign),
|
||||
("issuer", subj if ca_ai is None else ca_subj),
|
||||
("validity", Validity((
|
||||
("notBefore", Time(("utcTime", UTCTime(not_before)))),
|
||||
("notAfter", Time(("utcTime", UTCTime(not_after)))),
|
||||
))),
|
||||
("subject", subj),
|
||||
("subjectPublicKeyInfo", SubjectPublicKeyInfo((
|
||||
("algorithm", AlgorithmIdentifier((
|
||||
("algorithm", ai["key_algorithm"]),
|
||||
("parameters", Any(key_params)),
|
||||
))),
|
||||
("subjectPublicKey", BitString(OctetString(pub_raw).encode())),
|
||||
))),
|
||||
("extensions", Extensions(exts)),
|
||||
))
|
||||
cert = Certificate((
|
||||
("tbsCertificate", tbs),
|
||||
("signatureAlgorithm", ai_sign),
|
||||
("signatureValue", BitString(
|
||||
sign(curve, prv, ai["hasher"](tbs.encode()).digest()[::-1])
|
||||
if ca_ai is None else
|
||||
sign(ca_ai["curve"], ca_prv, ca_ai["hasher"](tbs.encode()).digest()[::-1])
|
||||
)),
|
||||
))
|
||||
out = stdout if args.out_cert is None else open(args.out_cert, "w")
|
||||
print("-----BEGIN CERTIFICATE-----", file=out)
|
||||
print(pem(cert), file=out)
|
||||
print("-----END CERTIFICATE-----", file=out)
|
||||
@ -1,431 +0,0 @@
|
||||
# coding: utf-8
|
||||
# PyGOST -- Pure Python GOST cryptographic functions library
|
||||
# Copyright (C) 2015-2023 Sergey Matveev <stargrave@stargrave.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, version 3 of the License.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
"""CMS related structures (**NOT COMPLETE**)
|
||||
"""
|
||||
|
||||
from pyderasn import Any
|
||||
from pyderasn import BitString
|
||||
from pyderasn import Choice
|
||||
from pyderasn import Integer
|
||||
from pyderasn import ObjectIdentifier
|
||||
from pyderasn import OctetString
|
||||
from pyderasn import Sequence
|
||||
from pyderasn import SequenceOf
|
||||
from pyderasn import SetOf
|
||||
from pyderasn import tag_ctxc
|
||||
from pyderasn import tag_ctxp
|
||||
|
||||
from pygost.asn1schemas.oids import id_cms_mac_attr
|
||||
from pygost.asn1schemas.oids import id_contentType
|
||||
from pygost.asn1schemas.oids import id_digestedData
|
||||
from pygost.asn1schemas.oids import id_encryptedData
|
||||
from pygost.asn1schemas.oids import id_envelopedData
|
||||
from pygost.asn1schemas.oids import id_Gost28147_89
|
||||
from pygost.asn1schemas.oids import id_gostr3412_2015_kuznyechik_ctracpkm
|
||||
from pygost.asn1schemas.oids import id_gostr3412_2015_kuznyechik_ctracpkm_omac
|
||||
from pygost.asn1schemas.oids import id_gostr3412_2015_kuznyechik_wrap_kexp15
|
||||
from pygost.asn1schemas.oids import id_gostr3412_2015_magma_ctracpkm
|
||||
from pygost.asn1schemas.oids import id_gostr3412_2015_magma_ctracpkm_omac
|
||||
from pygost.asn1schemas.oids import id_gostr3412_2015_magma_wrap_kexp15
|
||||
from pygost.asn1schemas.oids import id_messageDigest
|
||||
from pygost.asn1schemas.oids import id_signedData
|
||||
from pygost.asn1schemas.oids import id_tc26_gost3410_2012_256
|
||||
from pygost.asn1schemas.oids import id_tc26_gost3410_2012_512
|
||||
from pygost.asn1schemas.x509 import AlgorithmIdentifier
|
||||
from pygost.asn1schemas.x509 import Certificate
|
||||
from pygost.asn1schemas.x509 import CertificateSerialNumber
|
||||
from pygost.asn1schemas.x509 import Name
|
||||
from pygost.asn1schemas.x509 import SubjectPublicKeyInfo
|
||||
|
||||
|
||||
class CMSVersion(Integer):
|
||||
pass
|
||||
|
||||
|
||||
class ContentType(ObjectIdentifier):
|
||||
pass
|
||||
|
||||
|
||||
class IssuerAndSerialNumber(Sequence):
|
||||
schema = (
|
||||
("issuer", Name()),
|
||||
("serialNumber", CertificateSerialNumber()),
|
||||
)
|
||||
|
||||
|
||||
class KeyIdentifier(OctetString):
|
||||
pass
|
||||
|
||||
|
||||
class SubjectKeyIdentifier(KeyIdentifier):
|
||||
pass
|
||||
|
||||
|
||||
class RecipientIdentifier(Choice):
|
||||
schema = (
|
||||
("issuerAndSerialNumber", IssuerAndSerialNumber()),
|
||||
("subjectKeyIdentifier", SubjectKeyIdentifier(impl=tag_ctxp(0))),
|
||||
)
|
||||
|
||||
|
||||
class Gost2814789Key(OctetString):
|
||||
bounds = (32, 32)
|
||||
|
||||
|
||||
class Gost2814789MAC(OctetString):
|
||||
bounds = (4, 4)
|
||||
|
||||
|
||||
class Gost2814789EncryptedKey(Sequence):
|
||||
schema = (
|
||||
("encryptedKey", Gost2814789Key()),
|
||||
("maskKey", Gost2814789Key(impl=tag_ctxp(0), optional=True)),
|
||||
("macKey", Gost2814789MAC()),
|
||||
)
|
||||
|
||||
|
||||
class GostR34102001TransportParameters(Sequence):
|
||||
schema = (
|
||||
("encryptionParamSet", ObjectIdentifier()),
|
||||
("ephemeralPublicKey", SubjectPublicKeyInfo(
|
||||
impl=tag_ctxc(0),
|
||||
optional=True,
|
||||
)),
|
||||
("ukm", OctetString()),
|
||||
)
|
||||
|
||||
|
||||
class GostR3410KeyTransport(Sequence):
|
||||
schema = (
|
||||
("sessionEncryptedKey", Gost2814789EncryptedKey()),
|
||||
("transportParameters", GostR34102001TransportParameters(
|
||||
impl=tag_ctxc(0),
|
||||
optional=True,
|
||||
)),
|
||||
)
|
||||
|
||||
|
||||
class GostR3410KeyTransport2019(Sequence):
|
||||
schema = (
|
||||
("encryptedKey", OctetString()),
|
||||
("ephemeralPublicKey", SubjectPublicKeyInfo()),
|
||||
("ukm", OctetString()),
|
||||
)
|
||||
|
||||
|
||||
class GostR341012KEGParameters(Sequence):
|
||||
schema = (
|
||||
("algorithm", ObjectIdentifier()),
|
||||
)
|
||||
|
||||
|
||||
class KeyEncryptionAlgorithmIdentifier(AlgorithmIdentifier):
|
||||
schema = (
|
||||
("algorithm", ObjectIdentifier(defines=(
|
||||
(("parameters",), {
|
||||
id_gostr3412_2015_magma_wrap_kexp15: GostR341012KEGParameters(),
|
||||
id_gostr3412_2015_kuznyechik_wrap_kexp15: GostR341012KEGParameters(),
|
||||
}),
|
||||
(("..", "encryptedKey"), {
|
||||
id_tc26_gost3410_2012_256: GostR3410KeyTransport(),
|
||||
id_tc26_gost3410_2012_512: GostR3410KeyTransport(),
|
||||
id_gostr3412_2015_magma_wrap_kexp15: GostR3410KeyTransport2019(),
|
||||
id_gostr3412_2015_kuznyechik_wrap_kexp15: GostR3410KeyTransport2019(),
|
||||
}),
|
||||
(("..", "recipientEncryptedKeys", any, "encryptedKey"), {
|
||||
id_tc26_gost3410_2012_256: Gost2814789EncryptedKey(),
|
||||
id_tc26_gost3410_2012_512: Gost2814789EncryptedKey(),
|
||||
}),
|
||||
))),
|
||||
("parameters", Any(optional=True)),
|
||||
)
|
||||
|
||||
|
||||
class EncryptedKey(OctetString):
|
||||
pass
|
||||
|
||||
|
||||
class KeyTransRecipientInfo(Sequence):
|
||||
schema = (
|
||||
("version", CMSVersion()),
|
||||
("rid", RecipientIdentifier()),
|
||||
("keyEncryptionAlgorithm", KeyEncryptionAlgorithmIdentifier()),
|
||||
("encryptedKey", EncryptedKey()),
|
||||
)
|
||||
|
||||
|
||||
class OriginatorPublicKey(Sequence):
|
||||
schema = (
|
||||
("algorithm", AlgorithmIdentifier()),
|
||||
("publicKey", BitString()),
|
||||
)
|
||||
|
||||
|
||||
class OriginatorIdentifierOrKey(Choice):
|
||||
schema = (
|
||||
("issuerAndSerialNumber", IssuerAndSerialNumber()),
|
||||
("subjectKeyIdentifier", SubjectKeyIdentifier(impl=tag_ctxp(0))),
|
||||
("originatorKey", OriginatorPublicKey(impl=tag_ctxc(1))),
|
||||
)
|
||||
|
||||
|
||||
class UserKeyingMaterial(OctetString):
|
||||
pass
|
||||
|
||||
|
||||
class KeyAgreeRecipientIdentifier(Choice):
|
||||
schema = (
|
||||
("issuerAndSerialNumber", IssuerAndSerialNumber()),
|
||||
# ("rKeyId", RecipientKeyIdentifier(impl=tag_ctxc(0))),
|
||||
)
|
||||
|
||||
|
||||
class RecipientEncryptedKey(Sequence):
|
||||
schema = (
|
||||
("rid", KeyAgreeRecipientIdentifier()),
|
||||
("encryptedKey", EncryptedKey()),
|
||||
)
|
||||
|
||||
|
||||
class RecipientEncryptedKeys(SequenceOf):
|
||||
schema = RecipientEncryptedKey()
|
||||
|
||||
|
||||
class KeyAgreeRecipientInfo(Sequence):
|
||||
schema = (
|
||||
("version", CMSVersion(3)),
|
||||
("originator", OriginatorIdentifierOrKey(expl=tag_ctxc(0))),
|
||||
("ukm", UserKeyingMaterial(expl=tag_ctxc(1), optional=True)),
|
||||
("keyEncryptionAlgorithm", KeyEncryptionAlgorithmIdentifier()),
|
||||
("recipientEncryptedKeys", RecipientEncryptedKeys()),
|
||||
)
|
||||
|
||||
|
||||
class RecipientInfo(Choice):
|
||||
schema = (
|
||||
("ktri", KeyTransRecipientInfo()),
|
||||
("kari", KeyAgreeRecipientInfo(impl=tag_ctxc(1))),
|
||||
# ("kekri", KEKRecipientInfo(impl=tag_ctxc(2))),
|
||||
# ("pwri", PasswordRecipientInfo(impl=tag_ctxc(3))),
|
||||
# ("ori", OtherRecipientInfo(impl=tag_ctxc(4))),
|
||||
)
|
||||
|
||||
|
||||
class RecipientInfos(SetOf):
|
||||
schema = RecipientInfo()
|
||||
bounds = (1, float("+inf"))
|
||||
|
||||
|
||||
class Gost2814789IV(OctetString):
|
||||
bounds = (8, 8)
|
||||
|
||||
|
||||
class Gost2814789Parameters(Sequence):
|
||||
schema = (
|
||||
("iv", Gost2814789IV()),
|
||||
("encryptionParamSet", ObjectIdentifier()),
|
||||
)
|
||||
|
||||
|
||||
class Gost341215EncryptionParameters(Sequence):
|
||||
schema = (
|
||||
("ukm", OctetString()),
|
||||
)
|
||||
|
||||
|
||||
class ContentEncryptionAlgorithmIdentifier(AlgorithmIdentifier):
|
||||
schema = (
|
||||
("algorithm", ObjectIdentifier(defines=(
|
||||
(("parameters",), {
|
||||
id_Gost28147_89: Gost2814789Parameters(),
|
||||
id_gostr3412_2015_magma_ctracpkm: Gost341215EncryptionParameters(),
|
||||
id_gostr3412_2015_kuznyechik_ctracpkm: Gost341215EncryptionParameters(),
|
||||
id_gostr3412_2015_magma_ctracpkm_omac: Gost341215EncryptionParameters(),
|
||||
id_gostr3412_2015_kuznyechik_ctracpkm_omac: Gost341215EncryptionParameters(),
|
||||
}),
|
||||
))),
|
||||
("parameters", Any(optional=True)),
|
||||
)
|
||||
|
||||
|
||||
class EncryptedContent(OctetString):
|
||||
pass
|
||||
|
||||
|
||||
class EncryptedContentInfo(Sequence):
|
||||
schema = (
|
||||
("contentType", ContentType()),
|
||||
("contentEncryptionAlgorithm", ContentEncryptionAlgorithmIdentifier()),
|
||||
("encryptedContent", EncryptedContent(impl=tag_ctxp(0), optional=True)),
|
||||
)
|
||||
|
||||
|
||||
class Digest(OctetString):
|
||||
pass
|
||||
|
||||
|
||||
class AttributeValue(Any):
|
||||
pass
|
||||
|
||||
|
||||
class AttributeValues(SetOf):
|
||||
schema = AttributeValue()
|
||||
|
||||
|
||||
class EncryptedMac(OctetString):
|
||||
pass
|
||||
|
||||
|
||||
class Attribute(Sequence):
|
||||
schema = (
|
||||
("attrType", ObjectIdentifier(defines=(
|
||||
(("attrValues",), {
|
||||
id_contentType: ObjectIdentifier(),
|
||||
id_messageDigest: Digest(),
|
||||
id_cms_mac_attr: EncryptedMac(),
|
||||
},),
|
||||
))),
|
||||
("attrValues", AttributeValues()),
|
||||
)
|
||||
|
||||
|
||||
class UnprotectedAttributes(SetOf):
|
||||
schema = Attribute()
|
||||
bounds = (1, float("+inf"))
|
||||
|
||||
|
||||
class CertificateChoices(Choice):
|
||||
schema = (
|
||||
("certificate", Certificate()),
|
||||
# ("extendedCertificate", OctetString(impl=tag_ctxp(0))),
|
||||
# ("v1AttrCert", AttributeCertificateV1(impl=tag_ctxc(1))), # V1 is osbolete
|
||||
# ("v2AttrCert", AttributeCertificateV2(impl=tag_ctxc(2))),
|
||||
# ("other", OtherCertificateFormat(impl=tag_ctxc(3))),
|
||||
)
|
||||
|
||||
|
||||
class CertificateSet(SetOf):
|
||||
schema = CertificateChoices()
|
||||
|
||||
|
||||
class OriginatorInfo(Sequence):
|
||||
schema = (
|
||||
("certs", CertificateSet(impl=tag_ctxc(0), optional=True)),
|
||||
# ("crls", RevocationInfoChoices(impl=tag_ctxc(1), optional=True)),
|
||||
)
|
||||
|
||||
|
||||
class EnvelopedData(Sequence):
|
||||
schema = (
|
||||
("version", CMSVersion()),
|
||||
("originatorInfo", OriginatorInfo(impl=tag_ctxc(0), optional=True)),
|
||||
("recipientInfos", RecipientInfos()),
|
||||
("encryptedContentInfo", EncryptedContentInfo()),
|
||||
("unprotectedAttrs", UnprotectedAttributes(impl=tag_ctxc(1), optional=True)),
|
||||
)
|
||||
|
||||
|
||||
class EncapsulatedContentInfo(Sequence):
|
||||
schema = (
|
||||
("eContentType", ContentType()),
|
||||
("eContent", OctetString(expl=tag_ctxc(0), optional=True)),
|
||||
)
|
||||
|
||||
|
||||
class SignerIdentifier(Choice):
|
||||
schema = (
|
||||
("issuerAndSerialNumber", IssuerAndSerialNumber()),
|
||||
("subjectKeyIdentifier", SubjectKeyIdentifier(impl=tag_ctxp(0))),
|
||||
)
|
||||
|
||||
|
||||
class DigestAlgorithmIdentifiers(SetOf):
|
||||
schema = AlgorithmIdentifier()
|
||||
|
||||
|
||||
class DigestAlgorithmIdentifier(AlgorithmIdentifier):
|
||||
pass
|
||||
|
||||
|
||||
class SignatureAlgorithmIdentifier(AlgorithmIdentifier):
|
||||
pass
|
||||
|
||||
|
||||
class SignatureValue(OctetString):
|
||||
pass
|
||||
|
||||
|
||||
class SignedAttributes(SetOf):
|
||||
schema = Attribute()
|
||||
bounds = (1, float("+inf"))
|
||||
|
||||
|
||||
class SignerInfo(Sequence):
|
||||
schema = (
|
||||
("version", CMSVersion()),
|
||||
("sid", SignerIdentifier()),
|
||||
("digestAlgorithm", DigestAlgorithmIdentifier()),
|
||||
("signedAttrs", SignedAttributes(impl=tag_ctxc(0), optional=True)),
|
||||
("signatureAlgorithm", SignatureAlgorithmIdentifier()),
|
||||
("signature", SignatureValue()),
|
||||
# ("unsignedAttrs", UnsignedAttributes(impl=tag_ctxc(1), optional=True)),
|
||||
)
|
||||
|
||||
|
||||
class SignerInfos(SetOf):
|
||||
schema = SignerInfo()
|
||||
|
||||
|
||||
class SignedData(Sequence):
|
||||
schema = (
|
||||
("version", CMSVersion()),
|
||||
("digestAlgorithms", DigestAlgorithmIdentifiers()),
|
||||
("encapContentInfo", EncapsulatedContentInfo()),
|
||||
("certificates", CertificateSet(impl=tag_ctxc(0), optional=True)),
|
||||
# ("crls", RevocationInfoChoices(impl=tag_ctxc(1), optional=True)),
|
||||
("signerInfos", SignerInfos()),
|
||||
)
|
||||
|
||||
|
||||
class DigestedData(Sequence):
|
||||
schema = (
|
||||
("version", CMSVersion()),
|
||||
("digestAlgorithm", DigestAlgorithmIdentifier()),
|
||||
("encapContentInfo", EncapsulatedContentInfo()),
|
||||
("digest", Digest()),
|
||||
)
|
||||
|
||||
|
||||
class EncryptedData(Sequence):
|
||||
schema = (
|
||||
("version", CMSVersion()),
|
||||
("encryptedContentInfo", EncryptedContentInfo()),
|
||||
("unprotectedAttrs", UnprotectedAttributes(impl=tag_ctxc(1), optional=True)),
|
||||
)
|
||||
|
||||
|
||||
class ContentInfo(Sequence):
|
||||
schema = (
|
||||
("contentType", ContentType(defines=(
|
||||
(("content",), {
|
||||
id_digestedData: DigestedData(),
|
||||
id_encryptedData: EncryptedData(),
|
||||
id_envelopedData: EnvelopedData(),
|
||||
id_signedData: SignedData(),
|
||||
}),
|
||||
))),
|
||||
("content", Any(expl=tag_ctxc(0))),
|
||||
)
|
||||
@ -1,60 +0,0 @@
|
||||
from pyderasn import ObjectIdentifier
|
||||
|
||||
|
||||
id_at_commonName = ObjectIdentifier("2.5.4.3")
|
||||
id_at_countryName = ObjectIdentifier("2.5.4.6")
|
||||
id_at_localityName = ObjectIdentifier("2.5.4.7")
|
||||
id_at_stateOrProvinceName = ObjectIdentifier("2.5.4.8")
|
||||
id_at_organizationName = ObjectIdentifier("2.5.4.10")
|
||||
|
||||
id_pkcs7 = ObjectIdentifier("1.2.840.113549.1.7")
|
||||
id_data = id_pkcs7 + (1,)
|
||||
id_signedData = id_pkcs7 + (2,)
|
||||
id_envelopedData = id_pkcs7 + (3,)
|
||||
id_digestedData = id_pkcs7 + (5,)
|
||||
id_encryptedData = id_pkcs7 + (6,)
|
||||
|
||||
id_pkcs9 = ObjectIdentifier("1.2.840.113549.1.9")
|
||||
id_contentType = id_pkcs9 + (3,)
|
||||
id_messageDigest = id_pkcs9 + (4,)
|
||||
id_pkcs9_certTypes_x509Certificate = ObjectIdentifier("1.2.840.113549.1.9.22.1")
|
||||
id_pkcs12_bagtypes_keyBag = ObjectIdentifier("1.2.840.113549.1.12.10.1.1")
|
||||
id_pkcs12_bagtypes_pkcs8ShroudedKeyBag = ObjectIdentifier("1.2.840.113549.1.12.10.1.2")
|
||||
id_pkcs12_bagtypes_certBag = ObjectIdentifier("1.2.840.113549.1.12.10.1.3")
|
||||
|
||||
id_Gost28147_89 = ObjectIdentifier("1.2.643.2.2.21")
|
||||
id_GostR3410_2001_TestParamSet = ObjectIdentifier("1.2.643.2.2.35.0")
|
||||
id_cms_mac_attr = ObjectIdentifier("1.2.643.7.1.0.6.1.1")
|
||||
id_tc26_gost3410_2012_256 = ObjectIdentifier("1.2.643.7.1.1.1.1")
|
||||
id_tc26_gost3410_2012_512 = ObjectIdentifier("1.2.643.7.1.1.1.2")
|
||||
id_tc26_gost3411_2012_256 = ObjectIdentifier("1.2.643.7.1.1.2.2")
|
||||
id_tc26_gost3411_2012_512 = ObjectIdentifier("1.2.643.7.1.1.2.3")
|
||||
id_tc26_signwithdigest_gost3410_2012_256 = ObjectIdentifier("1.2.643.7.1.1.3.2")
|
||||
id_tc26_signwithdigest_gost3410_2012_512 = ObjectIdentifier("1.2.643.7.1.1.3.3")
|
||||
id_gostr3412_2015_magma_ctracpkm = ObjectIdentifier("1.2.643.7.1.1.5.1.1")
|
||||
id_gostr3412_2015_magma_ctracpkm_omac = ObjectIdentifier("1.2.643.7.1.1.5.1.2")
|
||||
id_gostr3412_2015_kuznyechik_ctracpkm = ObjectIdentifier("1.2.643.7.1.1.5.2.1")
|
||||
id_gostr3412_2015_kuznyechik_ctracpkm_omac = ObjectIdentifier("1.2.643.7.1.1.5.2.2")
|
||||
id_tc26_agreement_gost3410_2012_256 = ObjectIdentifier("1.2.643.7.1.1.6.1")
|
||||
id_tc26_agreement_gost3410_2012_512 = ObjectIdentifier("1.2.643.7.1.1.6.2")
|
||||
id_gostr3412_2015_magma_wrap_kexp15 = ObjectIdentifier("1.2.643.7.1.1.7.1.1")
|
||||
id_gostr3412_2015_kuznyechik_wrap_kexp15 = ObjectIdentifier("1.2.643.7.1.1.7.2.1")
|
||||
id_tc26_gost3410_2012_256_paramSetA = ObjectIdentifier("1.2.643.7.1.2.1.1.1")
|
||||
id_tc26_gost3410_2012_256_paramSetB = ObjectIdentifier("1.2.643.7.1.2.1.1.2")
|
||||
id_tc26_gost3410_2012_256_paramSetC = ObjectIdentifier("1.2.643.7.1.2.1.1.3")
|
||||
id_tc26_gost3410_2012_256_paramSetD = ObjectIdentifier("1.2.643.7.1.2.1.1.4")
|
||||
id_tc26_gost3410_2012_512_paramSetTest = ObjectIdentifier("1.2.643.7.1.2.1.2.0")
|
||||
id_tc26_gost3410_2012_512_paramSetA = ObjectIdentifier("1.2.643.7.1.2.1.2.1")
|
||||
id_tc26_gost3410_2012_512_paramSetB = ObjectIdentifier("1.2.643.7.1.2.1.2.2")
|
||||
id_tc26_gost3410_2012_512_paramSetC = ObjectIdentifier("1.2.643.7.1.2.1.2.3")
|
||||
id_tc26_gost_28147_param_Z = ObjectIdentifier("1.2.643.7.1.2.5.1.1")
|
||||
|
||||
id_pbes2 = ObjectIdentifier("1.2.840.113549.1.5.13")
|
||||
id_pbkdf2 = ObjectIdentifier("1.2.840.113549.1.5.12")
|
||||
|
||||
id_at_commonName = ObjectIdentifier("2.5.4.3")
|
||||
id_ce_basicConstraints = ObjectIdentifier("2.5.29.19")
|
||||
id_ce_subjectKeyIdentifier = ObjectIdentifier("2.5.29.14")
|
||||
id_ce_keyUsage = ObjectIdentifier("2.5.29.15")
|
||||
id_ce_subjectAltName = ObjectIdentifier("2.5.29.17")
|
||||
id_ce_authorityKeyIdentifier = ObjectIdentifier("2.5.29.35")
|
||||
@ -1,250 +0,0 @@
|
||||
# coding: utf-8
|
||||
# PyGOST -- Pure Python GOST cryptographic functions library
|
||||
# Copyright (C) 2015-2023 Sergey Matveev <stargrave@stargrave.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, version 3 of the License.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
"""PKCS #12 related structures (**NOT COMPLETE**)
|
||||
"""
|
||||
|
||||
from pyderasn import Any
|
||||
from pyderasn import Choice
|
||||
from pyderasn import Integer
|
||||
from pyderasn import ObjectIdentifier
|
||||
from pyderasn import OctetString
|
||||
from pyderasn import Sequence
|
||||
from pyderasn import SequenceOf
|
||||
from pyderasn import SetOf
|
||||
from pyderasn import tag_ctxc
|
||||
from pyderasn import tag_ctxp
|
||||
|
||||
from pygost.asn1schemas.cms import CMSVersion
|
||||
from pygost.asn1schemas.cms import ContentType
|
||||
from pygost.asn1schemas.cms import Gost2814789Parameters
|
||||
from pygost.asn1schemas.cms import Gost341215EncryptionParameters
|
||||
from pygost.asn1schemas.oids import id_data
|
||||
from pygost.asn1schemas.oids import id_encryptedData
|
||||
from pygost.asn1schemas.oids import id_Gost28147_89
|
||||
from pygost.asn1schemas.oids import id_gostr3412_2015_kuznyechik_ctracpkm
|
||||
from pygost.asn1schemas.oids import id_gostr3412_2015_kuznyechik_ctracpkm_omac
|
||||
from pygost.asn1schemas.oids import id_gostr3412_2015_magma_ctracpkm
|
||||
from pygost.asn1schemas.oids import id_gostr3412_2015_magma_ctracpkm_omac
|
||||
from pygost.asn1schemas.oids import id_pbes2
|
||||
from pygost.asn1schemas.oids import id_pbkdf2
|
||||
from pygost.asn1schemas.oids import id_pkcs9_certTypes_x509Certificate
|
||||
from pygost.asn1schemas.prvkey import PrivateKeyInfo
|
||||
from pygost.asn1schemas.x509 import AlgorithmIdentifier
|
||||
from pygost.asn1schemas.x509 import Certificate
|
||||
|
||||
|
||||
class PBKDF2Salt(Choice):
|
||||
schema = (
|
||||
("specified", OctetString()),
|
||||
# ("otherSource", PBKDF2SaltSources()),
|
||||
)
|
||||
|
||||
|
||||
id_hmacWithSHA1 = ObjectIdentifier("1.2.840.113549.2.7")
|
||||
|
||||
|
||||
class PBKDF2PRFs(AlgorithmIdentifier):
|
||||
schema = (
|
||||
("algorithm", ObjectIdentifier(default=id_hmacWithSHA1)),
|
||||
("parameters", Any(optional=True)),
|
||||
)
|
||||
|
||||
|
||||
class IterationCount(Integer):
|
||||
bounds = (1, float("+inf"))
|
||||
|
||||
|
||||
class KeyLength(Integer):
|
||||
bounds = (1, float("+inf"))
|
||||
|
||||
|
||||
class PBKDF2Params(Sequence):
|
||||
schema = (
|
||||
("salt", PBKDF2Salt()),
|
||||
("iterationCount", IterationCount(optional=True)),
|
||||
("keyLength", KeyLength(optional=True)),
|
||||
("prf", PBKDF2PRFs()),
|
||||
)
|
||||
|
||||
|
||||
class PBES2KDFs(AlgorithmIdentifier):
|
||||
schema = (
|
||||
("algorithm", ObjectIdentifier(defines=(
|
||||
(("parameters",), {id_pbkdf2: PBKDF2Params()}),
|
||||
))),
|
||||
("parameters", Any(optional=True)),
|
||||
)
|
||||
|
||||
|
||||
class PBES2Encs(AlgorithmIdentifier):
|
||||
schema = (
|
||||
("algorithm", ObjectIdentifier(defines=(
|
||||
(("parameters",), {
|
||||
id_Gost28147_89: Gost2814789Parameters(),
|
||||
id_gostr3412_2015_magma_ctracpkm: Gost341215EncryptionParameters(),
|
||||
id_gostr3412_2015_magma_ctracpkm_omac: Gost341215EncryptionParameters(),
|
||||
id_gostr3412_2015_kuznyechik_ctracpkm: Gost341215EncryptionParameters(),
|
||||
id_gostr3412_2015_kuznyechik_ctracpkm_omac: Gost341215EncryptionParameters(),
|
||||
}),
|
||||
))),
|
||||
("parameters", Any(optional=True)),
|
||||
)
|
||||
|
||||
|
||||
class PBES2Params(Sequence):
|
||||
schema = (
|
||||
("keyDerivationFunc", PBES2KDFs()),
|
||||
("encryptionScheme", PBES2Encs()),
|
||||
)
|
||||
|
||||
|
||||
class EncryptionAlgorithmIdentifier(AlgorithmIdentifier):
|
||||
schema = (
|
||||
("algorithm", ObjectIdentifier(defines=(
|
||||
(("parameters",), {id_pbes2: PBES2Params()}),
|
||||
))),
|
||||
("parameters", Any(optional=True)),
|
||||
)
|
||||
|
||||
|
||||
class ContentEncryptionAlgorithmIdentifier(EncryptionAlgorithmIdentifier):
|
||||
schema = (
|
||||
("algorithm", ObjectIdentifier(defines=(
|
||||
(("parameters",), {id_pbes2: PBES2Params()}),
|
||||
))),
|
||||
("parameters", Any(optional=True)),
|
||||
)
|
||||
|
||||
|
||||
class EncryptedContent(OctetString):
|
||||
pass
|
||||
|
||||
|
||||
class EncryptedContentInfo(Sequence):
|
||||
schema = (
|
||||
("contentType", ContentType()),
|
||||
("contentEncryptionAlgorithm", ContentEncryptionAlgorithmIdentifier()),
|
||||
("encryptedContent", EncryptedContent(impl=tag_ctxp(0), optional=True)),
|
||||
)
|
||||
|
||||
|
||||
class EncryptedData(Sequence):
|
||||
schema = (
|
||||
("version", CMSVersion()),
|
||||
("encryptedContentInfo", EncryptedContentInfo()),
|
||||
# ("unprotectedAttrs", UnprotectedAttributes(impl=tag_ctxc(1), optional=True)),
|
||||
)
|
||||
|
||||
|
||||
class PKCS12BagSet(Any):
|
||||
pass
|
||||
|
||||
|
||||
class AttrValue(SetOf):
|
||||
schema = Any()
|
||||
|
||||
|
||||
class PKCS12Attribute(Sequence):
|
||||
schema = (
|
||||
("attrId", ObjectIdentifier()),
|
||||
("attrValue", AttrValue()),
|
||||
)
|
||||
|
||||
|
||||
class PKCS12Attributes(SetOf):
|
||||
schema = PKCS12Attribute()
|
||||
|
||||
|
||||
class SafeBag(Sequence):
|
||||
schema = (
|
||||
("bagId", ObjectIdentifier(defines=(
|
||||
(("bagValue",), {id_encryptedData: EncryptedData()}),
|
||||
))),
|
||||
("bagValue", PKCS12BagSet(expl=tag_ctxc(0))),
|
||||
("bagAttributes", PKCS12Attributes(optional=True)),
|
||||
)
|
||||
|
||||
|
||||
class SafeContents(SequenceOf):
|
||||
schema = SafeBag()
|
||||
|
||||
|
||||
OctetStringSafeContents = SafeContents(expl=OctetString.tag_default)
|
||||
|
||||
|
||||
class AuthSafe(Sequence):
|
||||
schema = (
|
||||
("contentType", ContentType(defines=(
|
||||
(("content",), {id_data: OctetStringSafeContents()}),
|
||||
))),
|
||||
("content", Any(expl=tag_ctxc(0))),
|
||||
)
|
||||
|
||||
|
||||
class DigestInfo(Sequence):
|
||||
schema = (
|
||||
("digestAlgorithm", AlgorithmIdentifier()),
|
||||
("digest", OctetString()),
|
||||
)
|
||||
|
||||
|
||||
class MacData(Sequence):
|
||||
schema = (
|
||||
("mac", DigestInfo()),
|
||||
("macSalt", OctetString()),
|
||||
("iterations", Integer(default=1)),
|
||||
)
|
||||
|
||||
|
||||
class PFX(Sequence):
|
||||
schema = (
|
||||
("version", Integer(default=1)),
|
||||
("authSafe", AuthSafe()),
|
||||
("macData", MacData(optional=True)),
|
||||
)
|
||||
|
||||
|
||||
class EncryptedPrivateKeyInfo(Sequence):
|
||||
schema = (
|
||||
("encryptionAlgorithm", EncryptionAlgorithmIdentifier()),
|
||||
("encryptedData", OctetString()),
|
||||
)
|
||||
|
||||
|
||||
class PKCS8ShroudedKeyBag(EncryptedPrivateKeyInfo):
|
||||
pass
|
||||
|
||||
|
||||
OctetStringX509Certificate = Certificate(expl=OctetString.tag_default)
|
||||
|
||||
|
||||
class CertTypes(Any):
|
||||
pass
|
||||
|
||||
|
||||
class CertBag(Sequence):
|
||||
schema = (
|
||||
("certId", ObjectIdentifier(defines=(
|
||||
(("certValue",), {
|
||||
id_pkcs9_certTypes_x509Certificate: OctetStringX509Certificate(),
|
||||
}),
|
||||
))),
|
||||
("certValue", CertTypes(expl=tag_ctxc(0))),
|
||||
)
|
||||
|
||||
|
||||
class KeyBag(PrivateKeyInfo):
|
||||
pass
|
||||
@ -1,49 +0,0 @@
|
||||
# coding: utf-8
|
||||
# PyGOST -- Pure Python GOST cryptographic functions library
|
||||
# Copyright (C) 2015-2023 Sergey Matveev <stargrave@stargrave.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, version 3 of the License.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
"""PKCS #10 related structures (**NOT COMPLETE**)
|
||||
"""
|
||||
|
||||
from pyderasn import BitString
|
||||
from pyderasn import Integer
|
||||
from pyderasn import Sequence
|
||||
from pyderasn import SetOf
|
||||
from pyderasn import tag_ctxc
|
||||
|
||||
from pygost.asn1schemas.cms import Attribute
|
||||
from pygost.asn1schemas.x509 import AlgorithmIdentifier
|
||||
from pygost.asn1schemas.x509 import Name
|
||||
from pygost.asn1schemas.x509 import SubjectPublicKeyInfo
|
||||
|
||||
|
||||
class Attributes(SetOf):
|
||||
schema = Attribute()
|
||||
|
||||
|
||||
class CertificationRequestInfo(Sequence):
|
||||
schema = (
|
||||
("version", Integer(0)),
|
||||
("subject", Name()),
|
||||
("subjectPKInfo", SubjectPublicKeyInfo()),
|
||||
("attributes", Attributes(impl=tag_ctxc(0))),
|
||||
)
|
||||
|
||||
|
||||
class CertificationRequest(Sequence):
|
||||
schema = (
|
||||
("certificationRequestInfo", CertificationRequestInfo()),
|
||||
("signatureAlgorithm", AlgorithmIdentifier()),
|
||||
("signature", BitString()),
|
||||
)
|
||||
@ -1,100 +0,0 @@
|
||||
# coding: utf-8
|
||||
# PyGOST -- Pure Python GOST cryptographic functions library
|
||||
# Copyright (C) 2015-2023 Sergey Matveev <stargrave@stargrave.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, version 3 of the License.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from pyderasn import Any
|
||||
from pyderasn import BitString
|
||||
from pyderasn import Choice
|
||||
from pyderasn import Integer
|
||||
from pyderasn import Null
|
||||
from pyderasn import ObjectIdentifier
|
||||
from pyderasn import OctetString
|
||||
from pyderasn import Sequence
|
||||
from pyderasn import SetOf
|
||||
from pyderasn import tag_ctxc
|
||||
from pyderasn import tag_ctxp
|
||||
|
||||
from pygost.asn1schemas.oids import id_tc26_gost3410_2012_256
|
||||
from pygost.asn1schemas.oids import id_tc26_gost3410_2012_512
|
||||
from pygost.asn1schemas.x509 import GostR34102012PublicKeyParameters
|
||||
|
||||
|
||||
class ECParameters(Choice):
|
||||
schema = (
|
||||
("namedCurve", ObjectIdentifier()),
|
||||
("implicitCurve", Null()),
|
||||
# ("specifiedCurve", SpecifiedECDomain()),
|
||||
)
|
||||
|
||||
|
||||
ecPrivkeyVer1 = Integer(1)
|
||||
|
||||
|
||||
class ECPrivateKey(Sequence):
|
||||
schema = (
|
||||
("version", Integer(ecPrivkeyVer1)),
|
||||
("privateKey", OctetString()),
|
||||
("parameters", ECParameters(expl=tag_ctxc(0), optional=True)),
|
||||
("publicKey", BitString(expl=tag_ctxc(1), optional=True)),
|
||||
)
|
||||
|
||||
|
||||
class PrivateKeyAlgorithmIdentifier(Sequence):
|
||||
schema = (
|
||||
("algorithm", ObjectIdentifier(defines=(
|
||||
(("parameters",), {
|
||||
id_tc26_gost3410_2012_256: GostR34102012PublicKeyParameters(),
|
||||
id_tc26_gost3410_2012_512: GostR34102012PublicKeyParameters(),
|
||||
}),
|
||||
))),
|
||||
("parameters", Any(optional=True)),
|
||||
)
|
||||
|
||||
|
||||
class PrivateKey(OctetString):
|
||||
pass
|
||||
|
||||
|
||||
class AttributeValue(Any):
|
||||
pass
|
||||
|
||||
|
||||
class AttributeValues(SetOf):
|
||||
schema = AttributeValue()
|
||||
|
||||
|
||||
class Attribute(Sequence):
|
||||
schema = (
|
||||
("attrType", ObjectIdentifier()),
|
||||
("attrValues", AttributeValues()),
|
||||
)
|
||||
|
||||
|
||||
class Attributes(SetOf):
|
||||
schema = Attribute()
|
||||
|
||||
|
||||
class PublicKey(BitString):
|
||||
pass
|
||||
|
||||
|
||||
class PrivateKeyInfo(Sequence):
|
||||
schema = (
|
||||
("version", Integer(0)),
|
||||
("privateKeyAlgorithm", PrivateKeyAlgorithmIdentifier()),
|
||||
("privateKey", PrivateKey()),
|
||||
("attributes", Attributes(impl=tag_ctxc(0), optional=True)),
|
||||
("publicKey", PublicKey(impl=tag_ctxp(1), optional=True)),
|
||||
)
|
||||
@ -1,262 +0,0 @@
|
||||
# coding: utf-8
|
||||
# PyGOST -- Pure Python GOST cryptographic functions library
|
||||
# Copyright (C) 2015-2023 Sergey Matveev <stargrave@stargrave.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, version 3 of the License.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
""":rfc:`5280` related structures (**NOT COMPLETE**)
|
||||
|
||||
They are taken from `PyDERASN <http://www.pyderasn.cypherpunks.ru/`__ tests.
|
||||
"""
|
||||
|
||||
from pyderasn import Any
|
||||
from pyderasn import BitString
|
||||
from pyderasn import Boolean
|
||||
from pyderasn import Choice
|
||||
from pyderasn import GeneralizedTime
|
||||
from pyderasn import IA5String
|
||||
from pyderasn import Integer
|
||||
from pyderasn import ObjectIdentifier
|
||||
from pyderasn import OctetString
|
||||
from pyderasn import PrintableString
|
||||
from pyderasn import Sequence
|
||||
from pyderasn import SequenceOf
|
||||
from pyderasn import SetOf
|
||||
from pyderasn import tag_ctxc
|
||||
from pyderasn import tag_ctxp
|
||||
from pyderasn import TeletexString
|
||||
from pyderasn import UTCTime
|
||||
|
||||
from pygost.asn1schemas.oids import id_at_commonName
|
||||
from pygost.asn1schemas.oids import id_at_countryName
|
||||
from pygost.asn1schemas.oids import id_at_localityName
|
||||
from pygost.asn1schemas.oids import id_at_organizationName
|
||||
from pygost.asn1schemas.oids import id_at_stateOrProvinceName
|
||||
|
||||
|
||||
class Version(Integer):
|
||||
schema = (
|
||||
("v1", 0),
|
||||
("v2", 1),
|
||||
("v3", 2),
|
||||
)
|
||||
|
||||
|
||||
class CertificateSerialNumber(Integer):
|
||||
pass
|
||||
|
||||
|
||||
class AlgorithmIdentifier(Sequence):
|
||||
schema = (
|
||||
("algorithm", ObjectIdentifier()),
|
||||
("parameters", Any(optional=True)),
|
||||
)
|
||||
|
||||
|
||||
class AttributeType(ObjectIdentifier):
|
||||
pass
|
||||
|
||||
|
||||
class AttributeValue(Any):
|
||||
pass
|
||||
|
||||
|
||||
class OrganizationName(Choice):
|
||||
schema = (
|
||||
("printableString", PrintableString()),
|
||||
("teletexString", TeletexString()),
|
||||
)
|
||||
|
||||
|
||||
class AttributeTypeAndValue(Sequence):
|
||||
schema = (
|
||||
("type", AttributeType(defines=(((".", "value"), {
|
||||
id_at_countryName: PrintableString(),
|
||||
id_at_stateOrProvinceName: PrintableString(),
|
||||
id_at_localityName: PrintableString(),
|
||||
id_at_organizationName: OrganizationName(),
|
||||
id_at_commonName: PrintableString(),
|
||||
}),))),
|
||||
("value", AttributeValue()),
|
||||
)
|
||||
|
||||
|
||||
class RelativeDistinguishedName(SetOf):
|
||||
schema = AttributeTypeAndValue()
|
||||
bounds = (1, float("+inf"))
|
||||
|
||||
|
||||
class RDNSequence(SequenceOf):
|
||||
schema = RelativeDistinguishedName()
|
||||
|
||||
|
||||
class Name(Choice):
|
||||
schema = (
|
||||
("rdnSequence", RDNSequence()),
|
||||
)
|
||||
|
||||
|
||||
class Time(Choice):
|
||||
schema = (
|
||||
("utcTime", UTCTime()),
|
||||
("generalTime", GeneralizedTime()),
|
||||
)
|
||||
|
||||
|
||||
class Validity(Sequence):
|
||||
schema = (
|
||||
("notBefore", Time()),
|
||||
("notAfter", Time()),
|
||||
)
|
||||
|
||||
|
||||
class GostR34102012PublicKeyParameters(Sequence):
|
||||
schema = (
|
||||
("publicKeyParamSet", ObjectIdentifier()),
|
||||
("digestParamSet", ObjectIdentifier(optional=True)),
|
||||
)
|
||||
|
||||
|
||||
class SubjectPublicKeyInfo(Sequence):
|
||||
schema = (
|
||||
("algorithm", AlgorithmIdentifier()),
|
||||
("subjectPublicKey", BitString()),
|
||||
)
|
||||
|
||||
|
||||
class UniqueIdentifier(BitString):
|
||||
pass
|
||||
|
||||
|
||||
class KeyIdentifier(OctetString):
|
||||
pass
|
||||
|
||||
|
||||
class SubjectKeyIdentifier(KeyIdentifier):
|
||||
pass
|
||||
|
||||
|
||||
class BasicConstraints(Sequence):
|
||||
schema = (
|
||||
("cA", Boolean(default=False)),
|
||||
# ("pathLenConstraint", PathLenConstraint(optional=True)),
|
||||
)
|
||||
|
||||
|
||||
class Extension(Sequence):
|
||||
schema = (
|
||||
("extnID", ObjectIdentifier()),
|
||||
("critical", Boolean(default=False)),
|
||||
("extnValue", OctetString()),
|
||||
)
|
||||
|
||||
|
||||
class Extensions(SequenceOf):
|
||||
schema = Extension()
|
||||
bounds = (1, float("+inf"))
|
||||
|
||||
|
||||
class TBSCertificate(Sequence):
|
||||
schema = (
|
||||
("version", Version(expl=tag_ctxc(0), default="v1")),
|
||||
("serialNumber", CertificateSerialNumber()),
|
||||
("signature", AlgorithmIdentifier()),
|
||||
("issuer", Name()),
|
||||
("validity", Validity()),
|
||||
("subject", Name()),
|
||||
("subjectPublicKeyInfo", SubjectPublicKeyInfo()),
|
||||
("issuerUniqueID", UniqueIdentifier(impl=tag_ctxp(1), optional=True)),
|
||||
("subjectUniqueID", UniqueIdentifier(impl=tag_ctxp(2), optional=True)),
|
||||
("extensions", Extensions(expl=tag_ctxc(3), optional=True)),
|
||||
)
|
||||
|
||||
|
||||
class Certificate(Sequence):
|
||||
schema = (
|
||||
("tbsCertificate", TBSCertificate()),
|
||||
("signatureAlgorithm", AlgorithmIdentifier()),
|
||||
("signatureValue", BitString()),
|
||||
)
|
||||
|
||||
|
||||
class RevokedCertificates(SequenceOf):
|
||||
# schema = RevokedCertificate()
|
||||
schema = OctetString() # dummy
|
||||
|
||||
|
||||
class TBSCertList(Sequence):
|
||||
schema = (
|
||||
("version", Version(optional=True)),
|
||||
("signature", AlgorithmIdentifier()),
|
||||
("issuer", Name()),
|
||||
("thisUpdate", Time()),
|
||||
("nextUpdate", Time(optional=True)),
|
||||
("revokedCertificates", RevokedCertificates(optional=True)),
|
||||
("crlExtensions", Extensions(expl=tag_ctxc(0), optional=True)),
|
||||
)
|
||||
|
||||
|
||||
class CertificateList(Sequence):
|
||||
schema = (
|
||||
("tbsCertList", TBSCertList()),
|
||||
("signatureAlgorithm", AlgorithmIdentifier()),
|
||||
("signatureValue", BitString()),
|
||||
)
|
||||
|
||||
|
||||
class GeneralName(Choice):
|
||||
schema = (
|
||||
# ("otherName", AnotherName(impl=tag_ctxc(0))),
|
||||
# ("rfc822Name", IA5String(impl=tag_ctxp(1))),
|
||||
("dNSName", IA5String(impl=tag_ctxp(2))),
|
||||
# ("x400Address", ORAddress(impl=tag_ctxp(3))),
|
||||
# ("x400Address", OctetString(impl=tag_ctxp(3))),
|
||||
# ("directoryName", Name(expl=tag_ctxc(4))),
|
||||
# ("ediPartyName", EDIPartyName(impl=tag_ctxc(5))),
|
||||
# ("uniformResourceIdentifier", IA5String(impl=tag_ctxp(6))),
|
||||
# ("iPAddress", OctetString(impl=tag_ctxp(7))),
|
||||
# ("registeredID", ObjectIdentifier(impl=tag_ctxp(8))),
|
||||
)
|
||||
|
||||
|
||||
class GeneralNames(SequenceOf):
|
||||
schema = GeneralName()
|
||||
bounds = (1, float("+inf"))
|
||||
|
||||
|
||||
class SubjectAltName(GeneralNames):
|
||||
pass
|
||||
|
||||
|
||||
class AuthorityKeyIdentifier(Sequence):
|
||||
schema = (
|
||||
("keyIdentifier", KeyIdentifier(impl=tag_ctxp(0), optional=True)),
|
||||
# ("authorityCertIssuer", GeneralNames(impl=tag_ctxc(1), optional=True)),
|
||||
# (
|
||||
# "authorityCertSerialNumber",
|
||||
# CertificateSerialNumber(impl=tag_ctxp(2), optional=True),
|
||||
# ),
|
||||
)
|
||||
|
||||
|
||||
class KeyUsage(BitString):
|
||||
schema = (
|
||||
("digitalSignature", 0),
|
||||
("nonRepudiation", 1),
|
||||
("keyEncipherment", 2),
|
||||
("dataEncipherment", 3),
|
||||
("keyAgreement", 4),
|
||||
("keyCertSign", 5),
|
||||
("cRLSign", 6),
|
||||
("encipherOnly", 7),
|
||||
("decipherOnly", 8),
|
||||
)
|
||||
@ -1,457 +0,0 @@
|
||||
# coding: utf-8
|
||||
# PyGOST -- Pure Python GOST cryptographic functions library
|
||||
# Copyright (C) 2015-2023 Sergey Matveev <stargrave@stargrave.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, version 3 of the License.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
"""GOST 28147-89 block cipher
|
||||
|
||||
This is implementation of :rfc:`5830` ECB, CNT, CFB and :rfc:`4357`
|
||||
CBC modes of operation. N1, N2, K names are taken according to
|
||||
specification's terminology. CNT and CFB modes can work with arbitrary
|
||||
data lengths.
|
||||
"""
|
||||
|
||||
from functools import partial
|
||||
|
||||
from pygost.gost3413 import pad2
|
||||
from pygost.gost3413 import pad_size
|
||||
from pygost.gost3413 import unpad2
|
||||
from pygost.utils import hexdec
|
||||
from pygost.utils import strxor
|
||||
from pygost.utils import xrange
|
||||
|
||||
|
||||
KEYSIZE = 32
|
||||
BLOCKSIZE = 8
|
||||
C1 = 0x01010104
|
||||
C2 = 0x01010101
|
||||
|
||||
# Sequence of K_i S-box applying for encryption and decryption
|
||||
SEQ_ENCRYPT = (
|
||||
0, 1, 2, 3, 4, 5, 6, 7,
|
||||
0, 1, 2, 3, 4, 5, 6, 7,
|
||||
0, 1, 2, 3, 4, 5, 6, 7,
|
||||
7, 6, 5, 4, 3, 2, 1, 0,
|
||||
)
|
||||
SEQ_DECRYPT = (
|
||||
0, 1, 2, 3, 4, 5, 6, 7,
|
||||
7, 6, 5, 4, 3, 2, 1, 0,
|
||||
7, 6, 5, 4, 3, 2, 1, 0,
|
||||
7, 6, 5, 4, 3, 2, 1, 0,
|
||||
)
|
||||
|
||||
# S-box parameters
|
||||
DEFAULT_SBOX = "id-Gost28147-89-CryptoPro-A-ParamSet"
|
||||
SBOXES = {
|
||||
"id-Gost28147-89-TestParamSet": (
|
||||
(4, 2, 15, 5, 9, 1, 0, 8, 14, 3, 11, 12, 13, 7, 10, 6),
|
||||
(12, 9, 15, 14, 8, 1, 3, 10, 2, 7, 4, 13, 6, 0, 11, 5),
|
||||
(13, 8, 14, 12, 7, 3, 9, 10, 1, 5, 2, 4, 6, 15, 0, 11),
|
||||
(14, 9, 11, 2, 5, 15, 7, 1, 0, 13, 12, 6, 10, 4, 3, 8),
|
||||
(3, 14, 5, 9, 6, 8, 0, 13, 10, 11, 7, 12, 2, 1, 15, 4),
|
||||
(8, 15, 6, 11, 1, 9, 12, 5, 13, 3, 7, 10, 0, 14, 2, 4),
|
||||
(9, 11, 12, 0, 3, 6, 7, 5, 4, 8, 14, 15, 1, 10, 2, 13),
|
||||
(12, 6, 5, 2, 11, 0, 9, 13, 3, 14, 7, 10, 15, 4, 1, 8),
|
||||
),
|
||||
"id-Gost28147-89-CryptoPro-A-ParamSet": (
|
||||
(9, 6, 3, 2, 8, 11, 1, 7, 10, 4, 14, 15, 12, 0, 13, 5),
|
||||
(3, 7, 14, 9, 8, 10, 15, 0, 5, 2, 6, 12, 11, 4, 13, 1),
|
||||
(14, 4, 6, 2, 11, 3, 13, 8, 12, 15, 5, 10, 0, 7, 1, 9),
|
||||
(14, 7, 10, 12, 13, 1, 3, 9, 0, 2, 11, 4, 15, 8, 5, 6),
|
||||
(11, 5, 1, 9, 8, 13, 15, 0, 14, 4, 2, 3, 12, 7, 10, 6),
|
||||
(3, 10, 13, 12, 1, 2, 0, 11, 7, 5, 9, 4, 8, 15, 14, 6),
|
||||
(1, 13, 2, 9, 7, 10, 6, 0, 8, 12, 4, 5, 15, 3, 11, 14),
|
||||
(11, 10, 15, 5, 0, 12, 14, 8, 6, 2, 3, 9, 1, 7, 13, 4),
|
||||
),
|
||||
"id-Gost28147-89-CryptoPro-B-ParamSet": (
|
||||
(8, 4, 11, 1, 3, 5, 0, 9, 2, 14, 10, 12, 13, 6, 7, 15),
|
||||
(0, 1, 2, 10, 4, 13, 5, 12, 9, 7, 3, 15, 11, 8, 6, 14),
|
||||
(14, 12, 0, 10, 9, 2, 13, 11, 7, 5, 8, 15, 3, 6, 1, 4),
|
||||
(7, 5, 0, 13, 11, 6, 1, 2, 3, 10, 12, 15, 4, 14, 9, 8),
|
||||
(2, 7, 12, 15, 9, 5, 10, 11, 1, 4, 0, 13, 6, 8, 14, 3),
|
||||
(8, 3, 2, 6, 4, 13, 14, 11, 12, 1, 7, 15, 10, 0, 9, 5),
|
||||
(5, 2, 10, 11, 9, 1, 12, 3, 7, 4, 13, 0, 6, 15, 8, 14),
|
||||
(0, 4, 11, 14, 8, 3, 7, 1, 10, 2, 9, 6, 15, 13, 5, 12),
|
||||
),
|
||||
"id-Gost28147-89-CryptoPro-C-ParamSet": (
|
||||
(1, 11, 12, 2, 9, 13, 0, 15, 4, 5, 8, 14, 10, 7, 6, 3),
|
||||
(0, 1, 7, 13, 11, 4, 5, 2, 8, 14, 15, 12, 9, 10, 6, 3),
|
||||
(8, 2, 5, 0, 4, 9, 15, 10, 3, 7, 12, 13, 6, 14, 1, 11),
|
||||
(3, 6, 0, 1, 5, 13, 10, 8, 11, 2, 9, 7, 14, 15, 12, 4),
|
||||
(8, 13, 11, 0, 4, 5, 1, 2, 9, 3, 12, 14, 6, 15, 10, 7),
|
||||
(12, 9, 11, 1, 8, 14, 2, 4, 7, 3, 6, 5, 10, 0, 15, 13),
|
||||
(10, 9, 6, 8, 13, 14, 2, 0, 15, 3, 5, 11, 4, 1, 12, 7),
|
||||
(7, 4, 0, 5, 10, 2, 15, 14, 12, 6, 1, 11, 13, 9, 3, 8),
|
||||
),
|
||||
"id-Gost28147-89-CryptoPro-D-ParamSet": (
|
||||
(15, 12, 2, 10, 6, 4, 5, 0, 7, 9, 14, 13, 1, 11, 8, 3),
|
||||
(11, 6, 3, 4, 12, 15, 14, 2, 7, 13, 8, 0, 5, 10, 9, 1),
|
||||
(1, 12, 11, 0, 15, 14, 6, 5, 10, 13, 4, 8, 9, 3, 7, 2),
|
||||
(1, 5, 14, 12, 10, 7, 0, 13, 6, 2, 11, 4, 9, 3, 15, 8),
|
||||
(0, 12, 8, 9, 13, 2, 10, 11, 7, 3, 6, 5, 4, 14, 15, 1),
|
||||
(8, 0, 15, 3, 2, 5, 14, 11, 1, 10, 4, 7, 12, 9, 13, 6),
|
||||
(3, 0, 6, 15, 1, 14, 9, 2, 13, 8, 12, 4, 11, 10, 5, 7),
|
||||
(1, 10, 6, 8, 15, 11, 0, 4, 12, 3, 5, 9, 7, 13, 2, 14),
|
||||
),
|
||||
"id-tc26-gost-28147-param-Z": (
|
||||
(12, 4, 6, 2, 10, 5, 11, 9, 14, 8, 13, 7, 0, 3, 15, 1),
|
||||
(6, 8, 2, 3, 9, 10, 5, 12, 1, 14, 4, 7, 11, 13, 0, 15),
|
||||
(11, 3, 5, 8, 2, 15, 10, 13, 14, 1, 7, 4, 12, 9, 6, 0),
|
||||
(12, 8, 2, 1, 13, 4, 15, 6, 7, 0, 10, 5, 3, 14, 9, 11),
|
||||
(7, 15, 5, 10, 8, 1, 6, 13, 0, 9, 3, 14, 11, 4, 2, 12),
|
||||
(5, 13, 15, 6, 9, 2, 12, 10, 11, 7, 8, 1, 4, 3, 14, 0),
|
||||
(8, 14, 2, 5, 6, 9, 1, 12, 15, 4, 11, 0, 13, 10, 3, 7),
|
||||
(1, 7, 14, 13, 0, 5, 8, 3, 4, 15, 10, 6, 9, 12, 11, 2),
|
||||
),
|
||||
"id-GostR3411-94-TestParamSet": (
|
||||
(4, 10, 9, 2, 13, 8, 0, 14, 6, 11, 1, 12, 7, 15, 5, 3),
|
||||
(14, 11, 4, 12, 6, 13, 15, 10, 2, 3, 8, 1, 0, 7, 5, 9),
|
||||
(5, 8, 1, 13, 10, 3, 4, 2, 14, 15, 12, 7, 6, 0, 9, 11),
|
||||
(7, 13, 10, 1, 0, 8, 9, 15, 14, 4, 6, 12, 11, 2, 5, 3),
|
||||
(6, 12, 7, 1, 5, 15, 13, 8, 4, 10, 9, 14, 0, 3, 11, 2),
|
||||
(4, 11, 10, 0, 7, 2, 1, 13, 3, 6, 8, 5, 9, 12, 15, 14),
|
||||
(13, 11, 4, 1, 3, 15, 5, 9, 0, 10, 14, 7, 6, 8, 2, 12),
|
||||
(1, 15, 13, 0, 5, 7, 10, 4, 9, 2, 3, 14, 6, 11, 8, 12),
|
||||
),
|
||||
"id-GostR3411-94-CryptoProParamSet": (
|
||||
(10, 4, 5, 6, 8, 1, 3, 7, 13, 12, 14, 0, 9, 2, 11, 15),
|
||||
(5, 15, 4, 0, 2, 13, 11, 9, 1, 7, 6, 3, 12, 14, 10, 8),
|
||||
(7, 15, 12, 14, 9, 4, 1, 0, 3, 11, 5, 2, 6, 10, 8, 13),
|
||||
(4, 10, 7, 12, 0, 15, 2, 8, 14, 1, 6, 5, 13, 11, 9, 3),
|
||||
(7, 6, 4, 11, 9, 12, 2, 10, 1, 8, 0, 14, 15, 13, 3, 5),
|
||||
(7, 6, 2, 4, 13, 9, 15, 0, 10, 1, 5, 11, 8, 14, 12, 3),
|
||||
(13, 14, 4, 1, 7, 0, 5, 10, 3, 12, 8, 15, 6, 2, 9, 11),
|
||||
(1, 3, 10, 9, 5, 11, 4, 15, 8, 6, 7, 14, 13, 0, 2, 12),
|
||||
),
|
||||
"EACParamSet": (
|
||||
(11, 4, 8, 10, 9, 7, 0, 3, 1, 6, 2, 15, 14, 5, 12, 13),
|
||||
(1, 7, 14, 9, 11, 3, 15, 12, 0, 5, 4, 6, 13, 10, 8, 2),
|
||||
(7, 3, 1, 9, 2, 4, 13, 15, 8, 10, 12, 6, 5, 0, 11, 14),
|
||||
(10, 5, 15, 7, 14, 11, 3, 9, 2, 8, 1, 12, 0, 4, 6, 13),
|
||||
(0, 14, 6, 11, 9, 3, 8, 4, 12, 15, 10, 5, 13, 7, 1, 2),
|
||||
(9, 2, 11, 12, 0, 4, 5, 6, 3, 15, 13, 8, 1, 7, 14, 10),
|
||||
(4, 0, 14, 1, 5, 11, 8, 3, 12, 2, 9, 7, 6, 10, 13, 15),
|
||||
(7, 14, 12, 13, 9, 4, 8, 15, 10, 2, 6, 0, 3, 11, 5, 1),
|
||||
),
|
||||
}
|
||||
SBOXES["AppliedCryptography"] = SBOXES["id-GostR3411-94-TestParamSet"]
|
||||
|
||||
|
||||
def _K(s, _in):
|
||||
"""S-box substitution
|
||||
|
||||
:param s: S-box
|
||||
:param _in: 32-bit word
|
||||
:returns: substituted 32-bit word
|
||||
"""
|
||||
return (
|
||||
(s[0][(_in >> 0) & 0x0F] << 0) +
|
||||
(s[1][(_in >> 4) & 0x0F] << 4) +
|
||||
(s[2][(_in >> 8) & 0x0F] << 8) +
|
||||
(s[3][(_in >> 12) & 0x0F] << 12) +
|
||||
(s[4][(_in >> 16) & 0x0F] << 16) +
|
||||
(s[5][(_in >> 20) & 0x0F] << 20) +
|
||||
(s[6][(_in >> 24) & 0x0F] << 24) +
|
||||
(s[7][(_in >> 28) & 0x0F] << 28)
|
||||
)
|
||||
|
||||
|
||||
def block2ns(data):
|
||||
"""Convert block to N1 and N2 integers
|
||||
"""
|
||||
data = bytearray(data)
|
||||
return (
|
||||
data[0] | data[1] << 8 | data[2] << 16 | data[3] << 24,
|
||||
data[4] | data[5] << 8 | data[6] << 16 | data[7] << 24,
|
||||
)
|
||||
|
||||
|
||||
def ns2block(ns):
|
||||
"""Convert N1 and N2 integers to 8-byte block
|
||||
"""
|
||||
n1, n2 = ns
|
||||
return bytes(bytearray((
|
||||
(n2 >> 0) & 0xFF, (n2 >> 8) & 0xFF, (n2 >> 16) & 0xFF, (n2 >> 24) & 0xFF,
|
||||
(n1 >> 0) & 0xFF, (n1 >> 8) & 0xFF, (n1 >> 16) & 0xFF, (n1 >> 24) & 0xFF,
|
||||
)))
|
||||
|
||||
|
||||
def _shift11(x):
|
||||
"""11-bit cyclic shift
|
||||
"""
|
||||
return ((x << 11) & (2 ** 32 - 1)) | ((x >> (32 - 11)) & (2 ** 32 - 1))
|
||||
|
||||
|
||||
def validate_key(key):
|
||||
if len(key) != KEYSIZE:
|
||||
raise ValueError("Invalid key size")
|
||||
|
||||
|
||||
def validate_iv(iv):
|
||||
if len(iv) != BLOCKSIZE:
|
||||
raise ValueError("Invalid IV size")
|
||||
|
||||
|
||||
def validate_sbox(sbox):
|
||||
if sbox not in SBOXES:
|
||||
raise ValueError("Unknown sbox supplied")
|
||||
|
||||
|
||||
def xcrypt(seq, sbox, key, ns):
|
||||
"""Perform full-round single-block operation
|
||||
|
||||
:param seq: sequence of K_i S-box applying (either encrypt or decrypt)
|
||||
:param sbox: S-box parameters to use
|
||||
:type sbox: str, SBOXES'es key
|
||||
:param bytes key: 256-bit encryption key
|
||||
:param ns: N1 and N2 integers
|
||||
:type ns: (int, int)
|
||||
:returns: resulting N1 and N2
|
||||
:rtype: (int, int)
|
||||
"""
|
||||
s = SBOXES[sbox]
|
||||
w = bytearray(key)
|
||||
x = [
|
||||
w[0 + i * 4] |
|
||||
w[1 + i * 4] << 8 |
|
||||
w[2 + i * 4] << 16 |
|
||||
w[3 + i * 4] << 24 for i in range(8)
|
||||
]
|
||||
n1, n2 = ns
|
||||
for i in seq:
|
||||
n1, n2 = _shift11(_K(s, (n1 + x[i]) % (2 ** 32))) ^ n2, n1
|
||||
return n1, n2
|
||||
|
||||
|
||||
def encrypt(sbox, key, ns):
|
||||
"""Encrypt single block
|
||||
"""
|
||||
return xcrypt(SEQ_ENCRYPT, sbox, key, ns)
|
||||
|
||||
|
||||
def decrypt(sbox, key, ns):
|
||||
"""Decrypt single block
|
||||
"""
|
||||
return xcrypt(SEQ_DECRYPT, sbox, key, ns)
|
||||
|
||||
|
||||
def ecb(key, data, action, sbox=DEFAULT_SBOX):
|
||||
"""ECB mode of operation
|
||||
|
||||
:param bytes key: encryption key
|
||||
:param data: plaintext
|
||||
:type data: bytes, multiple of BLOCKSIZE
|
||||
:param func action: "encrypt"/"decrypt"
|
||||
:param sbox: S-box parameters to use
|
||||
:type sbox: str, SBOXES'es key
|
||||
:returns: ciphertext
|
||||
:rtype: bytes
|
||||
"""
|
||||
validate_key(key)
|
||||
validate_sbox(sbox)
|
||||
if not data or len(data) % BLOCKSIZE != 0:
|
||||
raise ValueError("Data is not blocksize aligned")
|
||||
result = []
|
||||
for i in xrange(0, len(data), BLOCKSIZE):
|
||||
result.append(ns2block(action(
|
||||
sbox, key, block2ns(data[i:i + BLOCKSIZE])
|
||||
)))
|
||||
return b"".join(result)
|
||||
|
||||
|
||||
ecb_encrypt = partial(ecb, action=encrypt)
|
||||
ecb_decrypt = partial(ecb, action=decrypt)
|
||||
|
||||
|
||||
def cbc_encrypt(key, data, iv=8 * b"\x00", pad=True, sbox=DEFAULT_SBOX, mesh=False):
|
||||
"""CBC encryption mode of operation
|
||||
|
||||
:param bytes key: encryption key
|
||||
:param bytes data: plaintext
|
||||
:param iv: initialization vector
|
||||
:type iv: bytes, BLOCKSIZE length
|
||||
:type bool pad: perform ISO/IEC 7816-4 padding
|
||||
:param sbox: S-box parameters to use
|
||||
:type sbox: str, SBOXES'es key
|
||||
:param bool mesh: enable key meshing
|
||||
:returns: ciphertext
|
||||
:rtype: bytes
|
||||
|
||||
34.13-2015 padding method 2 is used.
|
||||
"""
|
||||
validate_key(key)
|
||||
validate_iv(iv)
|
||||
validate_sbox(sbox)
|
||||
if not data:
|
||||
raise ValueError("No data supplied")
|
||||
if pad:
|
||||
data = pad2(data, BLOCKSIZE)
|
||||
if len(data) % BLOCKSIZE != 0:
|
||||
raise ValueError("Data is not blocksize aligned")
|
||||
ciphertext = [iv]
|
||||
for i in xrange(0, len(data), BLOCKSIZE):
|
||||
if mesh and i >= MESH_MAX_DATA and i % MESH_MAX_DATA == 0:
|
||||
key, _ = meshing(key, iv, sbox=sbox)
|
||||
ciphertext.append(ns2block(encrypt(sbox, key, block2ns(
|
||||
strxor(ciphertext[-1], data[i:i + BLOCKSIZE])
|
||||
))))
|
||||
return b"".join(ciphertext)
|
||||
|
||||
|
||||
def cbc_decrypt(key, data, pad=True, sbox=DEFAULT_SBOX, mesh=False):
|
||||
"""CBC decryption mode of operation
|
||||
|
||||
:param bytes key: encryption key
|
||||
:param bytes data: ciphertext
|
||||
:type bool pad: perform ISO/IEC 7816-4 unpadding after decryption
|
||||
:param sbox: S-box parameters to use
|
||||
:type sbox: str, SBOXES'es key
|
||||
:param bool mesh: enable key meshing
|
||||
:returns: plaintext
|
||||
:rtype: bytes
|
||||
"""
|
||||
validate_key(key)
|
||||
validate_sbox(sbox)
|
||||
if not data or len(data) % BLOCKSIZE != 0:
|
||||
raise ValueError("Data is not blocksize aligned")
|
||||
if len(data) < 2 * BLOCKSIZE:
|
||||
raise ValueError("There is no either data, or IV in ciphertext")
|
||||
iv = data[:BLOCKSIZE]
|
||||
plaintext = []
|
||||
for i in xrange(BLOCKSIZE, len(data), BLOCKSIZE):
|
||||
if (
|
||||
mesh and
|
||||
(i - BLOCKSIZE) >= MESH_MAX_DATA and
|
||||
(i - BLOCKSIZE) % MESH_MAX_DATA == 0
|
||||
):
|
||||
key, _ = meshing(key, iv, sbox=sbox)
|
||||
plaintext.append(strxor(
|
||||
ns2block(decrypt(sbox, key, block2ns(data[i:i + BLOCKSIZE]))),
|
||||
data[i - BLOCKSIZE:i],
|
||||
))
|
||||
if pad:
|
||||
plaintext[-1] = unpad2(plaintext[-1], BLOCKSIZE)
|
||||
return b"".join(plaintext)
|
||||
|
||||
|
||||
def cnt(key, data, iv=8 * b"\x00", sbox=DEFAULT_SBOX):
|
||||
"""Counter mode of operation
|
||||
|
||||
:param bytes key: encryption key
|
||||
:param bytes data: plaintext
|
||||
:param iv: initialization vector
|
||||
:type iv: bytes, BLOCKSIZE length
|
||||
:param sbox: S-box parameters to use
|
||||
:type sbox: str, SBOXES'es key
|
||||
:returns: ciphertext
|
||||
:rtype: bytes
|
||||
|
||||
For decryption you use the same function again.
|
||||
"""
|
||||
validate_key(key)
|
||||
validate_iv(iv)
|
||||
validate_sbox(sbox)
|
||||
if not data:
|
||||
raise ValueError("No data supplied")
|
||||
n2, n1 = encrypt(sbox, key, block2ns(iv))
|
||||
gamma = []
|
||||
for _ in xrange(0, len(data) + pad_size(len(data), BLOCKSIZE), BLOCKSIZE):
|
||||
n1 = (n1 + C2) % (2 ** 32)
|
||||
n2 = (n2 + C1) % (2 ** 32 - 1)
|
||||
gamma.append(ns2block(encrypt(sbox, key, (n1, n2))))
|
||||
return strxor(b"".join(gamma), data)
|
||||
|
||||
|
||||
MESH_CONST = hexdec("6900722264C904238D3ADB9646E92AC418FEAC9400ED0712C086DCC2EF4CA92B")
|
||||
MESH_MAX_DATA = 1024
|
||||
|
||||
|
||||
def meshing(key, iv, sbox=DEFAULT_SBOX):
|
||||
""":rfc:`4357` key meshing
|
||||
"""
|
||||
key = ecb_decrypt(key, MESH_CONST, sbox=sbox)
|
||||
iv = ecb_encrypt(key, iv, sbox=sbox)
|
||||
return key, iv
|
||||
|
||||
|
||||
def cfb_encrypt(key, data, iv=8 * b"\x00", sbox=DEFAULT_SBOX, mesh=False):
|
||||
"""CFB encryption mode of operation
|
||||
|
||||
:param bytes key: encryption key
|
||||
:param bytes data: plaintext
|
||||
:param iv: initialization vector
|
||||
:type iv: bytes, BLOCKSIZE length
|
||||
:param sbox: S-box parameters to use
|
||||
:type sbox: str, SBOXES'es key
|
||||
:param bool mesh: enable key meshing
|
||||
:returns: ciphertext
|
||||
:rtype: bytes
|
||||
"""
|
||||
validate_key(key)
|
||||
validate_iv(iv)
|
||||
validate_sbox(sbox)
|
||||
if not data:
|
||||
raise ValueError("No data supplied")
|
||||
ciphertext = [iv]
|
||||
for i in xrange(0, len(data) + pad_size(len(data), BLOCKSIZE), BLOCKSIZE):
|
||||
if mesh and i >= MESH_MAX_DATA and i % MESH_MAX_DATA == 0:
|
||||
key, iv = meshing(key, ciphertext[-1], sbox=sbox)
|
||||
ciphertext.append(strxor(
|
||||
data[i:i + BLOCKSIZE],
|
||||
ns2block(encrypt(sbox, key, block2ns(iv))),
|
||||
))
|
||||
continue
|
||||
ciphertext.append(strxor(
|
||||
data[i:i + BLOCKSIZE],
|
||||
ns2block(encrypt(sbox, key, block2ns(ciphertext[-1]))),
|
||||
))
|
||||
return b"".join(ciphertext[1:])
|
||||
|
||||
|
||||
def cfb_decrypt(key, data, iv=8 * b"\x00", sbox=DEFAULT_SBOX, mesh=False):
|
||||
"""CFB decryption mode of operation
|
||||
|
||||
:param bytes key: encryption key
|
||||
:param bytes data: plaintext
|
||||
:param iv: initialization vector
|
||||
:type iv: bytes, BLOCKSIZE length
|
||||
:param sbox: S-box parameters to use
|
||||
:type sbox: str, SBOXES'es key
|
||||
:param bool mesh: enable key meshing
|
||||
:returns: ciphertext
|
||||
:rtype: bytes
|
||||
"""
|
||||
validate_key(key)
|
||||
validate_iv(iv)
|
||||
validate_sbox(sbox)
|
||||
if not data:
|
||||
raise ValueError("No data supplied")
|
||||
plaintext = []
|
||||
data = iv + data
|
||||
for i in xrange(BLOCKSIZE, len(data) + pad_size(len(data), BLOCKSIZE), BLOCKSIZE):
|
||||
if (
|
||||
mesh and
|
||||
(i - BLOCKSIZE) >= MESH_MAX_DATA and
|
||||
(i - BLOCKSIZE) % MESH_MAX_DATA == 0
|
||||
):
|
||||
key, iv = meshing(key, data[i - BLOCKSIZE:i], sbox=sbox)
|
||||
plaintext.append(strxor(
|
||||
data[i:i + BLOCKSIZE],
|
||||
ns2block(encrypt(sbox, key, block2ns(iv))),
|
||||
))
|
||||
continue
|
||||
plaintext.append(strxor(
|
||||
data[i:i + BLOCKSIZE],
|
||||
ns2block(encrypt(sbox, key, block2ns(data[i - BLOCKSIZE:i]))),
|
||||
))
|
||||
return b"".join(plaintext)
|
||||
@ -1,99 +0,0 @@
|
||||
# coding: utf-8
|
||||
# PyGOST -- Pure Python GOST cryptographic functions library
|
||||
# Copyright (C) 2015-2023 Sergey Matveev <stargrave@stargrave.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, version 3 of the License.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
"""GOST 28147-89 MAC
|
||||
"""
|
||||
|
||||
from copy import copy
|
||||
|
||||
from pygost.gost28147 import block2ns
|
||||
from pygost.gost28147 import BLOCKSIZE
|
||||
from pygost.gost28147 import DEFAULT_SBOX
|
||||
from pygost.gost28147 import ns2block
|
||||
from pygost.gost28147 import validate_iv
|
||||
from pygost.gost28147 import validate_key
|
||||
from pygost.gost28147 import validate_sbox
|
||||
from pygost.gost28147 import xcrypt
|
||||
from pygost.gost3413 import pad1
|
||||
from pygost.iface import PEP247
|
||||
from pygost.utils import strxor
|
||||
from pygost.utils import xrange
|
||||
|
||||
digest_size = 8
|
||||
SEQ_MAC = (
|
||||
0, 1, 2, 3, 4, 5, 6, 7,
|
||||
0, 1, 2, 3, 4, 5, 6, 7,
|
||||
)
|
||||
|
||||
|
||||
class MAC(PEP247):
|
||||
"""GOST 28147-89 MAC mode of operation
|
||||
|
||||
>>> m = MAC(key=key)
|
||||
>>> m.update("some data")
|
||||
>>> m.update("another data")
|
||||
>>> m.hexdigest()[:8]
|
||||
'a687a08b'
|
||||
"""
|
||||
digest_size = digest_size
|
||||
|
||||
def __init__(self, key, data=b"", iv=8 * b"\x00", sbox=DEFAULT_SBOX):
|
||||
"""
|
||||
:param key: authentication key
|
||||
:type key: bytes, 32 bytes
|
||||
:param iv: initialization vector
|
||||
:type iv: bytes, BLOCKSIZE length
|
||||
:param sbox: S-box parameters to use
|
||||
:type sbox: str, SBOXES'es key
|
||||
"""
|
||||
validate_key(key)
|
||||
validate_iv(iv)
|
||||
validate_sbox(sbox)
|
||||
self.key = key
|
||||
self.data = data
|
||||
self.iv = iv
|
||||
self.sbox = sbox
|
||||
|
||||
def copy(self):
|
||||
return MAC(self.key, copy(self.data), self.iv, self.sbox)
|
||||
|
||||
def update(self, data):
|
||||
"""Append data that has to be authenticated
|
||||
"""
|
||||
self.data += data
|
||||
|
||||
def digest(self):
|
||||
"""Get MAC tag of supplied data
|
||||
|
||||
You have to provide at least single byte of data.
|
||||
If you want to produce tag length of 3 bytes, then
|
||||
``digest()[:3]``.
|
||||
"""
|
||||
if not self.data:
|
||||
raise ValueError("No data processed")
|
||||
data = pad1(self.data, BLOCKSIZE)
|
||||
prev = block2ns(self.iv)[::-1]
|
||||
for i in xrange(0, len(data), BLOCKSIZE):
|
||||
prev = xcrypt(
|
||||
SEQ_MAC, self.sbox, self.key, block2ns(strxor(
|
||||
data[i:i + BLOCKSIZE],
|
||||
ns2block(prev),
|
||||
)),
|
||||
)[::-1]
|
||||
return ns2block(prev)
|
||||
|
||||
|
||||
def new(key, data=b"", iv=8 * b"\x00", sbox=DEFAULT_SBOX):
|
||||
return MAC(key, data, iv, sbox)
|
||||
@ -1,412 +0,0 @@
|
||||
# coding: utf-8
|
||||
# PyGOST -- Pure Python GOST cryptographic functions library
|
||||
# Copyright (C) 2015-2023 Sergey Matveev <stargrave@stargrave.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, version 3 of the License.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
"""GOST R 34.10 public-key signature function.
|
||||
|
||||
This is implementation of GOST R 34.10-2001 (:rfc:`5832`), GOST R
|
||||
34.10-2012 (:rfc:`7091`). The difference between 2001 and 2012 is the
|
||||
key, digest and signature lengths.
|
||||
"""
|
||||
|
||||
from os import urandom
|
||||
|
||||
from pygost.utils import bytes2long
|
||||
from pygost.utils import hexdec
|
||||
from pygost.utils import long2bytes
|
||||
from pygost.utils import modinvert
|
||||
|
||||
|
||||
def point_size(point):
|
||||
"""Determine is it either 256 or 512 bit point
|
||||
"""
|
||||
return (512 // 8) if point.bit_length() > 256 else (256 // 8)
|
||||
|
||||
|
||||
class GOST3410Curve(object):
|
||||
"""GOST 34.10 validated curve
|
||||
|
||||
>>> curve = CURVES["id-GostR3410-2001-TestParamSet"]
|
||||
>>> prv = prv_unmarshal(urandom(32))
|
||||
>>> signature = sign(curve, prv, GOST341194(data).digest())
|
||||
>>> pub = public_key(curve, prv)
|
||||
>>> verify(curve, pub, GOST341194(data).digest(), signature)
|
||||
True
|
||||
|
||||
:param long p: characteristic of the underlying prime field
|
||||
:param long q: elliptic curve subgroup order
|
||||
:param long a, b: coefficients of the equation of the elliptic curve in
|
||||
the canonical form
|
||||
:param long x, y: the coordinate of the point P (generator of the
|
||||
subgroup of order q) of the elliptic curve in
|
||||
the canonical form
|
||||
:param long e, d: coefficients of the equation of the elliptic curve in
|
||||
the twisted Edwards form
|
||||
:param str name: human-readable curve name
|
||||
"""
|
||||
|
||||
def __init__(self, p, q, a, b, x, y, cofactor=1, e=None, d=None, name=None):
|
||||
self.p = p
|
||||
self.q = q
|
||||
self.a = a
|
||||
self.b = b
|
||||
self.x = x
|
||||
self.y = y
|
||||
self.cofactor = cofactor
|
||||
self.e = e
|
||||
self.d = d
|
||||
if not self.contains((x, y)):
|
||||
raise ValueError("Invalid parameters")
|
||||
self._st = None
|
||||
self.name = name
|
||||
|
||||
@property
|
||||
def point_size(self):
|
||||
return point_size(self.p)
|
||||
|
||||
def __repr__(self):
|
||||
return "<%s: %s>" % (self.__class__.__name__, self.name)
|
||||
|
||||
def pos(self, v):
|
||||
"""Make positive number
|
||||
"""
|
||||
if v < 0:
|
||||
return v + self.p
|
||||
return v
|
||||
|
||||
def contains(self, point):
|
||||
"""Is point on the curve?
|
||||
|
||||
:type point: (long, long)
|
||||
"""
|
||||
x, y = point
|
||||
r1 = y * y % self.p
|
||||
r2 = ((x * x + self.a) * x + self.b) % self.p
|
||||
return r1 == self.pos(r2)
|
||||
|
||||
def _add(self, p1x, p1y, p2x, p2y):
|
||||
if p1x == p2x and p1y == p2y:
|
||||
# double
|
||||
t = ((3 * p1x * p1x + self.a) * modinvert(2 * p1y, self.p)) % self.p
|
||||
else:
|
||||
tx = self.pos(p2x - p1x) % self.p
|
||||
ty = self.pos(p2y - p1y) % self.p
|
||||
t = (ty * modinvert(tx, self.p)) % self.p
|
||||
tx = self.pos(t * t - p1x - p2x) % self.p
|
||||
ty = self.pos(t * (p1x - tx) - p1y) % self.p
|
||||
return tx, ty
|
||||
|
||||
def exp(self, degree, x=None, y=None):
|
||||
x = x or self.x
|
||||
y = y or self.y
|
||||
tx = x
|
||||
ty = y
|
||||
if degree == 0:
|
||||
raise ValueError("Bad degree value")
|
||||
degree -= 1
|
||||
while degree != 0:
|
||||
if degree & 1 == 1:
|
||||
tx, ty = self._add(tx, ty, x, y)
|
||||
degree = degree >> 1
|
||||
x, y = self._add(x, y, x, y)
|
||||
return tx, ty
|
||||
|
||||
def st(self):
|
||||
"""Compute s/t parameters for twisted Edwards curve points conversion
|
||||
"""
|
||||
if self.e is None or self.d is None:
|
||||
raise ValueError("Non twisted Edwards curve")
|
||||
if self._st is not None:
|
||||
return self._st
|
||||
self._st = (
|
||||
self.pos(self.e - self.d) * modinvert(4, self.p) % self.p,
|
||||
(self.e + self.d) * modinvert(6, self.p) % self.p,
|
||||
)
|
||||
return self._st
|
||||
|
||||
|
||||
CURVES = {
|
||||
"GostR3410_2001_ParamSet_cc": GOST3410Curve(
|
||||
p=bytes2long(hexdec("C0000000000000000000000000000000000000000000000000000000000003C7")),
|
||||
q=bytes2long(hexdec("5fffffffffffffffffffffffffffffff606117a2f4bde428b7458a54b6e87b85")),
|
||||
a=bytes2long(hexdec("C0000000000000000000000000000000000000000000000000000000000003c4")),
|
||||
b=bytes2long(hexdec("2d06B4265ebc749ff7d0f1f1f88232e81632e9088fd44b7787d5e407e955080c")),
|
||||
x=bytes2long(hexdec("0000000000000000000000000000000000000000000000000000000000000002")),
|
||||
y=bytes2long(hexdec("a20e034bf8813ef5c18d01105e726a17eb248b264ae9706f440bedc8ccb6b22c")),
|
||||
),
|
||||
"id-GostR3410-2001-TestParamSet": GOST3410Curve(
|
||||
p=bytes2long(hexdec("8000000000000000000000000000000000000000000000000000000000000431")),
|
||||
q=bytes2long(hexdec("8000000000000000000000000000000150FE8A1892976154C59CFC193ACCF5B3")),
|
||||
a=bytes2long(hexdec("0000000000000000000000000000000000000000000000000000000000000007")),
|
||||
b=bytes2long(hexdec("5FBFF498AA938CE739B8E022FBAFEF40563F6E6A3472FC2A514C0CE9DAE23B7E")),
|
||||
x=bytes2long(hexdec("0000000000000000000000000000000000000000000000000000000000000002")),
|
||||
y=bytes2long(hexdec("08E2A8A0E65147D4BD6316030E16D19C85C97F0A9CA267122B96ABBCEA7E8FC8")),
|
||||
),
|
||||
"id-tc26-gost-3410-12-256-paramSetA": GOST3410Curve(
|
||||
p=bytes2long(hexdec("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD97")),
|
||||
q=bytes2long(hexdec("400000000000000000000000000000000FD8CDDFC87B6635C115AF556C360C67")),
|
||||
a=bytes2long(hexdec("C2173F1513981673AF4892C23035A27CE25E2013BF95AA33B22C656F277E7335")),
|
||||
b=bytes2long(hexdec("295F9BAE7428ED9CCC20E7C359A9D41A22FCCD9108E17BF7BA9337A6F8AE9513")),
|
||||
x=bytes2long(hexdec("91E38443A5E82C0D880923425712B2BB658B9196932E02C78B2582FE742DAA28")),
|
||||
y=bytes2long(hexdec("32879423AB1A0375895786C4BB46E9565FDE0B5344766740AF268ADB32322E5C")),
|
||||
cofactor=4,
|
||||
e=0x01,
|
||||
d=bytes2long(hexdec("0605F6B7C183FA81578BC39CFAD518132B9DF62897009AF7E522C32D6DC7BFFB")),
|
||||
),
|
||||
"id-tc26-gost-3410-12-256-paramSetB": GOST3410Curve(
|
||||
p=bytes2long(hexdec("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD97")),
|
||||
q=bytes2long(hexdec("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6C611070995AD10045841B09B761B893")),
|
||||
a=bytes2long(hexdec("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD94")),
|
||||
b=bytes2long(hexdec("00000000000000000000000000000000000000000000000000000000000000a6")),
|
||||
x=bytes2long(hexdec("0000000000000000000000000000000000000000000000000000000000000001")),
|
||||
y=bytes2long(hexdec("8D91E471E0989CDA27DF505A453F2B7635294F2DDF23E3B122ACC99C9E9F1E14")),
|
||||
),
|
||||
"id-tc26-gost-3410-12-256-paramSetC": GOST3410Curve(
|
||||
p=bytes2long(hexdec("8000000000000000000000000000000000000000000000000000000000000C99")),
|
||||
q=bytes2long(hexdec("800000000000000000000000000000015F700CFFF1A624E5E497161BCC8A198F")),
|
||||
a=bytes2long(hexdec("8000000000000000000000000000000000000000000000000000000000000C96")),
|
||||
b=bytes2long(hexdec("3E1AF419A269A5F866A7D3C25C3DF80AE979259373FF2B182F49D4CE7E1BBC8B")),
|
||||
x=bytes2long(hexdec("0000000000000000000000000000000000000000000000000000000000000001")),
|
||||
y=bytes2long(hexdec("3FA8124359F96680B83D1C3EB2C070E5C545C9858D03ECFB744BF8D717717EFC")),
|
||||
),
|
||||
"id-tc26-gost-3410-12-256-paramSetD": GOST3410Curve(
|
||||
p=bytes2long(hexdec("9B9F605F5A858107AB1EC85E6B41C8AACF846E86789051D37998F7B9022D759B")),
|
||||
q=bytes2long(hexdec("9B9F605F5A858107AB1EC85E6B41C8AA582CA3511EDDFB74F02F3A6598980BB9")),
|
||||
a=bytes2long(hexdec("9B9F605F5A858107AB1EC85E6B41C8AACF846E86789051D37998F7B9022D7598")),
|
||||
b=bytes2long(hexdec("000000000000000000000000000000000000000000000000000000000000805a")),
|
||||
x=bytes2long(hexdec("0000000000000000000000000000000000000000000000000000000000000000")),
|
||||
y=bytes2long(hexdec("41ECE55743711A8C3CBF3783CD08C0EE4D4DC440D4641A8F366E550DFDB3BB67")),
|
||||
),
|
||||
"id-tc26-gost-3410-12-512-paramSetTest": GOST3410Curve(
|
||||
p=bytes2long(hexdec("4531ACD1FE0023C7550D267B6B2FEE80922B14B2FFB90F04D4EB7C09B5D2D15DF1D852741AF4704A0458047E80E4546D35B8336FAC224DD81664BBF528BE6373")),
|
||||
q=bytes2long(hexdec("4531ACD1FE0023C7550D267B6B2FEE80922B14B2FFB90F04D4EB7C09B5D2D15DA82F2D7ECB1DBAC719905C5EECC423F1D86E25EDBE23C595D644AAF187E6E6DF")),
|
||||
a=7,
|
||||
b=bytes2long(hexdec("1CFF0806A31116DA29D8CFA54E57EB748BC5F377E49400FDD788B649ECA1AC4361834013B2AD7322480A89CA58E0CF74BC9E540C2ADD6897FAD0A3084F302ADC")),
|
||||
x=bytes2long(hexdec("24D19CC64572EE30F396BF6EBBFD7A6C5213B3B3D7057CC825F91093A68CD762FD60611262CD838DC6B60AA7EEE804E28BC849977FAC33B4B530F1B120248A9A")),
|
||||
y=bytes2long(hexdec("2BB312A43BD2CE6E0D020613C857ACDDCFBF061E91E5F2C3F32447C259F39B2C83AB156D77F1496BF7EB3351E1EE4E43DC1A18B91B24640B6DBB92CB1ADD371E")),
|
||||
),
|
||||
"id-tc26-gost-3410-12-512-paramSetA": GOST3410Curve(
|
||||
p=bytes2long(hexdec("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDC7")),
|
||||
q=bytes2long(hexdec("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF27E69532F48D89116FF22B8D4E0560609B4B38ABFAD2B85DCACDB1411F10B275")),
|
||||
a=bytes2long(hexdec("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDC4")),
|
||||
b=bytes2long(hexdec("E8C2505DEDFC86DDC1BD0B2B6667F1DA34B82574761CB0E879BD081CFD0B6265EE3CB090F30D27614CB4574010DA90DD862EF9D4EBEE4761503190785A71C760")),
|
||||
x=bytes2long(hexdec("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003")),
|
||||
y=bytes2long(hexdec("7503CFE87A836AE3A61B8816E25450E6CE5E1C93ACF1ABC1778064FDCBEFA921DF1626BE4FD036E93D75E6A50E3A41E98028FE5FC235F5B889A589CB5215F2A4")),
|
||||
),
|
||||
"id-tc26-gost-3410-12-512-paramSetB": GOST3410Curve(
|
||||
p=bytes2long(hexdec("8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006F")),
|
||||
q=bytes2long(hexdec("800000000000000000000000000000000000000000000000000000000000000149A1EC142565A545ACFDB77BD9D40CFA8B996712101BEA0EC6346C54374F25BD")),
|
||||
a=bytes2long(hexdec("8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006C")),
|
||||
b=bytes2long(hexdec("687D1B459DC841457E3E06CF6F5E2517B97C7D614AF138BCBF85DC806C4B289F3E965D2DB1416D217F8B276FAD1AB69C50F78BEE1FA3106EFB8CCBC7C5140116")),
|
||||
x=bytes2long(hexdec("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002")),
|
||||
y=bytes2long(hexdec("1A8F7EDA389B094C2C071E3647A8940F3C123B697578C213BE6DD9E6C8EC7335DCB228FD1EDF4A39152CBCAAF8C0398828041055F94CEEEC7E21340780FE41BD")),
|
||||
),
|
||||
"id-tc26-gost-3410-12-512-paramSetC": GOST3410Curve(
|
||||
p=bytes2long(hexdec("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDC7")),
|
||||
q=bytes2long(hexdec("3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC98CDBA46506AB004C33A9FF5147502CC8EDA9E7A769A12694623CEF47F023ED")),
|
||||
a=bytes2long(hexdec("DC9203E514A721875485A529D2C722FB187BC8980EB866644DE41C68E143064546E861C0E2C9EDD92ADE71F46FCF50FF2AD97F951FDA9F2A2EB6546F39689BD3")),
|
||||
b=bytes2long(hexdec("B4C4EE28CEBC6C2C8AC12952CF37F16AC7EFB6A9F69F4B57FFDA2E4F0DE5ADE038CBC2FFF719D2C18DE0284B8BFEF3B52B8CC7A5F5BF0A3C8D2319A5312557E1")),
|
||||
x=bytes2long(hexdec("E2E31EDFC23DE7BDEBE241CE593EF5DE2295B7A9CBAEF021D385F7074CEA043AA27272A7AE602BF2A7B9033DB9ED3610C6FB85487EAE97AAC5BC7928C1950148")),
|
||||
y=bytes2long(hexdec("F5CE40D95B5EB899ABBCCFF5911CB8577939804D6527378B8C108C3D2090FF9BE18E2D33E3021ED2EF32D85822423B6304F726AA854BAE07D0396E9A9ADDC40F")),
|
||||
cofactor=4,
|
||||
e=0x01,
|
||||
d=bytes2long(hexdec("9E4F5D8C017D8D9F13A5CF3CDF5BFE4DAB402D54198E31EBDE28A0621050439CA6B39E0A515C06B304E2CE43E79E369E91A0CFC2BC2A22B4CA302DBB33EE7550")),
|
||||
),
|
||||
}
|
||||
CURVES["id-GostR3410-2001-CryptoPro-A-ParamSet"] = CURVES["id-tc26-gost-3410-12-256-paramSetB"]
|
||||
CURVES["id-GostR3410-2001-CryptoPro-B-ParamSet"] = CURVES["id-tc26-gost-3410-12-256-paramSetC"]
|
||||
CURVES["id-GostR3410-2001-CryptoPro-C-ParamSet"] = CURVES["id-tc26-gost-3410-12-256-paramSetD"]
|
||||
CURVES["id-GostR3410-2001-CryptoPro-XchA-ParamSet"] = CURVES["id-GostR3410-2001-CryptoPro-A-ParamSet"]
|
||||
CURVES["id-GostR3410-2001-CryptoPro-XchB-ParamSet"] = CURVES["id-GostR3410-2001-CryptoPro-C-ParamSet"]
|
||||
CURVES["id-tc26-gost-3410-2012-256-paramSetA"] = CURVES["id-tc26-gost-3410-12-256-paramSetA"]
|
||||
CURVES["id-tc26-gost-3410-2012-256-paramSetB"] = CURVES["id-tc26-gost-3410-12-256-paramSetB"]
|
||||
CURVES["id-tc26-gost-3410-2012-256-paramSetC"] = CURVES["id-tc26-gost-3410-12-256-paramSetC"]
|
||||
CURVES["id-tc26-gost-3410-2012-256-paramSetD"] = CURVES["id-tc26-gost-3410-12-256-paramSetD"]
|
||||
CURVES["id-tc26-gost-3410-2012-512-paramSetTest"] = CURVES["id-tc26-gost-3410-12-512-paramSetTest"]
|
||||
CURVES["id-tc26-gost-3410-2012-512-paramSetA"] = CURVES["id-tc26-gost-3410-12-512-paramSetA"]
|
||||
CURVES["id-tc26-gost-3410-2012-512-paramSetB"] = CURVES["id-tc26-gost-3410-12-512-paramSetB"]
|
||||
CURVES["id-tc26-gost-3410-2012-512-paramSetC"] = CURVES["id-tc26-gost-3410-12-512-paramSetC"]
|
||||
for _name, _curve in CURVES.items():
|
||||
_curve.name = _name
|
||||
DEFAULT_CURVE = CURVES["id-tc26-gost-3410-12-256-paramSetB"]
|
||||
|
||||
|
||||
def public_key(curve, prv, mask=None):
|
||||
"""Generate public key from the private one
|
||||
|
||||
:param GOST3410Curve curve: curve to use
|
||||
:param long prv: private key
|
||||
:returns: public key's parts, X and Y
|
||||
:rtype: (long, long)
|
||||
"""
|
||||
pub = curve.exp(prv)
|
||||
if mask is not None:
|
||||
pub = curve.exp(mask, pub[0], pub[1])
|
||||
return pub
|
||||
|
||||
|
||||
def sign(curve, prv, digest, rand=None, mask=None):
|
||||
"""Calculate signature for provided digest
|
||||
|
||||
:param GOST3410Curve curve: curve to use
|
||||
:param long prv: private key
|
||||
:param digest: digest for signing
|
||||
:type digest: bytes, 32 or 64 bytes
|
||||
:param rand: optional predefined random data used for k/r generation
|
||||
:type rand: bytes, 32 or 64 bytes
|
||||
:returns: signature, BE(S) || BE(R)
|
||||
:rtype: bytes, 64 or 128 bytes
|
||||
"""
|
||||
size = curve.point_size
|
||||
q = curve.q
|
||||
e = bytes2long(digest) % q
|
||||
if e == 0:
|
||||
e = 1
|
||||
while True:
|
||||
if rand is None:
|
||||
rand = urandom(size)
|
||||
elif len(rand) != size:
|
||||
raise ValueError("rand length != %d" % size)
|
||||
k = bytes2long(rand) % q
|
||||
if k == 0:
|
||||
continue
|
||||
r, y = curve.exp(k)
|
||||
if mask is not None:
|
||||
r, y = curve.exp(mask, x=r, y=y)
|
||||
r %= q
|
||||
if r == 0:
|
||||
continue
|
||||
d = prv * r
|
||||
k *= e
|
||||
s = d + k
|
||||
if mask is not None:
|
||||
s *= mask
|
||||
s %= q
|
||||
if s == 0:
|
||||
continue
|
||||
break
|
||||
return long2bytes(s, size) + long2bytes(r, size)
|
||||
|
||||
|
||||
def verify(curve, pub, digest, signature):
|
||||
"""Verify provided digest with the signature
|
||||
|
||||
:param GOST3410Curve curve: curve to use
|
||||
:type pub: (long, long)
|
||||
:param digest: digest needed to check
|
||||
:type digest: bytes, 32 or 64 bytes
|
||||
:param signature: signature to verify with
|
||||
:type signature: bytes, 64 or 128 bytes
|
||||
:rtype: bool
|
||||
"""
|
||||
size = curve.point_size
|
||||
if len(signature) != size * 2:
|
||||
raise ValueError("Invalid signature length")
|
||||
q = curve.q
|
||||
p = curve.p
|
||||
s = bytes2long(signature[:size])
|
||||
r = bytes2long(signature[size:])
|
||||
if r <= 0 or r >= q or s <= 0 or s >= q:
|
||||
return False
|
||||
e = bytes2long(digest) % curve.q
|
||||
if e == 0:
|
||||
e = 1
|
||||
v = modinvert(e, q)
|
||||
z1 = s * v % q
|
||||
z2 = q - r * v % q
|
||||
p1x, p1y = curve.exp(z1)
|
||||
q1x, q1y = curve.exp(z2, pub[0], pub[1])
|
||||
lm = q1x - p1x
|
||||
if lm < 0:
|
||||
lm += p
|
||||
lm = modinvert(lm, p)
|
||||
z1 = q1y - p1y
|
||||
lm = lm * z1 % p
|
||||
lm = lm * lm % p
|
||||
lm = lm - p1x - q1x
|
||||
lm = lm % p
|
||||
if lm < 0:
|
||||
lm += p
|
||||
lm %= q
|
||||
# This is not constant time comparison!
|
||||
return lm == r
|
||||
|
||||
|
||||
def prv_unmarshal(prv):
|
||||
"""Unmarshal little-endian private key
|
||||
|
||||
:param bytes prv: serialized private key
|
||||
:rtype: long
|
||||
|
||||
It is advisable to use :py:func:`pygost.gost3410.prv_marshal` to
|
||||
assure that key i in curve's Q field for better compatibility with
|
||||
some implementations.
|
||||
"""
|
||||
return bytes2long(prv[::-1])
|
||||
|
||||
|
||||
def prv_marshal(curve, prv):
|
||||
"""Marshal little-endian private key
|
||||
|
||||
:param GOST3410Curve curve: curve to use
|
||||
:param long prv: serialized private key
|
||||
:rtype: bytes
|
||||
|
||||
Key is in curve's Q field.
|
||||
"""
|
||||
return long2bytes(prv % curve.q, point_size(prv))[::-1]
|
||||
|
||||
|
||||
def pub_marshal(pub):
|
||||
"""Marshal public key
|
||||
|
||||
:type pub: (long, long)
|
||||
:rtype: bytes
|
||||
:returns: LE(X) || LE(Y)
|
||||
"""
|
||||
size = point_size(pub[0])
|
||||
return (long2bytes(pub[1], size) + long2bytes(pub[0], size))[::-1]
|
||||
|
||||
|
||||
def pub_unmarshal(pub):
|
||||
"""Unmarshal public key
|
||||
|
||||
:param pub: LE(X) || LE(Y)
|
||||
:type pub: bytes
|
||||
:rtype: (long, long)
|
||||
"""
|
||||
size = len(pub) // 2
|
||||
pub = pub[::-1]
|
||||
return (bytes2long(pub[size:]), bytes2long(pub[:size]))
|
||||
|
||||
|
||||
def uv2xy(curve, u, v):
|
||||
"""Convert twisted Edwards curve U,V coordinates to Weierstrass X,Y
|
||||
"""
|
||||
s, t = curve.st()
|
||||
k1 = (s * (1 + v)) % curve.p
|
||||
k2 = curve.pos(1 - v)
|
||||
x = t + k1 * modinvert(k2, curve.p)
|
||||
y = k1 * modinvert(u * k2, curve.p)
|
||||
return x % curve.p, y % curve.p
|
||||
|
||||
|
||||
def xy2uv(curve, x, y):
|
||||
"""Convert Weierstrass X,Y coordinates to twisted Edwards curve U,V
|
||||
"""
|
||||
s, t = curve.st()
|
||||
xmt = curve.pos(x - t)
|
||||
u = xmt * modinvert(y, curve.p)
|
||||
v = curve.pos(xmt - s) * modinvert(xmt + s, curve.p)
|
||||
return u % curve.p, v % curve.p
|
||||
@ -1,97 +0,0 @@
|
||||
# coding: utf-8
|
||||
# PyGOST -- Pure Python GOST cryptographic functions library
|
||||
# Copyright (C) 2015-2023 Sergey Matveev <stargrave@stargrave.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, version 3 of the License.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
"""Key agreement functions, VKO GOST R 34.10-2001/2012
|
||||
"""
|
||||
|
||||
from pygost.gost3410 import pub_marshal
|
||||
from pygost.gost34112012256 import GOST34112012256
|
||||
from pygost.gost34112012512 import GOST34112012512
|
||||
from pygost.gost341194 import GOST341194
|
||||
from pygost.utils import bytes2long
|
||||
|
||||
|
||||
def ukm_unmarshal(ukm):
|
||||
"""Unmarshal UKM value
|
||||
|
||||
:type ukm: little-endian bytes
|
||||
:rtype: long
|
||||
"""
|
||||
return bytes2long(ukm[::-1])
|
||||
|
||||
|
||||
def kek(curve, prv, pub, ukm, mask=None):
|
||||
if not curve.contains(pub):
|
||||
raise ValueError("pub is not on the curve")
|
||||
key = curve.exp(prv, pub[0], pub[1])
|
||||
key = curve.exp(curve.cofactor * ukm, key[0], key[1])
|
||||
if mask is not None:
|
||||
key = curve.exp(mask, key[0], key[1])
|
||||
return pub_marshal(key)
|
||||
|
||||
|
||||
def kek_34102001(curve, prv, pub, ukm):
|
||||
"""Key agreement (34.10-2001, 34.11-94)
|
||||
|
||||
:param GOST3410Curve curve: curve to use
|
||||
:param long prv: private key
|
||||
:param pub: public key
|
||||
:type pub: (long, long)
|
||||
:param long ukm: user keying material, VKO-factor
|
||||
:returns: Key Encryption Key (shared key)
|
||||
:rtype: bytes, 32 bytes
|
||||
|
||||
Shared Key Encryption Key computation is based on
|
||||
:rfc:`4357` VKO GOST R 34.10-2001 with little-endian
|
||||
hash output.
|
||||
"""
|
||||
return GOST341194(
|
||||
kek(curve, prv, pub, ukm),
|
||||
sbox="id-GostR3411-94-CryptoProParamSet",
|
||||
).digest()
|
||||
|
||||
|
||||
def kek_34102012256(curve, prv, pub, ukm=1):
|
||||
"""Key agreement (34.10-2012, 34.11-2012 256 bit)
|
||||
|
||||
:param GOST3410Curve curve: curve to use
|
||||
:param long prv: private key
|
||||
:param pub: public key
|
||||
:type pub: (long, long)
|
||||
:param long ukm: user keying material, VKO-factor
|
||||
:returns: Key Encryption Key (shared key)
|
||||
:rtype: bytes, 32 bytes
|
||||
|
||||
Shared Key Encryption Key computation is based on
|
||||
:rfc:`7836` VKO GOST R 34.10-2012.
|
||||
"""
|
||||
return GOST34112012256(kek(curve, prv, pub, ukm)).digest()
|
||||
|
||||
|
||||
def kek_34102012512(curve, prv, pub, ukm=1):
|
||||
"""Key agreement (34.10-2012, 34.11-2012 512 bit)
|
||||
|
||||
:param GOST3410Curve curve: curve to use
|
||||
:param long prv: private key
|
||||
:param pub: public key
|
||||
:type pub: (long, long)
|
||||
:param long ukm: user keying material, VKO-factor
|
||||
:returns: Key Encryption Key (shared key)
|
||||
:rtype: bytes, 32 bytes
|
||||
|
||||
Shared Key Encryption Key computation is based on
|
||||
:rfc:`7836` VKO GOST R 34.10-2012.
|
||||
"""
|
||||
return GOST34112012512(kek(curve, prv, pub, ukm)).digest()
|
||||
@ -1,299 +0,0 @@
|
||||
# coding: utf-8
|
||||
# PyGOST -- Pure Python GOST cryptographic functions library
|
||||
# Copyright (C) 2015-2023 Sergey Matveev <stargrave@stargrave.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, version 3 of the License.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
"""GOST R 34.11-2012 (Streebog) hash function common files
|
||||
|
||||
This is implementation of :rfc:`6986`. Most function and variable names are
|
||||
taken according to specification's terminology.
|
||||
"""
|
||||
|
||||
from copy import copy
|
||||
from struct import pack
|
||||
from struct import unpack
|
||||
|
||||
from pygost.iface import PEP247
|
||||
from pygost.utils import hexdec
|
||||
from pygost.utils import strxor
|
||||
from pygost.utils import xrange
|
||||
|
||||
|
||||
BLOCKSIZE = 64
|
||||
Pi = bytearray((
|
||||
252, 238, 221, 17, 207, 110, 49, 22, 251, 196, 250,
|
||||
218, 35, 197, 4, 77, 233, 119, 240, 219, 147, 46,
|
||||
153, 186, 23, 54, 241, 187, 20, 205, 95, 193, 249,
|
||||
24, 101, 90, 226, 92, 239, 33, 129, 28, 60, 66,
|
||||
139, 1, 142, 79, 5, 132, 2, 174, 227, 106, 143,
|
||||
160, 6, 11, 237, 152, 127, 212, 211, 31, 235, 52,
|
||||
44, 81, 234, 200, 72, 171, 242, 42, 104, 162, 253,
|
||||
58, 206, 204, 181, 112, 14, 86, 8, 12, 118, 18,
|
||||
191, 114, 19, 71, 156, 183, 93, 135, 21, 161, 150,
|
||||
41, 16, 123, 154, 199, 243, 145, 120, 111, 157, 158,
|
||||
178, 177, 50, 117, 25, 61, 255, 53, 138, 126, 109,
|
||||
84, 198, 128, 195, 189, 13, 87, 223, 245, 36, 169,
|
||||
62, 168, 67, 201, 215, 121, 214, 246, 124, 34, 185,
|
||||
3, 224, 15, 236, 222, 122, 148, 176, 188, 220, 232,
|
||||
40, 80, 78, 51, 10, 74, 167, 151, 96, 115, 30,
|
||||
0, 98, 68, 26, 184, 56, 130, 100, 159, 38, 65,
|
||||
173, 69, 70, 146, 39, 94, 85, 47, 140, 163, 165,
|
||||
125, 105, 213, 149, 59, 7, 88, 179, 64, 134, 172,
|
||||
29, 247, 48, 55, 107, 228, 136, 217, 231, 137, 225,
|
||||
27, 131, 73, 76, 63, 248, 254, 141, 83, 170, 144,
|
||||
202, 216, 133, 97, 32, 113, 103, 164, 45, 43, 9,
|
||||
91, 203, 155, 37, 208, 190, 229, 108, 82, 89, 166,
|
||||
116, 210, 230, 244, 180, 192, 209, 102, 175, 194, 57,
|
||||
75, 99, 182,
|
||||
))
|
||||
|
||||
A = [unpack(">Q", hexdec(s))[0] for s in (
|
||||
"8e20faa72ba0b470", "47107ddd9b505a38", "ad08b0e0c3282d1c", "d8045870ef14980e",
|
||||
"6c022c38f90a4c07", "3601161cf205268d", "1b8e0b0e798c13c8", "83478b07b2468764",
|
||||
"a011d380818e8f40", "5086e740ce47c920", "2843fd2067adea10", "14aff010bdd87508",
|
||||
"0ad97808d06cb404", "05e23c0468365a02", "8c711e02341b2d01", "46b60f011a83988e",
|
||||
"90dab52a387ae76f", "486dd4151c3dfdb9", "24b86a840e90f0d2", "125c354207487869",
|
||||
"092e94218d243cba", "8a174a9ec8121e5d", "4585254f64090fa0", "accc9ca9328a8950",
|
||||
"9d4df05d5f661451", "c0a878a0a1330aa6", "60543c50de970553", "302a1e286fc58ca7",
|
||||
"18150f14b9ec46dd", "0c84890ad27623e0", "0642ca05693b9f70", "0321658cba93c138",
|
||||
"86275df09ce8aaa8", "439da0784e745554", "afc0503c273aa42a", "d960281e9d1d5215",
|
||||
"e230140fc0802984", "71180a8960409a42", "b60c05ca30204d21", "5b068c651810a89e",
|
||||
"456c34887a3805b9", "ac361a443d1c8cd2", "561b0d22900e4669", "2b838811480723ba",
|
||||
"9bcf4486248d9f5d", "c3e9224312c8c1a0", "effa11af0964ee50", "f97d86d98a327728",
|
||||
"e4fa2054a80b329c", "727d102a548b194e", "39b008152acb8227", "9258048415eb419d",
|
||||
"492c024284fbaec0", "aa16012142f35760", "550b8e9e21f7a530", "a48b474f9ef5dc18",
|
||||
"70a6a56e2440598e", "3853dc371220a247", "1ca76e95091051ad", "0edd37c48a08a6d8",
|
||||
"07e095624504536c", "8d70c431ac02a736", "c83862965601dd1b", "641c314b2b8ee083",
|
||||
)]
|
||||
|
||||
Tau = (
|
||||
0, 8, 16, 24, 32, 40, 48, 56,
|
||||
1, 9, 17, 25, 33, 41, 49, 57,
|
||||
2, 10, 18, 26, 34, 42, 50, 58,
|
||||
3, 11, 19, 27, 35, 43, 51, 59,
|
||||
4, 12, 20, 28, 36, 44, 52, 60,
|
||||
5, 13, 21, 29, 37, 45, 53, 61,
|
||||
6, 14, 22, 30, 38, 46, 54, 62,
|
||||
7, 15, 23, 31, 39, 47, 55, 63,
|
||||
)
|
||||
|
||||
C = [hexdec("".join(s))[::-1] for s in (
|
||||
(
|
||||
"b1085bda1ecadae9ebcb2f81c0657c1f",
|
||||
"2f6a76432e45d016714eb88d7585c4fc",
|
||||
"4b7ce09192676901a2422a08a460d315",
|
||||
"05767436cc744d23dd806559f2a64507",
|
||||
),
|
||||
(
|
||||
"6fa3b58aa99d2f1a4fe39d460f70b5d7",
|
||||
"f3feea720a232b9861d55e0f16b50131",
|
||||
"9ab5176b12d699585cb561c2db0aa7ca",
|
||||
"55dda21bd7cbcd56e679047021b19bb7",
|
||||
),
|
||||
(
|
||||
"f574dcac2bce2fc70a39fc286a3d8435",
|
||||
"06f15e5f529c1f8bf2ea7514b1297b7b",
|
||||
"d3e20fe490359eb1c1c93a376062db09",
|
||||
"c2b6f443867adb31991e96f50aba0ab2",
|
||||
),
|
||||
(
|
||||
"ef1fdfb3e81566d2f948e1a05d71e4dd",
|
||||
"488e857e335c3c7d9d721cad685e353f",
|
||||
"a9d72c82ed03d675d8b71333935203be",
|
||||
"3453eaa193e837f1220cbebc84e3d12e",
|
||||
),
|
||||
(
|
||||
"4bea6bacad4747999a3f410c6ca92363",
|
||||
"7f151c1f1686104a359e35d7800fffbd",
|
||||
"bfcd1747253af5a3dfff00b723271a16",
|
||||
"7a56a27ea9ea63f5601758fd7c6cfe57",
|
||||
),
|
||||
(
|
||||
"ae4faeae1d3ad3d96fa4c33b7a3039c0",
|
||||
"2d66c4f95142a46c187f9ab49af08ec6",
|
||||
"cffaa6b71c9ab7b40af21f66c2bec6b6",
|
||||
"bf71c57236904f35fa68407a46647d6e",
|
||||
),
|
||||
(
|
||||
"f4c70e16eeaac5ec51ac86febf240954",
|
||||
"399ec6c7e6bf87c9d3473e33197a93c9",
|
||||
"0992abc52d822c3706476983284a0504",
|
||||
"3517454ca23c4af38886564d3a14d493",
|
||||
),
|
||||
(
|
||||
"9b1f5b424d93c9a703e7aa020c6e4141",
|
||||
"4eb7f8719c36de1e89b4443b4ddbc49a",
|
||||
"f4892bcb929b069069d18d2bd1a5c42f",
|
||||
"36acc2355951a8d9a47f0dd4bf02e71e",
|
||||
),
|
||||
(
|
||||
"378f5a541631229b944c9ad8ec165fde",
|
||||
"3a7d3a1b258942243cd955b7e00d0984",
|
||||
"800a440bdbb2ceb17b2b8a9aa6079c54",
|
||||
"0e38dc92cb1f2a607261445183235adb",
|
||||
),
|
||||
(
|
||||
"abbedea680056f52382ae548b2e4f3f3",
|
||||
"8941e71cff8a78db1fffe18a1b336103",
|
||||
"9fe76702af69334b7a1e6c303b7652f4",
|
||||
"3698fad1153bb6c374b4c7fb98459ced",
|
||||
),
|
||||
(
|
||||
"7bcd9ed0efc889fb3002c6cd635afe94",
|
||||
"d8fa6bbbebab07612001802114846679",
|
||||
"8a1d71efea48b9caefbacd1d7d476e98",
|
||||
"dea2594ac06fd85d6bcaa4cd81f32d1b",
|
||||
),
|
||||
(
|
||||
"378ee767f11631bad21380b00449b17a",
|
||||
"cda43c32bcdf1d77f82012d430219f9b",
|
||||
"5d80ef9d1891cc86e71da4aa88e12852",
|
||||
"faf417d5d9b21b9948bc924af11bd720",
|
||||
),
|
||||
)]
|
||||
|
||||
|
||||
def _lcache():
|
||||
cache = []
|
||||
for byteN in xrange(8):
|
||||
cache.append([0 for _ in xrange(256)])
|
||||
for byteN in xrange(8):
|
||||
for byteVal in xrange(256):
|
||||
res64 = 0
|
||||
val = byteVal
|
||||
for bitN in xrange(8):
|
||||
if val & 0x80 > 0:
|
||||
res64 ^= A[(7 - byteN) * 8 + bitN]
|
||||
val <<= 1
|
||||
cache[byteN][byteVal] = res64
|
||||
return cache
|
||||
|
||||
|
||||
# Trade memory for CPU for part of L() calculations
|
||||
LCache = _lcache()
|
||||
|
||||
|
||||
def add512bit(a, b):
|
||||
a = int.from_bytes(a, "little")
|
||||
b = int.from_bytes(b, "little")
|
||||
r = (a + b) % (1 << 512)
|
||||
return r.to_bytes(512 // 8, "little")
|
||||
|
||||
|
||||
def g(n, hsh, msg):
|
||||
res = E(LPS(strxor(hsh[:8], pack("<Q", n)) + hsh[8:]), msg)
|
||||
return strxor(strxor(res, hsh), msg)
|
||||
|
||||
|
||||
def E(k, msg):
|
||||
for i in range(12):
|
||||
msg = LPS(strxor(k, msg))
|
||||
k = LPS(strxor(k, C[i]))
|
||||
return strxor(k, msg)
|
||||
|
||||
|
||||
def LPS(data):
|
||||
return L(PS(bytearray(data)))
|
||||
|
||||
|
||||
def PS(data):
|
||||
res = bytearray(BLOCKSIZE)
|
||||
for i in range(BLOCKSIZE):
|
||||
res[Tau[i]] = Pi[data[i]]
|
||||
return res
|
||||
|
||||
|
||||
def L(data):
|
||||
res = []
|
||||
for i in range(8):
|
||||
res64 = 0
|
||||
for j in range(8):
|
||||
res64 ^= LCache[j][data[8 * i + j]]
|
||||
res.append(pack("<Q", res64))
|
||||
return b"".join(res)
|
||||
|
||||
|
||||
class GOST34112012(PEP247):
|
||||
"""GOST 34.11-2012 big-endian hash
|
||||
|
||||
>>> m = GOST34112012(digest_size=32)
|
||||
>>> m.update("foo")
|
||||
>>> m.update("bar")
|
||||
>>> m.hexdigest()
|
||||
'e3c9fd89226d93b489a9fe27d686806e24a514e3787bca053c698ec4616ceb78'
|
||||
"""
|
||||
block_size = BLOCKSIZE
|
||||
|
||||
def __init__(self, data=b"", digest_size=64):
|
||||
"""
|
||||
:param digest_size: hash digest size to compute
|
||||
:type digest_size: 32 or 64 bytes
|
||||
"""
|
||||
self._digest_size = digest_size
|
||||
self.hsh = BLOCKSIZE * (b"\x01" if digest_size == 32 else b"\x00")
|
||||
self.chk = bytearray(BLOCKSIZE * b"\x00")
|
||||
self.n = 0
|
||||
self.buf = b""
|
||||
self.update(data)
|
||||
|
||||
def copy(self):
|
||||
obj = GOST34112012()
|
||||
obj._digest_size = self._digest_size
|
||||
obj.hsh = self.hsh
|
||||
obj.chk = copy(self.chk)
|
||||
obj.n = self.n
|
||||
obj.buf = self.buf
|
||||
return obj
|
||||
|
||||
@property
|
||||
def digest_size(self):
|
||||
return self._digest_size
|
||||
|
||||
def _update_block(self, block):
|
||||
self.hsh = g(self.n, self.hsh, block)
|
||||
self.chk = add512bit(self.chk, block)
|
||||
self.n += 512
|
||||
|
||||
def update(self, data):
|
||||
"""Update state with the new data
|
||||
"""
|
||||
if len(self.buf) > 0:
|
||||
chunk_len = BLOCKSIZE - len(self.buf)
|
||||
self.buf += data[:chunk_len]
|
||||
data = data[chunk_len:]
|
||||
if len(self.buf) == BLOCKSIZE:
|
||||
self._update_block(self.buf)
|
||||
self.buf = b""
|
||||
while len(data) >= BLOCKSIZE:
|
||||
self._update_block(data[:BLOCKSIZE])
|
||||
data = data[BLOCKSIZE:]
|
||||
self.buf += data
|
||||
|
||||
def digest(self):
|
||||
"""Get hash of the provided data
|
||||
"""
|
||||
data = self.buf
|
||||
|
||||
# Padding
|
||||
padblock_size = len(data) * 8
|
||||
data += b"\x01"
|
||||
padlen = BLOCKSIZE - len(data)
|
||||
if padlen != BLOCKSIZE:
|
||||
data += b"\x00" * padlen
|
||||
|
||||
hsh = g(self.n, self.hsh, data)
|
||||
n = self.n + padblock_size
|
||||
chk = add512bit(self.chk, data)
|
||||
hsh = g(0, hsh, pack("<Q", n) + 56 * b"\x00")
|
||||
hsh = g(0, hsh, chk)
|
||||
return hsh[-self._digest_size:]
|
||||
@ -1,16 +0,0 @@
|
||||
"""GOST R 34.11-2012 (Streebog) 256-bit hash function
|
||||
|
||||
This is implementation of :rfc:`6986`. Most function and variable names are
|
||||
taken according to specification's terminology.
|
||||
"""
|
||||
|
||||
from pygost.gost34112012 import GOST34112012
|
||||
|
||||
|
||||
class GOST34112012256(GOST34112012):
|
||||
def __init__(self, data=b""):
|
||||
super(GOST34112012256, self).__init__(data, digest_size=32)
|
||||
|
||||
|
||||
def new(data=b""):
|
||||
return GOST34112012256(data)
|
||||
@ -1,21 +0,0 @@
|
||||
"""GOST R 34.11-2012 (Streebog) 512-bit hash function
|
||||
|
||||
This is implementation of :rfc:`6986`. Most function and variable names are
|
||||
taken according to specification's terminology.
|
||||
"""
|
||||
|
||||
from pygost.gost34112012 import GOST34112012
|
||||
from pygost.pbkdf2 import pbkdf2 as pbkdf2_base
|
||||
|
||||
|
||||
class GOST34112012512(GOST34112012):
|
||||
def __init__(self, data=b""):
|
||||
super(GOST34112012512, self).__init__(data, digest_size=64)
|
||||
|
||||
|
||||
def new(data=b""):
|
||||
return GOST34112012512(data)
|
||||
|
||||
|
||||
def pbkdf2(password, salt, iterations, dklen):
|
||||
return pbkdf2_base(GOST34112012512, password, salt, iterations, dklen)
|
||||
@ -1,192 +0,0 @@
|
||||
# coding: utf-8
|
||||
# PyGOST -- Pure Python GOST cryptographic functions library
|
||||
# Copyright (C) 2015-2023 Sergey Matveev <stargrave@stargrave.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, version 3 of the License.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
"""GOST R 34.11-94 hash function
|
||||
|
||||
This is implementation of :rfc:`5831`. Most function and variable names are
|
||||
taken according to specification's terminology.
|
||||
"""
|
||||
|
||||
from copy import copy
|
||||
from functools import partial
|
||||
from struct import pack
|
||||
|
||||
from pygost.gost28147 import block2ns
|
||||
from pygost.gost28147 import encrypt
|
||||
from pygost.gost28147 import ns2block
|
||||
from pygost.gost28147 import validate_sbox
|
||||
from pygost.iface import PEP247
|
||||
from pygost.pbkdf2 import pbkdf2 as pbkdf2_base
|
||||
from pygost.utils import hexdec
|
||||
from pygost.utils import hexenc
|
||||
from pygost.utils import strxor
|
||||
from pygost.utils import xrange
|
||||
|
||||
|
||||
DEFAULT_SBOX = "id-GostR3411-94-CryptoProParamSet"
|
||||
BLOCKSIZE = 32
|
||||
C2 = 32 * b"\x00"
|
||||
C3 = hexdec(b"ff00ffff000000ffff0000ff00ffff0000ff00ff00ff00ffff00ff00ff00ff00")
|
||||
C4 = 32 * b"\x00"
|
||||
digest_size = 32
|
||||
|
||||
|
||||
def A(x):
|
||||
x4, x3, x2, x1 = x[0:8], x[8:16], x[16:24], x[24:32]
|
||||
return b"".join((strxor(x1, x2), x4, x3, x2))
|
||||
|
||||
|
||||
def P(x):
|
||||
return bytearray((
|
||||
x[0], x[8], x[16], x[24], x[1], x[9], x[17], x[25], x[2],
|
||||
x[10], x[18], x[26], x[3], x[11], x[19], x[27], x[4], x[12],
|
||||
x[20], x[28], x[5], x[13], x[21], x[29], x[6], x[14], x[22],
|
||||
x[30], x[7], x[15], x[23], x[31],
|
||||
))
|
||||
|
||||
|
||||
def _chi(Y):
|
||||
"""Chi function
|
||||
|
||||
This is some kind of LFSR.
|
||||
"""
|
||||
(y16, y15, y14, y13, y12, y11, y10, y9, y8, y7, y6, y5, y4, y3, y2, y1) = (
|
||||
Y[0:2], Y[2:4], Y[4:6], Y[6:8], Y[8:10], Y[10:12], Y[12:14],
|
||||
Y[14:16], Y[16:18], Y[18:20], Y[20:22], Y[22:24], Y[24:26],
|
||||
Y[26:28], Y[28:30], Y[30:32],
|
||||
)
|
||||
by1, by2, by3, by4, by13, by16, byx = (
|
||||
bytearray(y1), bytearray(y2), bytearray(y3), bytearray(y4),
|
||||
bytearray(y13), bytearray(y16), bytearray(2),
|
||||
)
|
||||
byx[0] = by1[0] ^ by2[0] ^ by3[0] ^ by4[0] ^ by13[0] ^ by16[0]
|
||||
byx[1] = by1[1] ^ by2[1] ^ by3[1] ^ by4[1] ^ by13[1] ^ by16[1]
|
||||
return b"".join((
|
||||
bytes(byx), y16, y15, y14, y13, y12, y11, y10, y9, y8, y7, y6, y5, y4, y3, y2
|
||||
))
|
||||
|
||||
|
||||
def _step(hin, m, sbox):
|
||||
"""Step function
|
||||
|
||||
H_out = f(H_in, m)
|
||||
"""
|
||||
# Generate keys
|
||||
u = hin
|
||||
v = m
|
||||
w = strxor(hin, m)
|
||||
k1 = P(w)
|
||||
|
||||
u = strxor(A(u), C2)
|
||||
v = A(A(v))
|
||||
w = strxor(u, v)
|
||||
k2 = P(w)
|
||||
|
||||
u = strxor(A(u), C3)
|
||||
v = A(A(v))
|
||||
w = strxor(u, v)
|
||||
k3 = P(w)
|
||||
|
||||
u = strxor(A(u), C4)
|
||||
v = A(A(v))
|
||||
w = strxor(u, v)
|
||||
k4 = P(w)
|
||||
|
||||
# Encipher
|
||||
h4, h3, h2, h1 = hin[0:8], hin[8:16], hin[16:24], hin[24:32]
|
||||
s1 = ns2block(encrypt(sbox, k1[::-1], block2ns(h1[::-1])))[::-1]
|
||||
s2 = ns2block(encrypt(sbox, k2[::-1], block2ns(h2[::-1])))[::-1]
|
||||
s3 = ns2block(encrypt(sbox, k3[::-1], block2ns(h3[::-1])))[::-1]
|
||||
s4 = ns2block(encrypt(sbox, k4[::-1], block2ns(h4[::-1])))[::-1]
|
||||
s = b"".join((s4, s3, s2, s1))
|
||||
|
||||
# Permute
|
||||
# H_out = chi^61(H_in XOR chi(m XOR chi^12(S)))
|
||||
x = s
|
||||
for _ in xrange(12):
|
||||
x = _chi(x)
|
||||
x = strxor(x, m)
|
||||
x = _chi(x)
|
||||
x = strxor(hin, x)
|
||||
for _ in xrange(61):
|
||||
x = _chi(x)
|
||||
return x
|
||||
|
||||
|
||||
class GOST341194(PEP247):
|
||||
"""GOST 34.11-94 big-endian hash
|
||||
|
||||
>>> m = GOST341194()
|
||||
>>> m.update("foo")
|
||||
>>> m.update("bar")
|
||||
>>> m.hexdigest()
|
||||
'3bd8a3a35917871dfa0d49f9e73e7c57eea028dc061133eb560849ea20c133af'
|
||||
>>> GOST341194("foobar").hexdigest()
|
||||
'3bd8a3a35917871dfa0d49f9e73e7c57eea028dc061133eb560849ea20c133af'
|
||||
"""
|
||||
block_size = BLOCKSIZE
|
||||
digest_size = digest_size
|
||||
|
||||
def __init__(self, data=b"", sbox=DEFAULT_SBOX):
|
||||
"""
|
||||
:param bytes data: provide initial data
|
||||
:param bytes sbox: S-box to use
|
||||
"""
|
||||
validate_sbox(sbox)
|
||||
self.data = data
|
||||
self.sbox = sbox
|
||||
|
||||
def copy(self):
|
||||
return GOST341194(copy(self.data), self.sbox)
|
||||
|
||||
def update(self, data):
|
||||
"""Append data that has to be hashed
|
||||
"""
|
||||
self.data += data
|
||||
|
||||
def digest(self):
|
||||
"""Get hash of the provided data
|
||||
"""
|
||||
_len = 0
|
||||
checksum = 0
|
||||
h = 32 * b"\x00"
|
||||
m = self.data
|
||||
for i in xrange(0, len(m), BLOCKSIZE):
|
||||
part = m[i:i + BLOCKSIZE][::-1]
|
||||
_len += len(part) * 8
|
||||
checksum = (checksum + int(hexenc(part), 16)) % (2 ** 256)
|
||||
if len(part) < BLOCKSIZE:
|
||||
part = b"\x00" * (BLOCKSIZE - len(part)) + part
|
||||
h = _step(h, part, self.sbox)
|
||||
h = _step(h, 24 * b"\x00" + pack(">Q", _len), self.sbox)
|
||||
|
||||
checksum = hex(checksum)[2:].rstrip("L")
|
||||
if len(checksum) % 2 != 0:
|
||||
checksum = "0" + checksum
|
||||
checksum = hexdec(checksum)
|
||||
checksum = b"\x00" * (BLOCKSIZE - len(checksum)) + checksum
|
||||
h = _step(h, checksum, self.sbox)
|
||||
return h[::-1]
|
||||
|
||||
|
||||
def new(data=b"", sbox=DEFAULT_SBOX):
|
||||
return GOST341194(data, sbox)
|
||||
|
||||
|
||||
PBKDF2_HASHER = partial(GOST341194, sbox="id-GostR3411-94-CryptoProParamSet")
|
||||
|
||||
|
||||
def pbkdf2(password, salt, iterations, dklen):
|
||||
return pbkdf2_base(PBKDF2_HASHER, password, salt, iterations, dklen)
|
||||
@ -1,186 +0,0 @@
|
||||
# coding: utf-8
|
||||
# PyGOST -- Pure Python GOST cryptographic functions library
|
||||
# Copyright (C) 2015-2023 Sergey Matveev <stargrave@stargrave.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, version 3 of the License.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
"""GOST 34.12-2015 64 and 128 bit block ciphers (:rfc:`7801`)
|
||||
|
||||
Several precalculations are performed during this module importing.
|
||||
"""
|
||||
|
||||
from pygost.gost28147 import block2ns as gost28147_block2ns
|
||||
from pygost.gost28147 import decrypt as gost28147_decrypt
|
||||
from pygost.gost28147 import encrypt as gost28147_encrypt
|
||||
from pygost.gost28147 import ns2block as gost28147_ns2block
|
||||
from pygost.utils import strxor
|
||||
from pygost.utils import xrange
|
||||
|
||||
|
||||
KEYSIZE = 32
|
||||
|
||||
LC = bytearray((
|
||||
148, 32, 133, 16, 194, 192, 1, 251, 1, 192, 194, 16, 133, 32, 148, 1,
|
||||
))
|
||||
PI = bytearray((
|
||||
252, 238, 221, 17, 207, 110, 49, 22, 251, 196, 250, 218, 35, 197, 4, 77,
|
||||
233, 119, 240, 219, 147, 46, 153, 186, 23, 54, 241, 187, 20, 205, 95, 193,
|
||||
249, 24, 101, 90, 226, 92, 239, 33, 129, 28, 60, 66, 139, 1, 142, 79, 5,
|
||||
132, 2, 174, 227, 106, 143, 160, 6, 11, 237, 152, 127, 212, 211, 31, 235,
|
||||
52, 44, 81, 234, 200, 72, 171, 242, 42, 104, 162, 253, 58, 206, 204, 181,
|
||||
112, 14, 86, 8, 12, 118, 18, 191, 114, 19, 71, 156, 183, 93, 135, 21, 161,
|
||||
150, 41, 16, 123, 154, 199, 243, 145, 120, 111, 157, 158, 178, 177, 50, 117,
|
||||
25, 61, 255, 53, 138, 126, 109, 84, 198, 128, 195, 189, 13, 87, 223, 245,
|
||||
36, 169, 62, 168, 67, 201, 215, 121, 214, 246, 124, 34, 185, 3, 224, 15,
|
||||
236, 222, 122, 148, 176, 188, 220, 232, 40, 80, 78, 51, 10, 74, 167, 151,
|
||||
96, 115, 30, 0, 98, 68, 26, 184, 56, 130, 100, 159, 38, 65, 173, 69, 70,
|
||||
146, 39, 94, 85, 47, 140, 163, 165, 125, 105, 213, 149, 59, 7, 88, 179, 64,
|
||||
134, 172, 29, 247, 48, 55, 107, 228, 136, 217, 231, 137, 225, 27, 131, 73,
|
||||
76, 63, 248, 254, 141, 83, 170, 144, 202, 216, 133, 97, 32, 113, 103, 164,
|
||||
45, 43, 9, 91, 203, 155, 37, 208, 190, 229, 108, 82, 89, 166, 116, 210, 230,
|
||||
244, 180, 192, 209, 102, 175, 194, 57, 75, 99, 182,
|
||||
))
|
||||
|
||||
########################################################################
|
||||
# Precalculate inverted PI value as a performance optimization.
|
||||
# Actually it can be computed only once and saved on the disk.
|
||||
########################################################################
|
||||
PIinv = bytearray(256)
|
||||
for x in xrange(256):
|
||||
PIinv[PI[x]] = x
|
||||
|
||||
|
||||
def gf(a, b):
|
||||
c = 0
|
||||
while b:
|
||||
if b & 1:
|
||||
c ^= a
|
||||
if a & 0x80:
|
||||
a = (a << 1) ^ 0x1C3
|
||||
else:
|
||||
a <<= 1
|
||||
b >>= 1
|
||||
return c
|
||||
|
||||
########################################################################
|
||||
# Precalculate all possible gf(byte, byte) values as a performance
|
||||
# optimization.
|
||||
# Actually it can be computed only once and saved on the disk.
|
||||
########################################################################
|
||||
|
||||
|
||||
GF = [bytearray(256) for _ in xrange(256)]
|
||||
|
||||
for x in xrange(256):
|
||||
for y in xrange(256):
|
||||
GF[x][y] = gf(x, y)
|
||||
|
||||
|
||||
def L(blk, rounds=16):
|
||||
for _ in range(rounds):
|
||||
t = blk[15]
|
||||
for i in range(14, -1, -1):
|
||||
blk[i + 1] = blk[i]
|
||||
t ^= GF[blk[i]][LC[i]]
|
||||
blk[0] = t
|
||||
return blk
|
||||
|
||||
|
||||
def Linv(blk):
|
||||
for _ in range(16):
|
||||
t = blk[0]
|
||||
for i in range(15):
|
||||
blk[i] = blk[i + 1]
|
||||
t ^= GF[blk[i]][LC[i]]
|
||||
blk[15] = t
|
||||
return blk
|
||||
|
||||
########################################################################
|
||||
# Precalculate values of the C -- it does not depend on key.
|
||||
# Actually it can be computed only once and saved on the disk.
|
||||
########################################################################
|
||||
|
||||
|
||||
C = []
|
||||
|
||||
for x in range(1, 33):
|
||||
y = bytearray(16)
|
||||
y[15] = x
|
||||
C.append(L(y))
|
||||
|
||||
|
||||
def lp(blk):
|
||||
return L([PI[v] for v in blk])
|
||||
|
||||
|
||||
class GOST3412Kuznechik(object):
|
||||
"""GOST 34.12-2015 128-bit block cipher Кузнечик (Kuznechik)
|
||||
"""
|
||||
blocksize = 16
|
||||
|
||||
def __init__(self, key):
|
||||
"""
|
||||
:param key: encryption/decryption key
|
||||
:type key: bytes, 32 bytes
|
||||
|
||||
Key scheduling (roundkeys precomputation) is performed here.
|
||||
"""
|
||||
kr0 = bytearray(key[:16])
|
||||
kr1 = bytearray(key[16:])
|
||||
self.ks = [kr0, kr1]
|
||||
for i in range(4):
|
||||
for j in range(8):
|
||||
k = lp(bytearray(strxor(C[8 * i + j], kr0)))
|
||||
kr0, kr1 = [strxor(k, kr1), kr0]
|
||||
self.ks.append(kr0)
|
||||
self.ks.append(kr1)
|
||||
|
||||
def encrypt(self, blk):
|
||||
blk = bytearray(blk)
|
||||
for i in range(9):
|
||||
blk = lp(bytearray(strxor(self.ks[i], blk)))
|
||||
return bytes(strxor(self.ks[9], blk))
|
||||
|
||||
def decrypt(self, blk):
|
||||
blk = bytearray(blk)
|
||||
for i in range(9, 0, -1):
|
||||
blk = [PIinv[v] for v in Linv(bytearray(strxor(self.ks[i], blk)))]
|
||||
return bytes(strxor(self.ks[0], blk))
|
||||
|
||||
|
||||
class GOST3412Magma(object):
|
||||
"""GOST 34.12-2015 64-bit block cipher Магма (Magma)
|
||||
"""
|
||||
blocksize = 8
|
||||
|
||||
def __init__(self, key):
|
||||
"""
|
||||
:param key: encryption/decryption key
|
||||
:type key: bytes, 32 bytes
|
||||
"""
|
||||
# Backward compatibility key preparation for 28147-89 key schedule
|
||||
self.key = b"".join(key[i * 4:i * 4 + 4][::-1] for i in range(8))
|
||||
self.sbox = "id-tc26-gost-28147-param-Z"
|
||||
|
||||
def encrypt(self, blk):
|
||||
return gost28147_ns2block(gost28147_encrypt(
|
||||
self.sbox,
|
||||
self.key,
|
||||
gost28147_block2ns(blk[::-1]),
|
||||
))[::-1]
|
||||
|
||||
def decrypt(self, blk):
|
||||
return gost28147_ns2block(gost28147_decrypt(
|
||||
self.sbox,
|
||||
self.key,
|
||||
gost28147_block2ns(blk[::-1]),
|
||||
))[::-1]
|
||||
@ -1,392 +0,0 @@
|
||||
# coding: utf-8
|
||||
# PyGOST -- Pure Python GOST cryptographic functions library
|
||||
# Copyright (C) 2015-2023 Sergey Matveev <stargrave@stargrave.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, version 3 of the License.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
"""GOST R 34.13-2015: Modes of operation for block ciphers
|
||||
|
||||
This module currently includes only padding methods.
|
||||
"""
|
||||
|
||||
from os import urandom
|
||||
|
||||
from pygost.utils import bytes2long
|
||||
from pygost.utils import long2bytes
|
||||
from pygost.utils import strxor
|
||||
from pygost.utils import xrange
|
||||
|
||||
|
||||
KEYSIZE = 32
|
||||
|
||||
|
||||
def pad_size(data_size, blocksize):
|
||||
"""Calculate required pad size to full up blocksize
|
||||
"""
|
||||
if data_size < blocksize:
|
||||
return blocksize - data_size
|
||||
if data_size % blocksize == 0:
|
||||
return 0
|
||||
return blocksize - data_size % blocksize
|
||||
|
||||
|
||||
def pad1(data, blocksize):
|
||||
"""Padding method 1
|
||||
|
||||
Just fill up with zeros if necessary.
|
||||
"""
|
||||
return data + b"\x00" * pad_size(len(data), blocksize)
|
||||
|
||||
|
||||
def pad2(data, blocksize):
|
||||
"""Padding method 2 (also known as ISO/IEC 7816-4)
|
||||
|
||||
Add one bit and then fill up with zeros.
|
||||
"""
|
||||
return data + b"\x80" + b"\x00" * pad_size(len(data) + 1, blocksize)
|
||||
|
||||
|
||||
def unpad2(data, blocksize):
|
||||
"""Unpad method 2
|
||||
"""
|
||||
last_block = bytearray(data[-blocksize:])
|
||||
pad_index = last_block.rfind(b"\x80")
|
||||
if pad_index == -1:
|
||||
raise ValueError("Invalid padding")
|
||||
for c in last_block[pad_index + 1:]:
|
||||
if c != 0:
|
||||
raise ValueError("Invalid padding")
|
||||
return data[:-(blocksize - pad_index)]
|
||||
|
||||
|
||||
def pad3(data, blocksize):
|
||||
"""Padding method 3
|
||||
"""
|
||||
if pad_size(len(data), blocksize) == 0:
|
||||
return data
|
||||
return pad2(data, blocksize)
|
||||
|
||||
|
||||
def ecb_encrypt(encrypter, bs, pt):
|
||||
"""ECB encryption mode of operation
|
||||
|
||||
:param encrypter: encrypting function, that takes block as an input
|
||||
:param int bs: cipher's blocksize, bytes
|
||||
:param bytes pt: already padded plaintext
|
||||
"""
|
||||
if not pt or len(pt) % bs != 0:
|
||||
raise ValueError("Plaintext is not blocksize aligned")
|
||||
ct = []
|
||||
for i in xrange(0, len(pt), bs):
|
||||
ct.append(encrypter(pt[i:i + bs]))
|
||||
return b"".join(ct)
|
||||
|
||||
|
||||
def ecb_decrypt(decrypter, bs, ct):
|
||||
"""ECB decryption mode of operation
|
||||
|
||||
:param decrypter: Decrypting function, that takes block as an input
|
||||
:param int bs: cipher's blocksize, bytes
|
||||
:param bytes ct: ciphertext
|
||||
"""
|
||||
if not ct or len(ct) % bs != 0:
|
||||
raise ValueError("Ciphertext is not blocksize aligned")
|
||||
pt = []
|
||||
for i in xrange(0, len(ct), bs):
|
||||
pt.append(decrypter(ct[i:i + bs]))
|
||||
return b"".join(pt)
|
||||
|
||||
|
||||
def acpkm(encrypter, bs):
|
||||
"""Perform ACPKM key derivation
|
||||
|
||||
:param encrypter: encrypting function, that takes block as an input
|
||||
:param int bs: cipher's blocksize, bytes
|
||||
"""
|
||||
return b"".join([
|
||||
encrypter(bytes(bytearray(range(d, d + bs))))
|
||||
for d in range(0x80, 0x80 + bs * (KEYSIZE // bs), bs)
|
||||
])
|
||||
|
||||
|
||||
def ctr(encrypter, bs, data, iv, _acpkm=None):
|
||||
"""Counter mode of operation
|
||||
|
||||
:param encrypter: encrypting function, that takes block as an input
|
||||
:param int bs: cipher's blocksize, bytes
|
||||
:param bytes data: plaintext/ciphertext
|
||||
:param bytes iv: half blocksize-sized initialization vector
|
||||
|
||||
For decryption you use the same function again.
|
||||
"""
|
||||
if len(iv) != bs // 2:
|
||||
raise ValueError("Invalid IV size")
|
||||
if len(data) > bs * (1 << (8 * (bs // 2 - 1))):
|
||||
raise ValueError("Too big data")
|
||||
stream = []
|
||||
ctr_value = 0
|
||||
ctr_max_value = 1 << (8 * (bs // 2))
|
||||
if _acpkm is not None:
|
||||
acpkm_algo_class, acpkm_section_size_in_bs = _acpkm
|
||||
acpkm_section_size_in_bs //= bs
|
||||
for _ in xrange(0, len(data) + pad_size(len(data), bs), bs):
|
||||
if (
|
||||
_acpkm is not None and
|
||||
ctr_value != 0 and
|
||||
ctr_value % acpkm_section_size_in_bs == 0
|
||||
):
|
||||
encrypter = acpkm_algo_class(acpkm(encrypter, bs)).encrypt
|
||||
stream.append(encrypter(iv + long2bytes(ctr_value, bs // 2)))
|
||||
ctr_value = (ctr_value + 1) % ctr_max_value
|
||||
return strxor(b"".join(stream), data)
|
||||
|
||||
|
||||
def ctr_acpkm(algo_class, encrypter, section_size, bs, data, iv):
|
||||
"""CTR-ACPKM mode of operation
|
||||
|
||||
:param algo_class: pygost.gost3412's algorithm class
|
||||
:param encrypter: encrypting function, that takes block as an input
|
||||
:param int section_size: ACPKM'es section size (N), in bytes
|
||||
:param int bs: cipher's blocksize, bytes
|
||||
:param bytes data: plaintext/ciphertext
|
||||
:param bytes iv: half blocksize-sized initialization vector
|
||||
|
||||
For decryption you use the same function again.
|
||||
"""
|
||||
if section_size % bs != 0:
|
||||
raise ValueError("section_size must be multiple of bs")
|
||||
return ctr(encrypter, bs, data, iv, _acpkm=(algo_class, section_size))
|
||||
|
||||
|
||||
def ofb(encrypter, bs, data, iv):
|
||||
"""OFB mode of operation
|
||||
|
||||
:param encrypter: encrypting function, that takes block as an input
|
||||
:param int bs: cipher's blocksize, bytes
|
||||
:param bytes data: plaintext/ciphertext
|
||||
:param bytes iv: blocksize-sized initialization vector
|
||||
|
||||
For decryption you use the same function again.
|
||||
"""
|
||||
if len(iv) < bs or len(iv) % bs != 0:
|
||||
raise ValueError("Invalid IV size")
|
||||
r = [iv[i:i + bs] for i in range(0, len(iv), bs)]
|
||||
result = []
|
||||
for i in xrange(0, len(data) + pad_size(len(data), bs), bs):
|
||||
r = r[1:] + [encrypter(r[0])]
|
||||
result.append(strxor(r[-1], data[i:i + bs]))
|
||||
return b"".join(result)
|
||||
|
||||
|
||||
def cbc_encrypt(encrypter, bs, pt, iv):
|
||||
"""CBC encryption mode of operation
|
||||
|
||||
:param encrypter: encrypting function, that takes block as an input
|
||||
:param int bs: cipher's blocksize, bytes
|
||||
:param bytes pt: already padded plaintext
|
||||
:param bytes iv: blocksize-sized initialization vector
|
||||
"""
|
||||
if not pt or len(pt) % bs != 0:
|
||||
raise ValueError("Plaintext is not blocksize aligned")
|
||||
if len(iv) < bs or len(iv) % bs != 0:
|
||||
raise ValueError("Invalid IV size")
|
||||
r = [iv[i:i + bs] for i in range(0, len(iv), bs)]
|
||||
ct = []
|
||||
for i in xrange(0, len(pt), bs):
|
||||
ct.append(encrypter(strxor(r[0], pt[i:i + bs])))
|
||||
r = r[1:] + [ct[-1]]
|
||||
return b"".join(ct)
|
||||
|
||||
|
||||
def cbc_decrypt(decrypter, bs, ct, iv):
|
||||
"""CBC decryption mode of operation
|
||||
|
||||
:param decrypter: Decrypting function, that takes block as an input
|
||||
:param int bs: cipher's blocksize, bytes
|
||||
:param bytes ct: ciphertext
|
||||
:param bytes iv: blocksize-sized initialization vector
|
||||
"""
|
||||
if not ct or len(ct) % bs != 0:
|
||||
raise ValueError("Ciphertext is not blocksize aligned")
|
||||
if len(iv) < bs or len(iv) % bs != 0:
|
||||
raise ValueError("Invalid IV size")
|
||||
r = [iv[i:i + bs] for i in range(0, len(iv), bs)]
|
||||
pt = []
|
||||
for i in xrange(0, len(ct), bs):
|
||||
blk = ct[i:i + bs]
|
||||
pt.append(strxor(r[0], decrypter(blk)))
|
||||
r = r[1:] + [blk]
|
||||
return b"".join(pt)
|
||||
|
||||
|
||||
def cfb_encrypt(encrypter, bs, pt, iv):
|
||||
"""CFB encryption mode of operation
|
||||
|
||||
:param encrypter: encrypting function, that takes block as an input
|
||||
:param int bs: cipher's blocksize, bytes
|
||||
:param bytes pt: plaintext
|
||||
:param bytes iv: blocksize-sized initialization vector
|
||||
"""
|
||||
if len(iv) < bs or len(iv) % bs != 0:
|
||||
raise ValueError("Invalid IV size")
|
||||
r = [iv[i:i + bs] for i in range(0, len(iv), bs)]
|
||||
ct = []
|
||||
for i in xrange(0, len(pt) + pad_size(len(pt), bs), bs):
|
||||
ct.append(strxor(encrypter(r[0]), pt[i:i + bs]))
|
||||
r = r[1:] + [ct[-1]]
|
||||
return b"".join(ct)
|
||||
|
||||
|
||||
def cfb_decrypt(encrypter, bs, ct, iv):
|
||||
"""CFB decryption mode of operation
|
||||
|
||||
:param encrypter: encrypting function, that takes block as an input
|
||||
:param int bs: cipher's blocksize, bytes
|
||||
:param bytes ct: ciphertext
|
||||
:param bytes iv: blocksize-sized initialization vector
|
||||
"""
|
||||
if len(iv) < bs or len(iv) % bs != 0:
|
||||
raise ValueError("Invalid IV size")
|
||||
r = [iv[i:i + bs] for i in range(0, len(iv), bs)]
|
||||
pt = []
|
||||
for i in xrange(0, len(ct) + pad_size(len(ct), bs), bs):
|
||||
blk = ct[i:i + bs]
|
||||
pt.append(strxor(encrypter(r[0]), blk))
|
||||
r = r[1:] + [blk]
|
||||
return b"".join(pt)
|
||||
|
||||
|
||||
def _mac_shift(bs, data, xor_lsb=0):
|
||||
num = (bytes2long(data) << 1) ^ xor_lsb
|
||||
return long2bytes(num, bs)[-bs:]
|
||||
|
||||
|
||||
Rb64 = 0b11011
|
||||
Rb128 = 0b10000111
|
||||
|
||||
|
||||
def _mac_ks(encrypter, bs):
|
||||
Rb = Rb128 if bs == 16 else Rb64
|
||||
_l = encrypter(bs * b"\x00")
|
||||
k1 = _mac_shift(bs, _l, Rb) if bytearray(_l)[0] & 0x80 > 0 else _mac_shift(bs, _l)
|
||||
k2 = _mac_shift(bs, k1, Rb) if bytearray(k1)[0] & 0x80 > 0 else _mac_shift(bs, k1)
|
||||
return k1, k2
|
||||
|
||||
|
||||
def mac(encrypter, bs, data):
|
||||
"""MAC (known here as CMAC, OMAC1) mode of operation
|
||||
|
||||
:param encrypter: encrypting function, that takes block as an input
|
||||
:param int bs: cipher's blocksize, bytes
|
||||
:param bytes data: data to authenticate
|
||||
|
||||
Implementation is based on PyCrypto's CMAC one, that is in public domain.
|
||||
"""
|
||||
k1, k2 = _mac_ks(encrypter, bs)
|
||||
if len(data) % bs == 0:
|
||||
tail_offset = len(data) - bs
|
||||
else:
|
||||
tail_offset = len(data) - (len(data) % bs)
|
||||
prev = bs * b"\x00"
|
||||
for i in xrange(0, tail_offset, bs):
|
||||
prev = encrypter(strxor(data[i:i + bs], prev))
|
||||
tail = data[tail_offset:]
|
||||
return encrypter(strxor(
|
||||
strxor(pad3(tail, bs), prev),
|
||||
k1 if len(tail) == bs else k2,
|
||||
))
|
||||
|
||||
|
||||
def acpkm_master(algo_class, encrypter, key_section_size, bs, keymat_len):
|
||||
"""ACPKM-Master key derivation
|
||||
|
||||
:param algo_class: pygost.gost3412's algorithm class
|
||||
:param encrypter: encrypting function, that takes block as an input
|
||||
:param int key_section_size: ACPKM'es key section size (T*), in bytes
|
||||
:param int bs: cipher's blocksize, bytes
|
||||
:param int keymat_len: length of key material to produce
|
||||
"""
|
||||
return ctr_acpkm(
|
||||
algo_class,
|
||||
encrypter,
|
||||
key_section_size,
|
||||
bs,
|
||||
data=b"\x00" * keymat_len,
|
||||
iv=b"\xFF" * (bs // 2),
|
||||
)
|
||||
|
||||
|
||||
def mac_acpkm_master(algo_class, encrypter, key_section_size, section_size, bs, data):
|
||||
"""OMAC-ACPKM-Master
|
||||
|
||||
:param algo_class: pygost.gost3412's algorithm class
|
||||
:param encrypter: encrypting function, that takes block as an input
|
||||
:param int key_section_size: ACPKM'es key section size (T*), in bytes
|
||||
:param int section_size: ACPKM'es section size (N), in bytes
|
||||
:param int bs: cipher's blocksize, bytes
|
||||
:param bytes data: data to authenticate
|
||||
"""
|
||||
if len(data) % bs == 0:
|
||||
tail_offset = len(data) - bs
|
||||
else:
|
||||
tail_offset = len(data) - (len(data) % bs)
|
||||
prev = bs * b"\x00"
|
||||
sections = len(data) // section_size
|
||||
if len(data) % section_size != 0:
|
||||
sections += 1
|
||||
keymats = acpkm_master(
|
||||
algo_class,
|
||||
encrypter,
|
||||
key_section_size,
|
||||
bs,
|
||||
(KEYSIZE + bs) * sections,
|
||||
)
|
||||
for i in xrange(0, tail_offset, bs):
|
||||
if i % section_size == 0:
|
||||
keymat, keymats = keymats[:KEYSIZE + bs], keymats[KEYSIZE + bs:]
|
||||
key, k1 = keymat[:KEYSIZE], keymat[KEYSIZE:]
|
||||
encrypter = algo_class(key).encrypt
|
||||
prev = encrypter(strxor(data[i:i + bs], prev))
|
||||
tail = data[tail_offset:]
|
||||
if len(tail) == bs:
|
||||
key, k1 = keymats[:KEYSIZE], keymats[KEYSIZE:]
|
||||
encrypter = algo_class(key).encrypt
|
||||
k2 = long2bytes(bytes2long(k1) << 1, size=bs)
|
||||
if bytearray(k1)[0] & 0x80 != 0:
|
||||
k2 = strxor(k2, long2bytes(Rb128 if bs == 16 else Rb64, size=bs))
|
||||
return encrypter(strxor(
|
||||
strxor(pad3(tail, bs), prev),
|
||||
k1 if len(tail) == bs else k2,
|
||||
))
|
||||
|
||||
|
||||
def pad_iso10126(data, blocksize):
|
||||
"""ISO 10126 padding
|
||||
|
||||
Does not exist in 34.13, but added for convenience.
|
||||
It uses urandom call for getting the randomness.
|
||||
"""
|
||||
pad_len = blocksize - len(data) % blocksize
|
||||
if pad_len == 0:
|
||||
pad_len = blocksize
|
||||
return b"".join((data, urandom(pad_len - 1), bytes((pad_len,))))
|
||||
|
||||
|
||||
def unpad_iso10126(data, blocksize):
|
||||
"""Unpad :py:func:`pygost.gost3413.pad_iso10126`
|
||||
"""
|
||||
if len(data) % blocksize != 0:
|
||||
raise ValueError("Data length is not multiple of blocksize")
|
||||
pad_len = bytearray(data)[-1]
|
||||
if pad_len > blocksize:
|
||||
raise ValueError("Padding length is bigger than blocksize")
|
||||
return data[:-pad_len]
|
||||
@ -1,50 +0,0 @@
|
||||
from abc import ABCMeta
|
||||
from abc import abstractmethod
|
||||
|
||||
from pygost.utils import hexenc
|
||||
|
||||
|
||||
# This function is taken from six package as is
|
||||
def add_metaclass(metaclass):
|
||||
"""Class decorator for creating a class with a metaclass."""
|
||||
def wrapper(cls):
|
||||
orig_vars = cls.__dict__.copy()
|
||||
slots = orig_vars.get("__slots__")
|
||||
if slots is not None:
|
||||
if isinstance(slots, str):
|
||||
slots = [slots]
|
||||
for slots_var in slots:
|
||||
orig_vars.pop(slots_var)
|
||||
orig_vars.pop("__dict__", None)
|
||||
orig_vars.pop("__weakref__", None)
|
||||
return metaclass(cls.__name__, cls.__bases__, orig_vars)
|
||||
return wrapper
|
||||
|
||||
|
||||
@add_metaclass(ABCMeta)
|
||||
class PEP247(object):
|
||||
@property
|
||||
@abstractmethod
|
||||
def digest_size(self):
|
||||
"""The size of the digest produced by the hashing objects.
|
||||
"""
|
||||
|
||||
@abstractmethod
|
||||
def copy(self):
|
||||
"""Return a separate copy of this hashing object.
|
||||
"""
|
||||
|
||||
@abstractmethod
|
||||
def update(self, data):
|
||||
"""Hash data into the current state of the hashing object.
|
||||
"""
|
||||
|
||||
@abstractmethod
|
||||
def digest(self):
|
||||
"""Return the hash value as a string containing 8-bit data.
|
||||
"""
|
||||
|
||||
def hexdigest(self):
|
||||
"""Return the hash value as a string containing hexadecimal digits.
|
||||
"""
|
||||
return hexenc(self.digest())
|
||||
@ -1,81 +0,0 @@
|
||||
# coding: utf-8
|
||||
# PyGOST -- Pure Python GOST cryptographic functions library
|
||||
# Copyright (C) 2015-2023 Sergey Matveev <stargrave@stargrave.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, version 3 of the License.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
"""Key derivation functions, Р 50.1.113-2016, Р 1323565.1.020-2018
|
||||
"""
|
||||
|
||||
import hmac
|
||||
|
||||
from pygost.gost3410_vko import kek_34102012256
|
||||
from pygost.gost3410_vko import kek_34102012512
|
||||
from pygost.gost34112012256 import GOST34112012256
|
||||
from pygost.utils import bytes2long
|
||||
from pygost.utils import long2bytes
|
||||
|
||||
|
||||
def kdf_gostr3411_2012_256(key, label, seed):
|
||||
"""KDF_GOSTR3411_2012_256
|
||||
|
||||
:param bytes key: initial key
|
||||
:param bytes label: label
|
||||
:param bytes seed: seed
|
||||
:returns: 32 bytes
|
||||
"""
|
||||
return hmac.new(
|
||||
key=key,
|
||||
msg=b"".join((b"\x01", label, b"\x00", seed, b"\x01\x00")),
|
||||
digestmod=GOST34112012256,
|
||||
).digest()
|
||||
|
||||
|
||||
def kdf_tree_gostr3411_2012_256(key, label, seed, keys, i_len=1):
|
||||
"""KDF_TREE_GOSTR3411_2012_256
|
||||
|
||||
:param bytes key: initial key
|
||||
:param bytes label: label
|
||||
:param bytes seed: seed
|
||||
:param int keys: number of generated keys
|
||||
:param int i_len: length of iterations value (called "R")
|
||||
:returns: list of 256-bit keys
|
||||
"""
|
||||
keymat = []
|
||||
_len = long2bytes(keys * 32 * 8, size=1)
|
||||
for i in range(keys):
|
||||
keymat.append(hmac.new(
|
||||
key=key,
|
||||
msg=b"".join((long2bytes(i + 1, size=i_len), label, b"\x00", seed, _len)),
|
||||
digestmod=GOST34112012256,
|
||||
).digest())
|
||||
return keymat
|
||||
|
||||
|
||||
def keg(curve, prv, pub, h):
|
||||
"""Export key generation (Р 1323565.1.020-2018)
|
||||
|
||||
:param GOST3410Curve curve: curve to use
|
||||
:param long prv: private key
|
||||
:param pub: public key
|
||||
:type pub: (long, long)
|
||||
:param bytes h: "h"-value, 32 bytes
|
||||
"""
|
||||
if len(h) != 32:
|
||||
raise ValueError("h must be 32 bytes long")
|
||||
ukm = bytes2long(h[:16])
|
||||
if ukm == 0:
|
||||
ukm = 1
|
||||
if curve.point_size == 64:
|
||||
return kek_34102012512(curve, prv, pub, ukm)
|
||||
k_exp = kek_34102012256(curve, prv, pub, ukm)
|
||||
return b"".join(kdf_tree_gostr3411_2012_256(k_exp, b"kdf tree", h[16:24], 2))
|
||||
@ -1,168 +0,0 @@
|
||||
# coding: utf-8
|
||||
# PyGOST -- Pure Python GOST cryptographic functions library
|
||||
# Copyright (C) 2015-2023 Sergey Matveev <stargrave@stargrave.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, version 3 of the License.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
"""Multilinear Galois Mode (MGM) block cipher mode.
|
||||
"""
|
||||
|
||||
from hmac import compare_digest
|
||||
|
||||
from pygost.gost3413 import pad1
|
||||
from pygost.utils import bytes2long
|
||||
from pygost.utils import long2bytes
|
||||
from pygost.utils import strxor
|
||||
|
||||
|
||||
def _incr(data, bs):
|
||||
return long2bytes(bytes2long(data) + 1, size=bs // 2)
|
||||
|
||||
|
||||
def incr_r(data, bs):
|
||||
return data[:bs // 2] + _incr(data[bs // 2:], bs)
|
||||
|
||||
|
||||
def incr_l(data, bs):
|
||||
return _incr(data[:bs // 2], bs) + data[bs // 2:]
|
||||
|
||||
|
||||
def nonce_prepare(nonce):
|
||||
"""Prepare nonce for MGM usage
|
||||
|
||||
It just clears MSB.
|
||||
"""
|
||||
n = bytearray(nonce)
|
||||
n[0] &= 0x7F
|
||||
return bytes(n)
|
||||
|
||||
|
||||
class MGM(object):
|
||||
# Implementation is fully based on go.cypherpunks.ru/gogost/mgm
|
||||
def __init__(self, encrypter, bs, tag_size=None):
|
||||
"""Multilinear Galois Mode (MGM) block cipher mode
|
||||
|
||||
:param encrypter: encrypting function, that takes block as an input
|
||||
:param int bs: cipher's blocksize
|
||||
:param int tag_size: authentication tag size
|
||||
(defaults to blocksize if not specified)
|
||||
"""
|
||||
if bs not in (8, 16):
|
||||
raise ValueError("Only 64/128-bit blocksizes allowed")
|
||||
self.tag_size = bs if tag_size is None else tag_size
|
||||
if self.tag_size < 4 or self.tag_size > bs:
|
||||
raise ValueError("Invalid tag_size")
|
||||
self.encrypter = encrypter
|
||||
self.bs = bs
|
||||
self.max_size = (1 << (bs * 8 // 2)) - 1
|
||||
self.r = 0x1B if bs == 8 else 0x87
|
||||
|
||||
def _validate_nonce(self, nonce):
|
||||
if len(nonce) != self.bs:
|
||||
raise ValueError("nonce length must be equal to cipher's blocksize")
|
||||
if bytearray(nonce)[0] & 0x80 > 0:
|
||||
raise ValueError("nonce must not have higher bit set")
|
||||
|
||||
def _validate_sizes(self, plaintext, additional_data):
|
||||
if len(plaintext) == 0 and len(additional_data) == 0:
|
||||
raise ValueError("At least one of plaintext or additional_data required")
|
||||
if len(plaintext) + len(additional_data) > self.max_size:
|
||||
raise ValueError("plaintext+additional_data are too big")
|
||||
|
||||
def _mul(self, x, y):
|
||||
x = bytes2long(x)
|
||||
y = bytes2long(y)
|
||||
z = 0
|
||||
max_bit = 1 << (self.bs * 8 - 1)
|
||||
while y > 0:
|
||||
if y & 1 == 1:
|
||||
z ^= x
|
||||
if x & max_bit > 0:
|
||||
x = ((x ^ max_bit) << 1) ^ self.r
|
||||
else:
|
||||
x <<= 1
|
||||
y >>= 1
|
||||
return long2bytes(z, size=self.bs)
|
||||
|
||||
def _crypt(self, icn, data):
|
||||
icn[0] &= 0x7F
|
||||
enc = self.encrypter(bytes(icn))
|
||||
res = []
|
||||
while len(data) > 0:
|
||||
res.append(strxor(self.encrypter(enc), data))
|
||||
enc = incr_r(enc, self.bs)
|
||||
data = data[self.bs:]
|
||||
return b"".join(res)
|
||||
|
||||
def _auth(self, icn, text, ad):
|
||||
icn[0] |= 0x80
|
||||
enc = self.encrypter(bytes(icn))
|
||||
_sum = self.bs * b"\x00"
|
||||
ad_len = len(ad)
|
||||
text_len = len(text)
|
||||
while len(ad) > 0:
|
||||
_sum = strxor(_sum, self._mul(
|
||||
self.encrypter(enc),
|
||||
pad1(ad[:self.bs], self.bs),
|
||||
))
|
||||
enc = incr_l(enc, self.bs)
|
||||
ad = ad[self.bs:]
|
||||
while len(text) > 0:
|
||||
_sum = strxor(_sum, self._mul(
|
||||
self.encrypter(enc),
|
||||
pad1(text[:self.bs], self.bs),
|
||||
))
|
||||
enc = incr_l(enc, self.bs)
|
||||
text = text[self.bs:]
|
||||
_sum = strxor(_sum, self._mul(self.encrypter(enc), (
|
||||
long2bytes(ad_len * 8, size=self.bs // 2) +
|
||||
long2bytes(text_len * 8, size=self.bs // 2)
|
||||
)))
|
||||
return self.encrypter(_sum)[:self.tag_size]
|
||||
|
||||
def seal(self, nonce, plaintext, additional_data):
|
||||
"""Seal plaintext
|
||||
|
||||
:param bytes nonce: blocksize-sized nonce.
|
||||
Assure that it does not have MSB bit set
|
||||
(:py:func:`pygost.mgm.nonce_prepare` helps)
|
||||
:param bytes plaintext: plaintext to be encrypted and authenticated
|
||||
:param bytes additional_data: additional data to be authenticated
|
||||
"""
|
||||
self._validate_nonce(nonce)
|
||||
self._validate_sizes(plaintext, additional_data)
|
||||
icn = bytearray(nonce)
|
||||
ciphertext = self._crypt(icn, plaintext)
|
||||
tag = self._auth(icn, ciphertext, additional_data)
|
||||
return ciphertext + tag
|
||||
|
||||
def open(self, nonce, ciphertext, additional_data):
|
||||
"""Open ciphertext
|
||||
|
||||
:param bytes nonce: blocksize-sized nonce.
|
||||
Assure that it does not have MSB bit set
|
||||
(:py:func:`pygost.mgm.nonce_prepare` helps)
|
||||
:param bytes ciphertext: ciphertext to be decrypted and authenticated
|
||||
:param bytes additional_data: additional data to be authenticated
|
||||
:raises ValueError: if ciphertext authentication fails
|
||||
"""
|
||||
self._validate_nonce(nonce)
|
||||
self._validate_sizes(ciphertext, additional_data)
|
||||
icn = bytearray(nonce)
|
||||
ciphertext, tag_expected = (
|
||||
ciphertext[:-self.tag_size],
|
||||
ciphertext[-self.tag_size:],
|
||||
)
|
||||
tag = self._auth(icn, ciphertext, additional_data)
|
||||
if not compare_digest(tag_expected, tag):
|
||||
raise ValueError("Invalid authentication tag")
|
||||
return self._crypt(icn, ciphertext)
|
||||
@ -1,41 +0,0 @@
|
||||
# coding: utf-8
|
||||
"""PBKDF2 implementation suitable for GOST R 34.11-94/34.11-2012.
|
||||
|
||||
This implementation is based on Python 3.5.2 source code's one.
|
||||
PyGOST does not register itself in hashlib anyway, so use it instead.
|
||||
"""
|
||||
|
||||
|
||||
from pygost.utils import bytes2long
|
||||
from pygost.utils import long2bytes
|
||||
from pygost.utils import strxor
|
||||
from pygost.utils import xrange
|
||||
|
||||
|
||||
def pbkdf2(hasher, password, salt, iterations, dklen):
|
||||
"""PBKDF2 implementation suitable for GOST R 34.11-94/34.11-2012
|
||||
"""
|
||||
inner = hasher()
|
||||
outer = hasher()
|
||||
password = password + b"\x00" * (inner.block_size - len(password))
|
||||
inner.update(strxor(password, len(password) * b"\x36"))
|
||||
outer.update(strxor(password, len(password) * b"\x5C"))
|
||||
|
||||
def prf(msg):
|
||||
icpy = inner.copy()
|
||||
ocpy = outer.copy()
|
||||
icpy.update(msg)
|
||||
ocpy.update(icpy.digest())
|
||||
return ocpy.digest()
|
||||
|
||||
dkey = b""
|
||||
loop = 1
|
||||
while len(dkey) < dklen:
|
||||
prev = prf(salt + long2bytes(loop, 4))
|
||||
rkey = bytes2long(prev)
|
||||
for _ in xrange(iterations - 1):
|
||||
prev = prf(prev)
|
||||
rkey ^= bytes2long(prev)
|
||||
loop += 1
|
||||
dkey += long2bytes(rkey, inner.digest_size)
|
||||
return dkey[:dklen]
|
||||
@ -1,101 +0,0 @@
|
||||
from typing import Callable
|
||||
from typing import Dict
|
||||
from typing import Sequence
|
||||
from typing import Tuple
|
||||
|
||||
|
||||
SBOXES = ... # type: Dict[str, Tuple[Tuple[int, ...], ...]]
|
||||
BLOCKSIZE = ... # type: int
|
||||
|
||||
Words = Tuple[int, int]
|
||||
|
||||
|
||||
def block2ns(data: bytes) -> Words: ...
|
||||
|
||||
|
||||
def ns2block(ns: Words) -> bytes: ...
|
||||
|
||||
|
||||
def validate_key(key: bytes) -> None: ...
|
||||
|
||||
|
||||
def validate_iv(iv: bytes) -> None: ...
|
||||
|
||||
|
||||
def validate_sbox(sbox: str) -> None: ...
|
||||
|
||||
|
||||
def xcrypt(seq: Sequence[int], sbox: str, key: bytes, ns: Words) -> Words: ...
|
||||
|
||||
|
||||
def encrypt(sbox: str, key: bytes, ns: Words) -> Words: ...
|
||||
|
||||
|
||||
def decrypt(sbox: str, key: bytes, ns: Words) -> Words: ...
|
||||
|
||||
|
||||
def ecb(
|
||||
key: bytes,
|
||||
data: bytes,
|
||||
action: Callable[[str, bytes, Words], Words],
|
||||
sbox: str = ...,
|
||||
) -> bytes: ...
|
||||
|
||||
|
||||
def ecb_encrypt(
|
||||
key: bytes,
|
||||
data: bytes,
|
||||
sbox: str = ...,
|
||||
) -> bytes: ...
|
||||
|
||||
|
||||
def ecb_decrypt(
|
||||
key: bytes,
|
||||
data: bytes,
|
||||
sbox: str = ...,
|
||||
) -> bytes: ...
|
||||
|
||||
|
||||
def cbc_encrypt(
|
||||
key: bytes,
|
||||
data: bytes,
|
||||
iv: bytes = ...,
|
||||
pad: bool = ...,
|
||||
sbox: str = ...,
|
||||
mesh: bool = ...,
|
||||
) -> bytes: ...
|
||||
|
||||
|
||||
def cbc_decrypt(
|
||||
key: bytes,
|
||||
data: bytes,
|
||||
pad: bool = ...,
|
||||
sbox: str = ...,
|
||||
mesh: bool = ...,
|
||||
) -> bytes: ...
|
||||
|
||||
|
||||
def cnt(
|
||||
key: bytes,
|
||||
data: bytes,
|
||||
iv: bytes = ...,
|
||||
sbox: str = ...,
|
||||
) -> bytes: ...
|
||||
|
||||
|
||||
def cfb_encrypt(
|
||||
key: bytes,
|
||||
data: bytes,
|
||||
iv: bytes = ...,
|
||||
sbox: str = ...,
|
||||
mesh: bool = ...,
|
||||
) -> bytes: ...
|
||||
|
||||
|
||||
def cfb_decrypt(
|
||||
key: bytes,
|
||||
data: bytes,
|
||||
iv: bytes = ...,
|
||||
sbox: str = ...,
|
||||
mesh: bool = ...,
|
||||
) -> bytes: ...
|
||||
@ -1,25 +0,0 @@
|
||||
from pygost.iface import PEP247
|
||||
|
||||
|
||||
class MAC(PEP247):
|
||||
def __init__(
|
||||
self,
|
||||
key: bytes,
|
||||
data: bytes = ...,
|
||||
iv: bytes = ...,
|
||||
sbox: str = ...,
|
||||
) -> None: ...
|
||||
|
||||
@property
|
||||
def digest_size(self) -> int: ...
|
||||
|
||||
def copy(self) -> "MAC": ...
|
||||
|
||||
def update(self, data: bytes) -> None: ...
|
||||
|
||||
def digest(self) -> bytes: ...
|
||||
|
||||
def hexdigest(self) -> str: ...
|
||||
|
||||
|
||||
def new(key: bytes, data: bytes = ..., iv: bytes = ..., sbox: str = ...) -> MAC: ...
|
||||
@ -1,72 +0,0 @@
|
||||
from typing import Dict
|
||||
from typing import Tuple
|
||||
|
||||
|
||||
DEFAULT_CURVE = ... # type: GOST3410Curve
|
||||
CURVES = ... # type: Dict[str, GOST3410Curve]
|
||||
PublicKey = Tuple[int, int]
|
||||
|
||||
|
||||
class GOST3410Curve(object):
|
||||
p = ... # type: int
|
||||
q = ... # type: int
|
||||
a = ... # type: int
|
||||
b = ... # type: int
|
||||
x = ... # type: int
|
||||
y = ... # type: int
|
||||
cofactor = ... # type: int
|
||||
e = ... # type: int
|
||||
d = ... # type: int
|
||||
name = ... # type: str
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
p: int,
|
||||
q: int,
|
||||
a: int,
|
||||
b: int,
|
||||
x: int,
|
||||
y: int,
|
||||
cofactor: int = 1,
|
||||
e: int = None,
|
||||
d: int = None,
|
||||
name: str = None,
|
||||
) -> None: ...
|
||||
|
||||
def pos(self, v: int) -> int: ...
|
||||
|
||||
def exp(self, degree: int, x: int = ..., y: int = ...) -> int: ...
|
||||
|
||||
def st(self) -> Tuple[int, int]: ...
|
||||
|
||||
@property
|
||||
def point_size(self) -> int: ...
|
||||
|
||||
def contains(self, point: Tuple[int, int]) -> bool: ...
|
||||
|
||||
|
||||
def public_key(curve: GOST3410Curve, prv: int) -> PublicKey: ...
|
||||
|
||||
|
||||
def sign(curve: GOST3410Curve, prv: int, digest: bytes, rand: bytes = None) -> bytes: ...
|
||||
|
||||
|
||||
def verify(curve: GOST3410Curve, pub: PublicKey, digest: bytes, signature: bytes) -> bool: ...
|
||||
|
||||
|
||||
def prv_unmarshal(prv: bytes) -> int: ...
|
||||
|
||||
|
||||
def prv_marshal(curve: GOST3410Curve, prv: int) -> bytes: ...
|
||||
|
||||
|
||||
def pub_marshal(pub: PublicKey) -> bytes: ...
|
||||
|
||||
|
||||
def pub_unmarshal(pub: bytes) -> PublicKey: ...
|
||||
|
||||
|
||||
def uv2xy(curve: GOST3410Curve, u: int, v: int) -> Tuple[int, int]: ...
|
||||
|
||||
|
||||
def xy2uv(curve: GOST3410Curve, x: int, y: int) -> Tuple[int, int]: ...
|
||||
@ -1,17 +0,0 @@
|
||||
from pygost.gost3410 import GOST3410Curve
|
||||
from pygost.gost3410 import PublicKey
|
||||
|
||||
|
||||
def ukm_unmarshal(ukm: bytes) -> int: ...
|
||||
|
||||
|
||||
def kek(curve: GOST3410Curve, prv: int, pub: PublicKey, ukm: int) -> bytes: ...
|
||||
|
||||
|
||||
def kek_34102001(curve: GOST3410Curve, prv: int, pub: PublicKey, ukm: int) -> bytes: ...
|
||||
|
||||
|
||||
def kek_34102012256(curve: GOST3410Curve, prv: int, pub: PublicKey, ukm: int = ...) -> bytes: ...
|
||||
|
||||
|
||||
def kek_34102012512(curve: GOST3410Curve, prv: int, pub: PublicKey, ukm: int = ...) -> bytes: ...
|
||||
@ -1,18 +0,0 @@
|
||||
from pygost.iface import PEP247
|
||||
|
||||
|
||||
class GOST34112012(PEP247):
|
||||
block_size = ... # type: int
|
||||
|
||||
def __init__(self, data: bytes = ..., digest_size: int = ...) -> None: ...
|
||||
|
||||
@property
|
||||
def digest_size(self) -> int: ...
|
||||
|
||||
def copy(self) -> "GOST34112012": ...
|
||||
|
||||
def update(self, data: bytes) -> None: ...
|
||||
|
||||
def digest(self) -> bytes: ...
|
||||
|
||||
def hexdigest(self) -> str: ...
|
||||
@ -1,21 +0,0 @@
|
||||
from pygost.iface import PEP247
|
||||
|
||||
|
||||
class GOST34112012256(PEP247):
|
||||
block_size = ... # type: int
|
||||
|
||||
def __init__(self, data: bytes = ...) -> None: ...
|
||||
|
||||
@property
|
||||
def digest_size(self) -> int: ...
|
||||
|
||||
def copy(self) -> "GOST34112012256": ...
|
||||
|
||||
def update(self, data: bytes) -> None: ...
|
||||
|
||||
def digest(self) -> bytes: ...
|
||||
|
||||
def hexdigest(self) -> str: ...
|
||||
|
||||
|
||||
def new(data: bytes = ...) -> GOST34112012256: ...
|
||||
@ -1,24 +0,0 @@
|
||||
from pygost.iface import PEP247
|
||||
|
||||
|
||||
class GOST34112012512(PEP247):
|
||||
block_size = ... # type: int
|
||||
|
||||
def __init__(self, data: bytes = ...) -> None: ...
|
||||
|
||||
@property
|
||||
def digest_size(self) -> int: ...
|
||||
|
||||
def copy(self) -> "GOST34112012512": ...
|
||||
|
||||
def update(self, data: bytes) -> None: ...
|
||||
|
||||
def digest(self) -> bytes: ...
|
||||
|
||||
def hexdigest(self) -> str: ...
|
||||
|
||||
|
||||
def new(data: bytes = ...) -> GOST34112012512: ...
|
||||
|
||||
|
||||
def pbkdf2(password: bytes, salt: bytes, iterations: int, dklen: int) -> bytes: ...
|
||||
@ -1,25 +0,0 @@
|
||||
from pygost.iface import PEP247
|
||||
|
||||
|
||||
class GOST341194(PEP247):
|
||||
sbox = ... # type: str
|
||||
block_size = ... # type: int
|
||||
|
||||
def __init__(self, data: bytes = ..., sbox: str = ...) -> None: ...
|
||||
|
||||
@property
|
||||
def digest_size(self) -> int: ...
|
||||
|
||||
def copy(self) -> "GOST341194": ...
|
||||
|
||||
def update(self, data: bytes) -> None: ...
|
||||
|
||||
def digest(self) -> bytes: ...
|
||||
|
||||
def hexdigest(self) -> str: ...
|
||||
|
||||
|
||||
def new(data: bytes = ..., sbox: str = ...) -> GOST341194: ...
|
||||
|
||||
|
||||
def pbkdf2(password: bytes, salt: bytes, iterations: int, dklen: int) -> bytes: ...
|
||||
@ -1,18 +0,0 @@
|
||||
class GOST3412Kuznechik(object):
|
||||
blocksize = ... # type: int
|
||||
|
||||
def __init__(self, key: bytes) -> None: ...
|
||||
|
||||
def encrypt(self, blk: bytes) -> bytes: ...
|
||||
|
||||
def decrypt(self, blk: bytes) -> bytes: ...
|
||||
|
||||
|
||||
class GOST3412Magma(object):
|
||||
blocksize = ... # type: int
|
||||
|
||||
def __init__(self, key: bytes) -> None: ...
|
||||
|
||||
def encrypt(self, blk: bytes) -> bytes: ...
|
||||
|
||||
def decrypt(self, blk: bytes) -> bytes: ...
|
||||
@ -1,81 +0,0 @@
|
||||
from typing import Callable
|
||||
|
||||
|
||||
def pad_size(data_size: int, blocksize: int) -> int: ...
|
||||
|
||||
|
||||
def pad1(data: bytes, blocksize: int) -> bytes: ...
|
||||
|
||||
|
||||
def pad2(data: bytes, blocksize: int) -> bytes: ...
|
||||
|
||||
|
||||
def unpad2(data: bytes, blocksize: int) -> bytes: ...
|
||||
|
||||
|
||||
def pad3(data: bytes, blocksize: int) -> bytes: ...
|
||||
|
||||
|
||||
def ecb_encrypt(encrypter: Callable[[bytes], bytes], bs: int, pt: bytes) -> bytes: ...
|
||||
|
||||
|
||||
def ecb_decrypt(decrypter: Callable[[bytes], bytes], bs: int, ct: bytes) -> bytes: ...
|
||||
|
||||
|
||||
def acpkm(encrypter: Callable[[bytes], bytes], bs: int) -> bytes: ...
|
||||
|
||||
|
||||
def ctr(encrypter: Callable[[bytes], bytes], bs: int, data: bytes, iv: bytes) -> bytes: ...
|
||||
|
||||
|
||||
def ctr_acpkm(
|
||||
algo_class: object,
|
||||
encrypter: Callable[[bytes], bytes],
|
||||
section_size: int,
|
||||
bs: int,
|
||||
data: bytes,
|
||||
iv: bytes,
|
||||
) -> bytes: ...
|
||||
|
||||
|
||||
def ofb(encrypter: Callable[[bytes], bytes], bs: int, data: bytes, iv: bytes) -> bytes: ...
|
||||
|
||||
|
||||
def cbc_encrypt(encrypter: Callable[[bytes], bytes], bs: int, pt: bytes, iv: bytes) -> bytes: ...
|
||||
|
||||
|
||||
def cbc_decrypt(decrypter: Callable[[bytes], bytes], bs: int, ct: bytes, iv: bytes) -> bytes: ...
|
||||
|
||||
|
||||
def cfb_encrypt(encrypter: Callable[[bytes], bytes], bs: int, pt: bytes, iv: bytes) -> bytes: ...
|
||||
|
||||
|
||||
def cfb_decrypt(encrypter: Callable[[bytes], bytes], bs: int, ct: bytes, iv: bytes) -> bytes: ...
|
||||
|
||||
|
||||
def mac(encrypter: Callable[[bytes], bytes], bs: int, data: bytes) -> bytes: ...
|
||||
|
||||
|
||||
def acpkm_master(
|
||||
algo_class: object,
|
||||
encrypter: Callable[[bytes], bytes],
|
||||
key_section_size: int,
|
||||
bs: int,
|
||||
keymat_len: int,
|
||||
) -> bytes: ...
|
||||
|
||||
|
||||
def mac_acpkm_master(
|
||||
algo_class: object,
|
||||
encrypter: Callable[[bytes], bytes],
|
||||
key_section_size: int,
|
||||
section_size: int,
|
||||
bs: int,
|
||||
data: bytes,
|
||||
) -> bytes: ...
|
||||
|
||||
|
||||
def pad_iso10126(data: bytes, blocksize: int) -> bytes: ...
|
||||
|
||||
|
||||
def unpad_iso10126(data: bytes, blocksize: int) -> bytes: ...
|
||||
@ -1,19 +0,0 @@
|
||||
from abc import ABCMeta
|
||||
from abc import abstractmethod
|
||||
|
||||
|
||||
class PEP247(metaclass=ABCMeta):
|
||||
@abstractmethod
|
||||
@property
|
||||
def digest_size(self) -> int: ...
|
||||
|
||||
@abstractmethod
|
||||
def copy(self) -> "PEP247": ...
|
||||
|
||||
@abstractmethod
|
||||
def update(self, data: bytes) -> None: ...
|
||||
|
||||
@abstractmethod
|
||||
def digest(self) -> bytes: ...
|
||||
|
||||
def hexdigest(self) -> str: ...
|
||||
@ -1,22 +0,0 @@
|
||||
from typing import Sequence
|
||||
from typing import Tuple
|
||||
|
||||
from pygost.gost3410 import GOST3410Curve
|
||||
|
||||
|
||||
PublicKey = Tuple[int, int]
|
||||
|
||||
|
||||
def kdf_gostr3411_2012_256(key: bytes, label: bytes, seed: bytes) -> bytes: ...
|
||||
|
||||
|
||||
def kdf_tree_gostr3411_2012_256(
|
||||
key: bytes,
|
||||
label: bytes,
|
||||
seed: bytes,
|
||||
keys: int,
|
||||
i_len: int = 1,
|
||||
) -> Sequence[bytes]: ...
|
||||
|
||||
|
||||
def keg(curve: GOST3410Curve, prv: int, pub: PublicKey, h: bytes) -> bytes: ...
|
||||
@ -1,17 +0,0 @@
|
||||
from typing import Callable
|
||||
|
||||
|
||||
def nonce_prepare(nonce: bytes) -> bytes: ...
|
||||
|
||||
|
||||
class MGM(object):
|
||||
def __init__(
|
||||
self,
|
||||
encrypter: Callable[[bytes], bytes],
|
||||
bs: int,
|
||||
tag_size: int = None,
|
||||
) -> None: ...
|
||||
|
||||
def seal(self, nonce: bytes, plaintext: bytes, additional_data: bytes) -> bytes: ...
|
||||
|
||||
def open(self, nonce: bytes, ciphertext: bytes, additional_data: bytes) -> bytes: ...
|
||||
@ -1,19 +0,0 @@
|
||||
from typing import AnyStr
|
||||
|
||||
|
||||
def strxor(a: bytes, b: bytes) -> bytes: ...
|
||||
|
||||
|
||||
def hexdec(data: AnyStr) -> bytes: ...
|
||||
|
||||
|
||||
def hexenc(data: bytes) -> str: ...
|
||||
|
||||
|
||||
def bytes2long(raw: bytes) -> int: ...
|
||||
|
||||
|
||||
def long2bytes(n: int, size: int = ...) -> bytes: ...
|
||||
|
||||
|
||||
def modinvert(a: int, n: int) -> int: ...
|
||||
@ -1,31 +0,0 @@
|
||||
from typing import Callable
|
||||
|
||||
|
||||
def wrap_gost(ukm: bytes, kek: bytes, cek: bytes, sbox: str = ...) -> bytes: ...
|
||||
|
||||
|
||||
def unwrap_gost(kek: bytes, data: bytes, sbox: str = ...) -> bytes: ...
|
||||
|
||||
|
||||
def wrap_cryptopro(ukm: bytes, kek: bytes, cek: bytes, sbox: str = ...) -> bytes: ...
|
||||
|
||||
|
||||
def unwrap_cryptopro(kek: bytes, data: bytes, sbox: str = ...) -> bytes: ...
|
||||
|
||||
|
||||
def kexp15(
|
||||
encrypter_key: Callable[[bytes], bytes],
|
||||
encrypter_mac: Callable[[bytes], bytes],
|
||||
bs: int,
|
||||
key: bytes,
|
||||
iv: bytes,
|
||||
) -> bytes: ...
|
||||
|
||||
|
||||
def kimp15(
|
||||
encrypter_key: Callable[[bytes], bytes],
|
||||
encrypter_mac: Callable[[bytes], bytes],
|
||||
bs: int,
|
||||
kexp: bytes,
|
||||
iv: bytes,
|
||||
) -> bytes: ...
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,384 +0,0 @@
|
||||
# coding: utf-8
|
||||
# PyGOST -- Pure Python GOST cryptographic functions library
|
||||
# Copyright (C) 2015-2023 Sergey Matveev <stargrave@stargrave.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, version 3 of the License.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from os import urandom
|
||||
from unittest import TestCase
|
||||
|
||||
from pygost.gost28147 import block2ns
|
||||
from pygost.gost28147 import BLOCKSIZE
|
||||
from pygost.gost28147 import cbc_decrypt
|
||||
from pygost.gost28147 import cbc_encrypt
|
||||
from pygost.gost28147 import cfb_decrypt
|
||||
from pygost.gost28147 import cfb_encrypt
|
||||
from pygost.gost28147 import cnt
|
||||
from pygost.gost28147 import DEFAULT_SBOX
|
||||
from pygost.gost28147 import ecb_decrypt
|
||||
from pygost.gost28147 import ecb_encrypt
|
||||
from pygost.gost28147 import encrypt
|
||||
from pygost.gost28147 import KEYSIZE
|
||||
from pygost.gost28147 import MESH_MAX_DATA
|
||||
from pygost.gost28147 import ns2block
|
||||
from pygost.utils import hexdec
|
||||
from pygost.utils import strxor
|
||||
|
||||
|
||||
class ECBTest(TestCase):
|
||||
def test_gcl(self):
|
||||
"""Test vectors from libgcl3
|
||||
"""
|
||||
sbox = "id-Gost28147-89-TestParamSet"
|
||||
key = hexdec(b"0475f6e05038fbfad2c7c390edb3ca3d1547124291ae1e8a2f79cd9ed2bcefbd")
|
||||
plaintext = bytes(bytearray((
|
||||
0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
|
||||
0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
|
||||
0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10,
|
||||
0x1f, 0x1e, 0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18,
|
||||
0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x20,
|
||||
0x2f, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28,
|
||||
0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30,
|
||||
0x3f, 0x3e, 0x3d, 0x3c, 0x3b, 0x3a, 0x39, 0x38,
|
||||
0x47, 0x46, 0x45, 0x44, 0x43, 0x42, 0x41, 0x40,
|
||||
0x4f, 0x4e, 0x4d, 0x4c, 0x4b, 0x4a, 0x49, 0x48,
|
||||
0x57, 0x56, 0x55, 0x54, 0x53, 0x52, 0x51, 0x50,
|
||||
0x5f, 0x5e, 0x5d, 0x5c, 0x5b, 0x5a, 0x59, 0x58,
|
||||
0x67, 0x66, 0x65, 0x64, 0x63, 0x62, 0x61, 0x60,
|
||||
0x6f, 0x6e, 0x6d, 0x6c, 0x6b, 0x6a, 0x69, 0x68,
|
||||
0x77, 0x76, 0x75, 0x74, 0x73, 0x72, 0x71, 0x70,
|
||||
0x7f, 0x7e, 0x7d, 0x7c, 0x7b, 0x7a, 0x79, 0x78,
|
||||
0x87, 0x86, 0x85, 0x84, 0x83, 0x82, 0x81, 0x80,
|
||||
0x8f, 0x8e, 0x8d, 0x8c, 0x8b, 0x8a, 0x89, 0x88,
|
||||
0x97, 0x96, 0x95, 0x94, 0x93, 0x92, 0x91, 0x90,
|
||||
0x9f, 0x9e, 0x9d, 0x9c, 0x9b, 0x9a, 0x99, 0x98,
|
||||
0xa7, 0xa6, 0xa5, 0xa4, 0xa3, 0xa2, 0xa1, 0xa0,
|
||||
0xaf, 0xae, 0xad, 0xac, 0xab, 0xaa, 0xa9, 0xa8,
|
||||
0xb7, 0xb6, 0xb5, 0xb4, 0xb3, 0xb2, 0xb1, 0xb0,
|
||||
0xbf, 0xbe, 0xbd, 0xbc, 0xbb, 0xba, 0xb9, 0xb8,
|
||||
0xc7, 0xc6, 0xc5, 0xc4, 0xc3, 0xc2, 0xc1, 0xc0,
|
||||
0xcf, 0xce, 0xcd, 0xcc, 0xcb, 0xca, 0xc9, 0xc8,
|
||||
0xd7, 0xd6, 0xd5, 0xd4, 0xd3, 0xd2, 0xd1, 0xd0,
|
||||
0xdf, 0xde, 0xdd, 0xdc, 0xdb, 0xda, 0xd9, 0xd8,
|
||||
0xe7, 0xe6, 0xe5, 0xe4, 0xe3, 0xe2, 0xe1, 0xe0,
|
||||
0xef, 0xee, 0xed, 0xec, 0xeb, 0xea, 0xe9, 0xe8,
|
||||
0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf2, 0xf1, 0xf0,
|
||||
0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8,
|
||||
)))
|
||||
ciphertext = bytes(bytearray((
|
||||
0x4b, 0x8c, 0x4c, 0x98, 0x15, 0xf2, 0x4a, 0xea,
|
||||
0x1e, 0xc3, 0x57, 0x09, 0xb3, 0xbc, 0x2e, 0xd1,
|
||||
0xe0, 0xd1, 0xf2, 0x22, 0x65, 0x2d, 0x59, 0x18,
|
||||
0xf7, 0xdf, 0xfc, 0x80, 0x4b, 0xde, 0x5c, 0x68,
|
||||
0x46, 0x53, 0x75, 0x53, 0xa7, 0x46, 0x0d, 0xec,
|
||||
0x05, 0x1f, 0x1b, 0xd3, 0x0a, 0x63, 0x1a, 0xb7,
|
||||
0x78, 0xc4, 0x43, 0xe0, 0x5d, 0x3e, 0xa4, 0x0e,
|
||||
0x2d, 0x7e, 0x23, 0xa9, 0x1b, 0xc9, 0x02, 0xbc,
|
||||
0x21, 0x0c, 0x84, 0xcb, 0x0d, 0x0a, 0x07, 0xc8,
|
||||
0x7b, 0xd0, 0xfb, 0xb5, 0x1a, 0x14, 0x04, 0x5c,
|
||||
0xa2, 0x53, 0x97, 0x71, 0x2e, 0x5c, 0xc2, 0x8f,
|
||||
0x39, 0x3f, 0x6f, 0x52, 0xf2, 0x30, 0x26, 0x4e,
|
||||
0x8c, 0xe0, 0xd1, 0x01, 0x75, 0x6d, 0xdc, 0xd3,
|
||||
0x03, 0x79, 0x1e, 0xca, 0xd5, 0xc1, 0x0e, 0x12,
|
||||
0x53, 0x0a, 0x78, 0xe2, 0x0a, 0xb1, 0x1c, 0xea,
|
||||
0x3a, 0xf8, 0x55, 0xb9, 0x7c, 0xe1, 0x0b, 0xba,
|
||||
0xa0, 0xc8, 0x96, 0xeb, 0x50, 0x5a, 0xd3, 0x60,
|
||||
0x43, 0xa3, 0x0f, 0x98, 0xdb, 0xd9, 0x50, 0x6d,
|
||||
0x63, 0x91, 0xaf, 0x01, 0x40, 0xe9, 0x75, 0x5a,
|
||||
0x46, 0x5c, 0x1f, 0x19, 0x4a, 0x0b, 0x89, 0x9b,
|
||||
0xc4, 0xf6, 0xf8, 0xf5, 0x2f, 0x87, 0x3f, 0xfa,
|
||||
0x26, 0xd4, 0xf8, 0x25, 0xba, 0x1f, 0x98, 0x82,
|
||||
0xfc, 0x26, 0xaf, 0x2d, 0xc0, 0xf9, 0xc4, 0x58,
|
||||
0x49, 0xfa, 0x09, 0x80, 0x02, 0x62, 0xa4, 0x34,
|
||||
0x2d, 0xcb, 0x5a, 0x6b, 0xab, 0x61, 0x5d, 0x08,
|
||||
0xd4, 0x26, 0xe0, 0x08, 0x13, 0xd6, 0x2e, 0x02,
|
||||
0x2a, 0x37, 0xe8, 0xd0, 0xcf, 0x36, 0xf1, 0xc7,
|
||||
0xc0, 0x3f, 0x9b, 0x21, 0x60, 0xbd, 0x29, 0x2d,
|
||||
0x2e, 0x01, 0x48, 0x4e, 0xf8, 0x8f, 0x20, 0x16,
|
||||
0x8a, 0xbf, 0x82, 0xdc, 0x32, 0x7a, 0xa3, 0x18,
|
||||
0x69, 0xd1, 0x50, 0x59, 0x31, 0x91, 0xf2, 0x6c,
|
||||
0x5a, 0x5f, 0xca, 0x58, 0x9a, 0xb2, 0x2d, 0xb2,
|
||||
)))
|
||||
encrypted = ecb_encrypt(key, plaintext, sbox=sbox)
|
||||
self.assertSequenceEqual(encrypted, ciphertext)
|
||||
decrypted = ecb_decrypt(key, encrypted, sbox=sbox)
|
||||
self.assertSequenceEqual(decrypted, plaintext)
|
||||
|
||||
def test_cryptopp(self):
|
||||
"""Test vectors from Crypto++ 5.6.2
|
||||
"""
|
||||
sbox = "AppliedCryptography"
|
||||
data = (
|
||||
(b"BE5EC2006CFF9DCF52354959F1FF0CBFE95061B5A648C10387069C25997C0672", b"0DF82802B741A292", b"07F9027DF7F7DF89"),
|
||||
(b"B385272AC8D72A5A8B344BC80363AC4D09BF58F41F540624CBCB8FDCF55307D7", b"1354EE9C0A11CD4C", b"4FB50536F960A7B1"),
|
||||
(b"AEE02F609A35660E4097E546FD3026B032CD107C7D459977ADF489BEF2652262", b"6693D492C4B0CC39", b"670034AC0FA811B5"),
|
||||
(b"320E9D8422165D58911DFC7D8BBB1F81B0ECD924023BF94D9DF7DCF7801240E0", b"99E2D13080928D79", b"8118FF9D3B3CFE7D"),
|
||||
(b"C9F703BBBFC63691BFA3B7B87EA8FD5E8E8EF384EF733F1A61AEF68C8FFA265F", b"D1E787749C72814C", b"A083826A790D3E0C"),
|
||||
(b"728FEE32F04B4C654AD7F607D71C660C2C2670D7C999713233149A1C0C17A1F0", b"D4C05323A4F7A7B5", b"4D1F2E6B0D9DE2CE"),
|
||||
(b"35FC96402209500FCFDEF5352D1ABB038FE33FC0D9D58512E56370B22BAA133B", b"8742D9A05F6A3AF6", b"2F3BB84879D11E52"),
|
||||
(b"D416F630BE65B7FE150656183370E07018234EE5DA3D89C4CE9152A03E5BFB77", b"F86506DA04E41CB8", b"96F0A5C77A04F5CE"),
|
||||
)
|
||||
for key, pt, ct in data:
|
||||
key = hexdec(key)
|
||||
pt = hexdec(pt)
|
||||
ct = hexdec(ct)
|
||||
self.assertSequenceEqual(ecb_encrypt(key, pt, sbox=sbox), ct)
|
||||
|
||||
def test_cryptomanager(self):
|
||||
"""Test vector from http://cryptomanager.com/tv.html
|
||||
"""
|
||||
sbox = "id-GostR3411-94-TestParamSet"
|
||||
key = hexdec(b"75713134B60FEC45A607BB83AA3746AF4FF99DA6D1B53B5B1B402A1BAA030D1B")
|
||||
self.assertSequenceEqual(
|
||||
ecb_encrypt(key, hexdec(b"1122334455667788"), sbox=sbox),
|
||||
hexdec(b"03251E14F9D28ACB"),
|
||||
)
|
||||
|
||||
|
||||
class CFBTest(TestCase):
|
||||
def test_cryptomanager(self):
|
||||
"""Test vector from http://cryptomanager.com/tv.html
|
||||
"""
|
||||
key = hexdec(b"75713134B60FEC45A607BB83AA3746AF4FF99DA6D1B53B5B1B402A1BAA030D1B")
|
||||
sbox = "id-GostR3411-94-TestParamSet"
|
||||
self.assertSequenceEqual(
|
||||
cfb_encrypt(
|
||||
key,
|
||||
hexdec(b"112233445566778899AABBCCDD800000"),
|
||||
iv=hexdec(b"0102030405060708"),
|
||||
sbox=sbox,
|
||||
),
|
||||
hexdec(b"6EE84586DD2BCA0CAD3616940E164242"),
|
||||
)
|
||||
self.assertSequenceEqual(
|
||||
cfb_decrypt(
|
||||
key,
|
||||
hexdec(b"6EE84586DD2BCA0CAD3616940E164242"),
|
||||
iv=hexdec(b"0102030405060708"),
|
||||
sbox=sbox,
|
||||
),
|
||||
hexdec(b"112233445566778899AABBCCDD800000"),
|
||||
)
|
||||
|
||||
def test_steps(self):
|
||||
"""Check step-by-step operation manually
|
||||
"""
|
||||
key = urandom(KEYSIZE)
|
||||
iv = urandom(BLOCKSIZE)
|
||||
plaintext = urandom(20)
|
||||
ciphertext = cfb_encrypt(key, plaintext, iv)
|
||||
|
||||
# First full block
|
||||
step = encrypt(DEFAULT_SBOX, key, block2ns(iv))
|
||||
step = strxor(plaintext[:8], ns2block(step))
|
||||
self.assertSequenceEqual(step, ciphertext[:8])
|
||||
|
||||
# Second full block
|
||||
step = encrypt(DEFAULT_SBOX, key, block2ns(step))
|
||||
step = strxor(plaintext[8:16], ns2block(step))
|
||||
self.assertSequenceEqual(step, ciphertext[8:16])
|
||||
|
||||
# Third non-full block
|
||||
step = encrypt(DEFAULT_SBOX, key, block2ns(step))
|
||||
step = strxor(plaintext[16:] + 4 * b"\x00", ns2block(step))
|
||||
self.assertSequenceEqual(step[:4], ciphertext[16:])
|
||||
|
||||
def test_random(self):
|
||||
"""Random data with various sizes
|
||||
"""
|
||||
key = urandom(KEYSIZE)
|
||||
iv = urandom(BLOCKSIZE)
|
||||
for size in (5, 8, 16, 120):
|
||||
pt = urandom(size)
|
||||
self.assertSequenceEqual(
|
||||
cfb_decrypt(key, cfb_encrypt(key, pt, iv), iv),
|
||||
pt,
|
||||
)
|
||||
|
||||
|
||||
class CTRTest(TestCase):
|
||||
def test_gcl(self):
|
||||
"""Test vectors from libgcl3
|
||||
"""
|
||||
sbox = "id-Gost28147-89-TestParamSet"
|
||||
key = hexdec(b"0475f6e05038fbfad2c7c390edb3ca3d1547124291ae1e8a2f79cd9ed2bcefbd")
|
||||
plaintext = bytes(bytearray((
|
||||
0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
|
||||
0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
|
||||
0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10,
|
||||
0x1f, 0x1e, 0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18,
|
||||
0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x20,
|
||||
0x2f, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28,
|
||||
0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30,
|
||||
0x3f, 0x3e, 0x3d, 0x3c, 0x3b, 0x3a, 0x39, 0x38,
|
||||
0x47, 0x46, 0x45, 0x44, 0x43, 0x42, 0x41, 0x40,
|
||||
0x4f, 0x4e, 0x4d, 0x4c, 0x4b, 0x4a, 0x49, 0x48,
|
||||
0x57, 0x56, 0x55, 0x54, 0x53, 0x52, 0x51, 0x50,
|
||||
0x5f, 0x5e, 0x5d, 0x5c, 0x5b, 0x5a, 0x59, 0x58,
|
||||
0x67, 0x66, 0x65, 0x64, 0x63, 0x62, 0x61, 0x60,
|
||||
0x6f, 0x6e, 0x6d, 0x6c, 0x6b, 0x6a, 0x69, 0x68,
|
||||
0x77, 0x76, 0x75, 0x74, 0x73, 0x72, 0x71, 0x70,
|
||||
0x7f, 0x7e, 0x7d, 0x7c, 0x7b, 0x7a, 0x79, 0x78,
|
||||
0x87, 0x86, 0x85, 0x84, 0x83, 0x82, 0x81, 0x80,
|
||||
0x8f, 0x8e, 0x8d, 0x8c, 0x8b, 0x8a, 0x89, 0x88,
|
||||
0x97, 0x96, 0x95, 0x94, 0x93, 0x92, 0x91, 0x90,
|
||||
0x9f, 0x9e, 0x9d, 0x9c, 0x9b, 0x9a, 0x99, 0x98,
|
||||
0xa7, 0xa6, 0xa5, 0xa4, 0xa3, 0xa2, 0xa1, 0xa0,
|
||||
0xaf, 0xae, 0xad, 0xac, 0xab, 0xaa, 0xa9, 0xa8,
|
||||
0xb7, 0xb6, 0xb5, 0xb4, 0xb3, 0xb2, 0xb1, 0xb0,
|
||||
0xbf, 0xbe, 0xbd, 0xbc, 0xbb, 0xba, 0xb9, 0xb8,
|
||||
0xc7, 0xc6, 0xc5, 0xc4, 0xc3, 0xc2, 0xc1, 0xc0,
|
||||
0xcf, 0xce, 0xcd, 0xcc, 0xcb, 0xca, 0xc9, 0xc8,
|
||||
0xd7, 0xd6, 0xd5, 0xd4, 0xd3, 0xd2, 0xd1, 0xd0,
|
||||
0xdf, 0xde, 0xdd, 0xdc, 0xdb, 0xda, 0xd9, 0xd8,
|
||||
0xe7, 0xe6, 0xe5, 0xe4, 0xe3, 0xe2, 0xe1, 0xe0,
|
||||
0xef, 0xee, 0xed, 0xec, 0xeb, 0xea, 0xe9, 0xe8,
|
||||
0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf2, 0xf1, 0xf0,
|
||||
0xff, 0xfe, 0xfd, 0xfc, 0xfb,
|
||||
)))
|
||||
ciphertext = bytes(bytearray((
|
||||
0x4a, 0x5e, 0x37, 0x6c, 0xa1, 0x12, 0xd3, 0x55,
|
||||
0x09, 0x13, 0x1a, 0x21, 0xac, 0xfb, 0xb2, 0x1e,
|
||||
0x8c, 0x24, 0x9b, 0x57, 0x20, 0x68, 0x46, 0xd5,
|
||||
0x23, 0x2a, 0x26, 0x35, 0x12, 0x56, 0x5c, 0x69,
|
||||
0x2a, 0x2f, 0xd1, 0xab, 0xbd, 0x45, 0xdc, 0x3a,
|
||||
0x1a, 0xa4, 0x57, 0x64, 0xd5, 0xe4, 0x69, 0x6d,
|
||||
0xb4, 0x8b, 0xf1, 0x54, 0x78, 0x3b, 0x10, 0x8f,
|
||||
0x7a, 0x4b, 0x32, 0xe0, 0xe8, 0x4c, 0xbf, 0x03,
|
||||
0x24, 0x37, 0x95, 0x6a, 0x55, 0xa8, 0xce, 0x6f,
|
||||
0x95, 0x62, 0x12, 0xf6, 0x79, 0xe6, 0xf0, 0x1b,
|
||||
0x86, 0xef, 0x36, 0x36, 0x05, 0xd8, 0x6f, 0x10,
|
||||
0xa1, 0x41, 0x05, 0x07, 0xf8, 0xfa, 0xa4, 0x0b,
|
||||
0x17, 0x2c, 0x71, 0xbc, 0x8b, 0xcb, 0xcf, 0x3d,
|
||||
0x74, 0x18, 0x32, 0x0b, 0x1c, 0xd2, 0x9e, 0x75,
|
||||
0xba, 0x3e, 0x61, 0xe1, 0x61, 0x96, 0xd0, 0xee,
|
||||
0x8f, 0xf2, 0x9a, 0x5e, 0xb7, 0x7a, 0x15, 0xaa,
|
||||
0x4e, 0x1e, 0x77, 0x7c, 0x99, 0xe1, 0x41, 0x13,
|
||||
0xf4, 0x60, 0x39, 0x46, 0x4c, 0x35, 0xde, 0x95,
|
||||
0xcc, 0x4f, 0xd5, 0xaf, 0xd1, 0x4d, 0x84, 0x1a,
|
||||
0x45, 0xc7, 0x2a, 0xf2, 0x2c, 0xc0, 0xb7, 0x94,
|
||||
0xa3, 0x08, 0xb9, 0x12, 0x96, 0xb5, 0x97, 0x99,
|
||||
0x3a, 0xb7, 0x0c, 0x14, 0x56, 0xb9, 0xcb, 0x49,
|
||||
0x44, 0xa9, 0x93, 0xa9, 0xfb, 0x19, 0x10, 0x8c,
|
||||
0x6a, 0x68, 0xe8, 0x7b, 0x06, 0x57, 0xf0, 0xef,
|
||||
0x88, 0x44, 0xa6, 0xd2, 0x98, 0xbe, 0xd4, 0x07,
|
||||
0x41, 0x37, 0x45, 0xa6, 0x71, 0x36, 0x76, 0x69,
|
||||
0x4b, 0x75, 0x15, 0x33, 0x90, 0x29, 0x6e, 0x33,
|
||||
0xcb, 0x96, 0x39, 0x78, 0x19, 0x2e, 0x96, 0xf3,
|
||||
0x49, 0x4c, 0x89, 0x3d, 0xa1, 0x86, 0x82, 0x00,
|
||||
0xce, 0xbd, 0x54, 0x29, 0x65, 0x00, 0x1d, 0x16,
|
||||
0x13, 0xc3, 0xfe, 0x1f, 0x8c, 0x55, 0x63, 0x09,
|
||||
0x1f, 0xcd, 0xd4, 0x28, 0xca,
|
||||
)))
|
||||
iv = b"\x02\x01\x01\x01\x01\x01\x01\x01"
|
||||
encrypted = cnt(key, plaintext, iv=iv, sbox=sbox)
|
||||
self.assertSequenceEqual(encrypted, ciphertext)
|
||||
decrypted = cnt(key, encrypted, iv=iv, sbox=sbox)
|
||||
self.assertSequenceEqual(decrypted, plaintext)
|
||||
|
||||
def test_gcl2(self):
|
||||
"""Test vectors 2 from libgcl3
|
||||
"""
|
||||
sbox = "id-Gost28147-89-TestParamSet"
|
||||
key = hexdec(b"fc7ad2886f455b50d29008fa622b57d5c65b3c637202025799cadf0768519e8a")
|
||||
plaintext = bytes(bytearray((
|
||||
0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,
|
||||
0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08,
|
||||
0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10,
|
||||
0x1f, 0x1e, 0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18,
|
||||
0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x20,
|
||||
0x2f, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28,
|
||||
0xff, 0xfe, 0xfd, 0xfc, 0xfb,
|
||||
)))
|
||||
ciphertext = bytes(bytearray((
|
||||
0xd0, 0xbe, 0x60, 0x1a, 0x2c, 0xf1, 0x90, 0x26,
|
||||
0x9b, 0x7b, 0x23, 0xb4, 0xd2, 0xcc, 0xe1, 0x15,
|
||||
0xf6, 0x05, 0x57, 0x28, 0x88, 0x75, 0xeb, 0x1e,
|
||||
0xd3, 0x62, 0xdc, 0xda, 0x9b, 0x62, 0xee, 0x9a,
|
||||
0x57, 0x87, 0x8a, 0xf1, 0x82, 0x37, 0x9c, 0x7f,
|
||||
0x13, 0xcc, 0x55, 0x38, 0xb5, 0x63, 0x32, 0xc5,
|
||||
0x23, 0xa4, 0xcb, 0x7d, 0x51,
|
||||
)))
|
||||
iv = BLOCKSIZE * b"\x00"
|
||||
encrypted = cnt(key, plaintext, iv=iv, sbox=sbox)
|
||||
self.assertSequenceEqual(encrypted, ciphertext)
|
||||
decrypted = cnt(key, encrypted, iv=iv, sbox=sbox)
|
||||
self.assertSequenceEqual(decrypted, plaintext)
|
||||
|
||||
|
||||
class CBCTest(TestCase):
|
||||
def test_pad_requirement(self):
|
||||
key = KEYSIZE * b"x"
|
||||
for s in (b"", b"foo", b"foobarbaz"):
|
||||
with self.assertRaises(ValueError):
|
||||
cbc_encrypt(key, s, pad=False)
|
||||
with self.assertRaises(ValueError):
|
||||
cbc_decrypt(key, s, pad=False)
|
||||
|
||||
def test_passes(self):
|
||||
iv = urandom(BLOCKSIZE)
|
||||
key = KEYSIZE * b"x"
|
||||
for pt in (b"foo", b"foobarba", b"foobarbaz", 16 * b"x"):
|
||||
ct = cbc_encrypt(key, pt, iv)
|
||||
dt = cbc_decrypt(key, ct)
|
||||
self.assertSequenceEqual(pt, dt)
|
||||
|
||||
def test_iv_existence_check(self):
|
||||
key = KEYSIZE * b"x"
|
||||
with self.assertRaises(ValueError):
|
||||
cbc_decrypt(key, BLOCKSIZE * b"x")
|
||||
iv = urandom(BLOCKSIZE)
|
||||
cbc_decrypt(key, cbc_encrypt(key, BLOCKSIZE * b"x", iv))
|
||||
|
||||
def test_meshing(self):
|
||||
pt = urandom(MESH_MAX_DATA * 3)
|
||||
key = urandom(KEYSIZE)
|
||||
ct = cbc_encrypt(key, pt)
|
||||
dt = cbc_decrypt(key, ct)
|
||||
self.assertSequenceEqual(pt, dt)
|
||||
|
||||
|
||||
class CFBMeshingTest(TestCase):
|
||||
def setUp(self):
|
||||
self.key = urandom(KEYSIZE)
|
||||
self.iv = urandom(BLOCKSIZE)
|
||||
|
||||
def test_single(self):
|
||||
pt = b"\x00"
|
||||
ct = cfb_encrypt(self.key, pt, mesh=True)
|
||||
dec = cfb_decrypt(self.key, ct, mesh=True)
|
||||
self.assertSequenceEqual(pt, dec)
|
||||
|
||||
def test_short(self):
|
||||
pt = urandom(MESH_MAX_DATA - 1)
|
||||
ct = cfb_encrypt(self.key, pt, mesh=True)
|
||||
dec = cfb_decrypt(self.key, ct, mesh=True)
|
||||
dec_plain = cfb_decrypt(self.key, ct)
|
||||
self.assertSequenceEqual(pt, dec)
|
||||
self.assertSequenceEqual(pt, dec_plain)
|
||||
|
||||
def test_short_iv(self):
|
||||
pt = urandom(MESH_MAX_DATA - 1)
|
||||
ct = cfb_encrypt(self.key, pt, iv=self.iv, mesh=True)
|
||||
dec = cfb_decrypt(self.key, ct, iv=self.iv, mesh=True)
|
||||
dec_plain = cfb_decrypt(self.key, ct, iv=self.iv)
|
||||
self.assertSequenceEqual(pt, dec)
|
||||
self.assertSequenceEqual(pt, dec_plain)
|
||||
|
||||
def test_longer_iv(self):
|
||||
pt = urandom(MESH_MAX_DATA * 3)
|
||||
ct = cfb_encrypt(self.key, pt, iv=self.iv, mesh=True)
|
||||
dec = cfb_decrypt(self.key, ct, iv=self.iv, mesh=True)
|
||||
dec_plain = cfb_decrypt(self.key, ct, iv=self.iv)
|
||||
self.assertSequenceEqual(pt, dec)
|
||||
self.assertNotEqual(pt, dec_plain)
|
||||
@ -1,63 +0,0 @@
|
||||
# coding: utf-8
|
||||
# PyGOST -- Pure Python GOST cryptographic functions library
|
||||
# Copyright (C) 2015-2023 Sergey Matveev <stargrave@stargrave.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, version 3 of the License.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from unittest import TestCase
|
||||
|
||||
from pygost.gost28147_mac import MAC
|
||||
|
||||
|
||||
class TestMAC(TestCase):
|
||||
"""Test vectors generated with libgcl3 library
|
||||
"""
|
||||
k = b"This is message\xFF length\x0032 bytes"
|
||||
|
||||
def test_a(self):
|
||||
self.assertSequenceEqual(
|
||||
MAC(self.k, b"a").hexdigest(),
|
||||
"bd5d3b5b2b7b57af",
|
||||
)
|
||||
|
||||
def test_abc(self):
|
||||
self.assertSequenceEqual(
|
||||
MAC(self.k, b"abc").hexdigest(),
|
||||
"28661e40805b1ff9",
|
||||
)
|
||||
|
||||
def test_128U(self):
|
||||
self.assertSequenceEqual(
|
||||
MAC(self.k, 128 * b"U").hexdigest(),
|
||||
"1a06d1bad74580ef",
|
||||
)
|
||||
|
||||
def test_13x(self):
|
||||
self.assertSequenceEqual(
|
||||
MAC(self.k, 13 * b"x").hexdigest(),
|
||||
"917ee1f1a668fbd3",
|
||||
)
|
||||
|
||||
def test_parts(self):
|
||||
m = MAC(self.k)
|
||||
m.update(b"foo")
|
||||
m.update(b"bar")
|
||||
self.assertSequenceEqual(m.digest(), MAC(self.k, b"foobar").digest())
|
||||
|
||||
def test_copy(self):
|
||||
m = MAC(self.k, b"foo")
|
||||
c = m.copy()
|
||||
m.update(b"barbaz")
|
||||
c.update(b"bar")
|
||||
c.update(b"baz")
|
||||
self.assertSequenceEqual(m.digest(), c.digest())
|
||||
@ -1,495 +0,0 @@
|
||||
# coding: utf-8
|
||||
# PyGOST -- Pure Python GOST cryptographic functions library
|
||||
# Copyright (C) 2015-2023 Sergey Matveev <stargrave@stargrave.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, version 3 of the License.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from os import urandom
|
||||
from unittest import TestCase
|
||||
|
||||
from pygost.gost3410 import CURVES
|
||||
from pygost.gost3410 import GOST3410Curve
|
||||
from pygost.gost3410 import prv_marshal
|
||||
from pygost.gost3410 import prv_unmarshal
|
||||
from pygost.gost3410 import public_key
|
||||
from pygost.gost3410 import sign
|
||||
from pygost.gost3410 import uv2xy
|
||||
from pygost.gost3410 import verify
|
||||
from pygost.gost3410 import xy2uv
|
||||
from pygost.utils import bytes2long
|
||||
from pygost.utils import hexdec
|
||||
from pygost.utils import hexenc
|
||||
from pygost.utils import long2bytes
|
||||
|
||||
|
||||
class Test341001(TestCase):
|
||||
def test_rfc(self):
|
||||
"""Test vector from :rfc:`5832`
|
||||
"""
|
||||
prv = bytes(bytearray((
|
||||
0x7A, 0x92, 0x9A, 0xDE, 0x78, 0x9B, 0xB9, 0xBE,
|
||||
0x10, 0xED, 0x35, 0x9D, 0xD3, 0x9A, 0x72, 0xC1,
|
||||
0x1B, 0x60, 0x96, 0x1F, 0x49, 0x39, 0x7E, 0xEE,
|
||||
0x1D, 0x19, 0xCE, 0x98, 0x91, 0xEC, 0x3B, 0x28
|
||||
)))
|
||||
pub_x = bytes(bytearray((
|
||||
0x7F, 0x2B, 0x49, 0xE2, 0x70, 0xDB, 0x6D, 0x90,
|
||||
0xD8, 0x59, 0x5B, 0xEC, 0x45, 0x8B, 0x50, 0xC5,
|
||||
0x85, 0x85, 0xBA, 0x1D, 0x4E, 0x9B, 0x78, 0x8F,
|
||||
0x66, 0x89, 0xDB, 0xD8, 0xE5, 0x6F, 0xD8, 0x0B
|
||||
)))
|
||||
pub_y = bytes(bytearray((
|
||||
0x26, 0xF1, 0xB4, 0x89, 0xD6, 0x70, 0x1D, 0xD1,
|
||||
0x85, 0xC8, 0x41, 0x3A, 0x97, 0x7B, 0x3C, 0xBB,
|
||||
0xAF, 0x64, 0xD1, 0xC5, 0x93, 0xD2, 0x66, 0x27,
|
||||
0xDF, 0xFB, 0x10, 0x1A, 0x87, 0xFF, 0x77, 0xDA
|
||||
)))
|
||||
digest = bytes(bytearray((
|
||||
0x2D, 0xFB, 0xC1, 0xB3, 0x72, 0xD8, 0x9A, 0x11,
|
||||
0x88, 0xC0, 0x9C, 0x52, 0xE0, 0xEE, 0xC6, 0x1F,
|
||||
0xCE, 0x52, 0x03, 0x2A, 0xB1, 0x02, 0x2E, 0x8E,
|
||||
0x67, 0xEC, 0xE6, 0x67, 0x2B, 0x04, 0x3E, 0xE5
|
||||
)))
|
||||
signature = bytes(bytearray((
|
||||
0x41, 0xAA, 0x28, 0xD2, 0xF1, 0xAB, 0x14, 0x82,
|
||||
0x80, 0xCD, 0x9E, 0xD5, 0x6F, 0xED, 0xA4, 0x19,
|
||||
0x74, 0x05, 0x35, 0x54, 0xA4, 0x27, 0x67, 0xB8,
|
||||
0x3A, 0xD0, 0x43, 0xFD, 0x39, 0xDC, 0x04, 0x93,
|
||||
0x01, 0x45, 0x6C, 0x64, 0xBA, 0x46, 0x42, 0xA1,
|
||||
0x65, 0x3C, 0x23, 0x5A, 0x98, 0xA6, 0x02, 0x49,
|
||||
0xBC, 0xD6, 0xD3, 0xF7, 0x46, 0xB6, 0x31, 0xDF,
|
||||
0x92, 0x80, 0x14, 0xF6, 0xC5, 0xBF, 0x9C, 0x40
|
||||
)))
|
||||
prv = bytes2long(prv)
|
||||
signature = signature[32:] + signature[:32]
|
||||
|
||||
c = CURVES["id-GostR3410-2001-TestParamSet"]
|
||||
pubX, pubY = public_key(c, prv)
|
||||
self.assertSequenceEqual(long2bytes(pubX), pub_x)
|
||||
self.assertSequenceEqual(long2bytes(pubY), pub_y)
|
||||
s = sign(c, prv, digest)
|
||||
self.assertTrue(verify(c, (pubX, pubY), digest, s))
|
||||
self.assertTrue(verify(c, (pubX, pubY), digest, signature))
|
||||
|
||||
def test_sequence(self):
|
||||
c = CURVES["id-GostR3410-2001-TestParamSet"]
|
||||
prv = prv_unmarshal(urandom(32))
|
||||
pubX, pubY = public_key(c, prv_unmarshal(prv_marshal(c, prv)))
|
||||
for _ in range(20):
|
||||
digest = urandom(32)
|
||||
s = sign(c, prv, digest)
|
||||
self.assertTrue(verify(c, (pubX, pubY), digest, s))
|
||||
|
||||
|
||||
class Test34102012(TestCase):
|
||||
def test_1(self):
|
||||
"""Test vector from 34.10-2012 standard itself
|
||||
"""
|
||||
curve = CURVES["id-GostR3410-2001-TestParamSet"]
|
||||
prv = bytes2long(hexdec("7A929ADE789BB9BE10ED359DD39A72C11B60961F49397EEE1D19CE9891EC3B28"))
|
||||
digest = hexdec("2DFBC1B372D89A1188C09C52E0EEC61FCE52032AB1022E8E67ECE6672B043EE5")
|
||||
rand = hexdec("77105C9B20BCD3122823C8CF6FCC7B956DE33814E95B7FE64FED924594DCEAB3")
|
||||
signature = sign(curve, prv, digest, rand)
|
||||
r = "41aa28d2f1ab148280cd9ed56feda41974053554a42767b83ad043fd39dc0493"
|
||||
s = "01456c64ba4642a1653c235a98a60249bcd6d3f746b631df928014f6c5bf9c40"
|
||||
self.assertSequenceEqual(hexenc(signature), s + r)
|
||||
|
||||
def test_2(self):
|
||||
"""Test vector from 34.10-2012 standard itself
|
||||
"""
|
||||
curve = GOST3410Curve(
|
||||
p=3623986102229003635907788753683874306021320925534678605086546150450856166624002482588482022271496854025090823603058735163734263822371964987228582907372403,
|
||||
q=3623986102229003635907788753683874306021320925534678605086546150450856166623969164898305032863068499961404079437936585455865192212970734808812618120619743,
|
||||
a=7,
|
||||
b=1518655069210828534508950034714043154928747527740206436194018823352809982443793732829756914785974674866041605397883677596626326413990136959047435811826396,
|
||||
x=1928356944067022849399309401243137598997786635459507974357075491307766592685835441065557681003184874819658004903212332884252335830250729527632383493573274,
|
||||
y=2288728693371972859970012155529478416353562327329506180314497425931102860301572814141997072271708807066593850650334152381857347798885864807605098724013854,
|
||||
)
|
||||
prv = bytes2long(hexdec("0BA6048AADAE241BA40936D47756D7C93091A0E8514669700EE7508E508B102072E8123B2200A0563322DAD2827E2714A2636B7BFD18AADFC62967821FA18DD4"))
|
||||
digest = hexdec("3754F3CFACC9E0615C4F4A7C4D8DAB531B09B6F9C170C533A71D147035B0C5917184EE536593F4414339976C647C5D5A407ADEDB1D560C4FC6777D2972075B8C")
|
||||
rand = hexdec("0359E7F4B1410FEACC570456C6801496946312120B39D019D455986E364F365886748ED7A44B3E794434006011842286212273A6D14CF70EA3AF71BB1AE679F1")
|
||||
signature = sign(curve, prv, digest, rand)
|
||||
r = "2f86fa60a081091a23dd795e1e3c689ee512a3c82ee0dcc2643c78eea8fcacd35492558486b20f1c9ec197c90699850260c93bcbcd9c5c3317e19344e173ae36"
|
||||
s = "1081b394696ffe8e6585e7a9362d26b6325f56778aadbc081c0bfbe933d52ff5823ce288e8c4f362526080df7f70ce406a6eeb1f56919cb92a9853bde73e5b4a"
|
||||
self.assertSequenceEqual(hexenc(signature), s + r)
|
||||
|
||||
def test_gcl3(self):
|
||||
"""Test vector from libgcl3
|
||||
"""
|
||||
p = bytes2long(bytes(bytearray((
|
||||
0x45, 0x31, 0xAC, 0xD1, 0xFE, 0x00, 0x23, 0xC7,
|
||||
0x55, 0x0D, 0x26, 0x7B, 0x6B, 0x2F, 0xEE, 0x80,
|
||||
0x92, 0x2B, 0x14, 0xB2, 0xFF, 0xB9, 0x0F, 0x04,
|
||||
0xD4, 0xEB, 0x7C, 0x09, 0xB5, 0xD2, 0xD1, 0x5D,
|
||||
0xF1, 0xD8, 0x52, 0x74, 0x1A, 0xF4, 0x70, 0x4A,
|
||||
0x04, 0x58, 0x04, 0x7E, 0x80, 0xE4, 0x54, 0x6D,
|
||||
0x35, 0xB8, 0x33, 0x6F, 0xAC, 0x22, 0x4D, 0xD8,
|
||||
0x16, 0x64, 0xBB, 0xF5, 0x28, 0xBE, 0x63, 0x73,
|
||||
))))
|
||||
q = bytes2long(bytes(bytearray((
|
||||
0x45, 0x31, 0xAC, 0xD1, 0xFE, 0x00, 0x23, 0xC7,
|
||||
0x55, 0x0D, 0x26, 0x7B, 0x6B, 0x2F, 0xEE, 0x80,
|
||||
0x92, 0x2B, 0x14, 0xB2, 0xFF, 0xB9, 0x0F, 0x04,
|
||||
0xD4, 0xEB, 0x7C, 0x09, 0xB5, 0xD2, 0xD1, 0x5D,
|
||||
0xA8, 0x2F, 0x2D, 0x7E, 0xCB, 0x1D, 0xBA, 0xC7,
|
||||
0x19, 0x90, 0x5C, 0x5E, 0xEC, 0xC4, 0x23, 0xF1,
|
||||
0xD8, 0x6E, 0x25, 0xED, 0xBE, 0x23, 0xC5, 0x95,
|
||||
0xD6, 0x44, 0xAA, 0xF1, 0x87, 0xE6, 0xE6, 0xDF,
|
||||
))))
|
||||
a = bytes2long(bytes(bytearray((
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07,
|
||||
))))
|
||||
b = bytes2long(bytes(bytearray((
|
||||
0x1C, 0xFF, 0x08, 0x06, 0xA3, 0x11, 0x16, 0xDA,
|
||||
0x29, 0xD8, 0xCF, 0xA5, 0x4E, 0x57, 0xEB, 0x74,
|
||||
0x8B, 0xC5, 0xF3, 0x77, 0xE4, 0x94, 0x00, 0xFD,
|
||||
0xD7, 0x88, 0xB6, 0x49, 0xEC, 0xA1, 0xAC, 0x43,
|
||||
0x61, 0x83, 0x40, 0x13, 0xB2, 0xAD, 0x73, 0x22,
|
||||
0x48, 0x0A, 0x89, 0xCA, 0x58, 0xE0, 0xCF, 0x74,
|
||||
0xBC, 0x9E, 0x54, 0x0C, 0x2A, 0xDD, 0x68, 0x97,
|
||||
0xFA, 0xD0, 0xA3, 0x08, 0x4F, 0x30, 0x2A, 0xDC,
|
||||
))))
|
||||
x = bytes2long(bytes(bytearray((
|
||||
0x24, 0xD1, 0x9C, 0xC6, 0x45, 0x72, 0xEE, 0x30,
|
||||
0xF3, 0x96, 0xBF, 0x6E, 0xBB, 0xFD, 0x7A, 0x6C,
|
||||
0x52, 0x13, 0xB3, 0xB3, 0xD7, 0x05, 0x7C, 0xC8,
|
||||
0x25, 0xF9, 0x10, 0x93, 0xA6, 0x8C, 0xD7, 0x62,
|
||||
0xFD, 0x60, 0x61, 0x12, 0x62, 0xCD, 0x83, 0x8D,
|
||||
0xC6, 0xB6, 0x0A, 0xA7, 0xEE, 0xE8, 0x04, 0xE2,
|
||||
0x8B, 0xC8, 0x49, 0x97, 0x7F, 0xAC, 0x33, 0xB4,
|
||||
0xB5, 0x30, 0xF1, 0xB1, 0x20, 0x24, 0x8A, 0x9A,
|
||||
))))
|
||||
y = bytes2long(bytes(bytearray((
|
||||
0x2B, 0xB3, 0x12, 0xA4, 0x3B, 0xD2, 0xCE, 0x6E,
|
||||
0x0D, 0x02, 0x06, 0x13, 0xC8, 0x57, 0xAC, 0xDD,
|
||||
0xCF, 0xBF, 0x06, 0x1E, 0x91, 0xE5, 0xF2, 0xC3,
|
||||
0xF3, 0x24, 0x47, 0xC2, 0x59, 0xF3, 0x9B, 0x2C,
|
||||
0x83, 0xAB, 0x15, 0x6D, 0x77, 0xF1, 0x49, 0x6B,
|
||||
0xF7, 0xEB, 0x33, 0x51, 0xE1, 0xEE, 0x4E, 0x43,
|
||||
0xDC, 0x1A, 0x18, 0xB9, 0x1B, 0x24, 0x64, 0x0B,
|
||||
0x6D, 0xBB, 0x92, 0xCB, 0x1A, 0xDD, 0x37, 0x1E,
|
||||
))))
|
||||
prv = bytes(bytearray((
|
||||
0x0B, 0xA6, 0x04, 0x8A, 0xAD, 0xAE, 0x24, 0x1B,
|
||||
0xA4, 0x09, 0x36, 0xD4, 0x77, 0x56, 0xD7, 0xC9,
|
||||
0x30, 0x91, 0xA0, 0xE8, 0x51, 0x46, 0x69, 0x70,
|
||||
0x0E, 0xE7, 0x50, 0x8E, 0x50, 0x8B, 0x10, 0x20,
|
||||
0x72, 0xE8, 0x12, 0x3B, 0x22, 0x00, 0xA0, 0x56,
|
||||
0x33, 0x22, 0xDA, 0xD2, 0x82, 0x7E, 0x27, 0x14,
|
||||
0xA2, 0x63, 0x6B, 0x7B, 0xFD, 0x18, 0xAA, 0xDF,
|
||||
0xC6, 0x29, 0x67, 0x82, 0x1F, 0xA1, 0x8D, 0xD4,
|
||||
)))
|
||||
pub_x = bytes(bytearray((
|
||||
0x11, 0x5D, 0xC5, 0xBC, 0x96, 0x76, 0x0C, 0x7B,
|
||||
0x48, 0x59, 0x8D, 0x8A, 0xB9, 0xE7, 0x40, 0xD4,
|
||||
0xC4, 0xA8, 0x5A, 0x65, 0xBE, 0x33, 0xC1, 0x81,
|
||||
0x5B, 0x5C, 0x32, 0x0C, 0x85, 0x46, 0x21, 0xDD,
|
||||
0x5A, 0x51, 0x58, 0x56, 0xD1, 0x33, 0x14, 0xAF,
|
||||
0x69, 0xBC, 0x5B, 0x92, 0x4C, 0x8B, 0x4D, 0xDF,
|
||||
0xF7, 0x5C, 0x45, 0x41, 0x5C, 0x1D, 0x9D, 0xD9,
|
||||
0xDD, 0x33, 0x61, 0x2C, 0xD5, 0x30, 0xEF, 0xE1,
|
||||
)))
|
||||
pub_y = bytes(bytearray((
|
||||
0x37, 0xC7, 0xC9, 0x0C, 0xD4, 0x0B, 0x0F, 0x56,
|
||||
0x21, 0xDC, 0x3A, 0xC1, 0xB7, 0x51, 0xCF, 0xA0,
|
||||
0xE2, 0x63, 0x4F, 0xA0, 0x50, 0x3B, 0x3D, 0x52,
|
||||
0x63, 0x9F, 0x5D, 0x7F, 0xB7, 0x2A, 0xFD, 0x61,
|
||||
0xEA, 0x19, 0x94, 0x41, 0xD9, 0x43, 0xFF, 0xE7,
|
||||
0xF0, 0xC7, 0x0A, 0x27, 0x59, 0xA3, 0xCD, 0xB8,
|
||||
0x4C, 0x11, 0x4E, 0x1F, 0x93, 0x39, 0xFD, 0xF2,
|
||||
0x7F, 0x35, 0xEC, 0xA9, 0x36, 0x77, 0xBE, 0xEC,
|
||||
)))
|
||||
digest = bytes(bytearray((
|
||||
0x37, 0x54, 0xF3, 0xCF, 0xAC, 0xC9, 0xE0, 0x61,
|
||||
0x5C, 0x4F, 0x4A, 0x7C, 0x4D, 0x8D, 0xAB, 0x53,
|
||||
0x1B, 0x09, 0xB6, 0xF9, 0xC1, 0x70, 0xC5, 0x33,
|
||||
0xA7, 0x1D, 0x14, 0x70, 0x35, 0xB0, 0xC5, 0x91,
|
||||
0x71, 0x84, 0xEE, 0x53, 0x65, 0x93, 0xF4, 0x41,
|
||||
0x43, 0x39, 0x97, 0x6C, 0x64, 0x7C, 0x5D, 0x5A,
|
||||
0x40, 0x7A, 0xDE, 0xDB, 0x1D, 0x56, 0x0C, 0x4F,
|
||||
0xC6, 0x77, 0x7D, 0x29, 0x72, 0x07, 0x5B, 0x8C,
|
||||
)))
|
||||
signature = bytes(bytearray((
|
||||
0x2F, 0x86, 0xFA, 0x60, 0xA0, 0x81, 0x09, 0x1A,
|
||||
0x23, 0xDD, 0x79, 0x5E, 0x1E, 0x3C, 0x68, 0x9E,
|
||||
0xE5, 0x12, 0xA3, 0xC8, 0x2E, 0xE0, 0xDC, 0xC2,
|
||||
0x64, 0x3C, 0x78, 0xEE, 0xA8, 0xFC, 0xAC, 0xD3,
|
||||
0x54, 0x92, 0x55, 0x84, 0x86, 0xB2, 0x0F, 0x1C,
|
||||
0x9E, 0xC1, 0x97, 0xC9, 0x06, 0x99, 0x85, 0x02,
|
||||
0x60, 0xC9, 0x3B, 0xCB, 0xCD, 0x9C, 0x5C, 0x33,
|
||||
0x17, 0xE1, 0x93, 0x44, 0xE1, 0x73, 0xAE, 0x36,
|
||||
0x10, 0x81, 0xB3, 0x94, 0x69, 0x6F, 0xFE, 0x8E,
|
||||
0x65, 0x85, 0xE7, 0xA9, 0x36, 0x2D, 0x26, 0xB6,
|
||||
0x32, 0x5F, 0x56, 0x77, 0x8A, 0xAD, 0xBC, 0x08,
|
||||
0x1C, 0x0B, 0xFB, 0xE9, 0x33, 0xD5, 0x2F, 0xF5,
|
||||
0x82, 0x3C, 0xE2, 0x88, 0xE8, 0xC4, 0xF3, 0x62,
|
||||
0x52, 0x60, 0x80, 0xDF, 0x7F, 0x70, 0xCE, 0x40,
|
||||
0x6A, 0x6E, 0xEB, 0x1F, 0x56, 0x91, 0x9C, 0xB9,
|
||||
0x2A, 0x98, 0x53, 0xBD, 0xE7, 0x3E, 0x5B, 0x4A,
|
||||
)))
|
||||
prv = bytes2long(prv)
|
||||
signature = signature[64:] + signature[:64]
|
||||
c = GOST3410Curve(p, q, a, b, x, y)
|
||||
pubX, pubY = public_key(c, prv)
|
||||
self.assertSequenceEqual(long2bytes(pubX), pub_x)
|
||||
self.assertSequenceEqual(long2bytes(pubY), pub_y)
|
||||
s = sign(c, prv, digest)
|
||||
self.assertTrue(verify(c, (pubX, pubY), digest, s))
|
||||
self.assertTrue(verify(c, (pubX, pubY), digest, signature))
|
||||
|
||||
def test_sequence(self):
|
||||
c = CURVES["id-tc26-gost-3410-12-512-paramSetA"]
|
||||
prv = bytes2long(urandom(64))
|
||||
pubX, pubY = public_key(c, prv_unmarshal(prv_marshal(c, prv)))
|
||||
for _ in range(20):
|
||||
digest = urandom(64)
|
||||
s = sign(c, prv, digest)
|
||||
self.assertTrue(verify(c, (pubX, pubY), digest, s))
|
||||
self.assertNotIn(b"\x00" * 8, s)
|
||||
|
||||
|
||||
class TestUVXYConversion(TestCase):
|
||||
"""Twisted Edwards to Weierstrass coordinates conversion and vice versa
|
||||
"""
|
||||
def test_curve1(self):
|
||||
c = CURVES["id-tc26-gost-3410-2012-256-paramSetA"]
|
||||
u, v = (0x0D, bytes2long(hexdec("60CA1E32AA475B348488C38FAB07649CE7EF8DBE87F22E81F92B2592DBA300E7")))
|
||||
self.assertEqual(uv2xy(c, u, v), (c.x, c.y))
|
||||
self.assertEqual(xy2uv(c, c.x, c.y), (u, v))
|
||||
|
||||
def test_curve2(self):
|
||||
c = CURVES["id-tc26-gost-3410-2012-512-paramSetC"]
|
||||
u, v = (0x12, bytes2long(hexdec("469AF79D1FB1F5E16B99592B77A01E2A0FDFB0D01794368D9A56117F7B38669522DD4B650CF789EEBF068C5D139732F0905622C04B2BAAE7600303EE73001A3D")))
|
||||
self.assertEqual(uv2xy(c, u, v), (c.x, c.y))
|
||||
self.assertEqual(xy2uv(c, c.x, c.y), (u, v))
|
||||
|
||||
|
||||
class Test34102012SESPAKE(TestCase):
|
||||
"""Test vectors for multiplication from :rfc:`8133`
|
||||
"""
|
||||
def test_curve1(self):
|
||||
c = CURVES["id-GostR3410-2001-CryptoPro-A-ParamSet"]
|
||||
q_ind = (
|
||||
0xA69D51CAF1A309FA9E9B66187759B0174C274E080356F23CFCBFE84D396AD7BB,
|
||||
0x5D26F29ECC2E9AC0404DCF7986FA55FE94986362170F54B9616426A659786DAC,
|
||||
)
|
||||
self.assertEqual(
|
||||
c.exp(bytes2long(hexdec(
|
||||
"BD04673F7149B18E98155BD1E2724E71D0099AA25174F792D3326C6F18127067"
|
||||
)[::-1]), x=q_ind[0], y=q_ind[1]),
|
||||
(
|
||||
0x59495655D1E7C7424C622485F575CCF121F3122D274101E8AB734CC9C9A9B45E,
|
||||
0x48D1C311D33C9B701F3B03618562A4A07A044E3AF31E3999E67B487778B53C62,
|
||||
)
|
||||
)
|
||||
self.assertEqual(
|
||||
c.exp(0x1F2538097D5A031FA68BBB43C84D12B3DE47B7061C0D5E24993E0C873CDBA6B3),
|
||||
(
|
||||
0xBBC77CF42DC1E62D06227935379B4AA4D14FEA4F565DDF4CB4FA4D31579F9676,
|
||||
0x8E16604A4AFDF28246684D4996274781F6CB80ABBBA1414C1513EC988509DABF,
|
||||
)
|
||||
)
|
||||
self.assertEqual(
|
||||
c.exp(0xDC497D9EF6324912FD367840EE509A2032AEDB1C0A890D133B45F596FCCBD45D),
|
||||
(
|
||||
0x6097341C1BE388E83E7CA2DF47FAB86E2271FD942E5B7B2EB2409E49F742BC29,
|
||||
0xC81AA48BDB4CA6FA0EF18B9788AE25FE30857AA681B3942217F9FED151BAB7D0,
|
||||
),
|
||||
)
|
||||
|
||||
def test_curve2(self):
|
||||
c = CURVES["id-GostR3410-2001-CryptoPro-B-ParamSet"]
|
||||
q_ind = (
|
||||
0x3D715A874A4B17CB3B517893A9794A2B36C89D2FFC693F01EE4CC27E7F49E399,
|
||||
0x1C5A641FCF7CE7E87CDF8CEA38F3DB3096EACE2FAD158384B53953365F4FE7FE,
|
||||
)
|
||||
self.assertEqual(
|
||||
c.exp(bytes2long(hexdec(
|
||||
"BD04673F7149B18E98155BD1E2724E71D0099AA25174F792D3326C6F18127067"
|
||||
)[::-1]), x=q_ind[0], y=q_ind[1]),
|
||||
(
|
||||
0x6DC2AE26BC691FCA5A73D9C452790D15E34BA5404D92955B914C8D2662ABB985,
|
||||
0x3B02AAA9DD65AE30C335CED12F3154BBAC059F66B088306747453EDF6E5DB077,
|
||||
)
|
||||
)
|
||||
self.assertEqual(
|
||||
c.exp(0x499D72B90299CAB0DA1F8BE19D9122F622A13B32B730C46BD0664044F2144FAD),
|
||||
(
|
||||
0x61D6F916DB717222D74877F179F7EBEF7CD4D24D8C1F523C048E34A1DF30F8DD,
|
||||
0x3EC48863049CFCFE662904082E78503F4973A4E105E2F1B18C69A5E7FB209000,
|
||||
)
|
||||
)
|
||||
self.assertEqual(
|
||||
c.exp(0x0F69FF614957EF83668EDC2D7ED614BE76F7B253DB23C5CC9C52BF7DF8F4669D),
|
||||
(
|
||||
0x33BC6F7E9C0BA10CFB2B72546C327171295508EA97F8C8BA9F890F2478AB4D6C,
|
||||
0x75D57B396C396F492F057E9222CCC686437A2AAD464E452EF426FC8EEED1A4A6,
|
||||
),
|
||||
)
|
||||
|
||||
def test_curve3(self):
|
||||
c = CURVES["id-GostR3410-2001-CryptoPro-C-ParamSet"]
|
||||
q_ind = (
|
||||
0x1E36383E43BB6CFA2917167D71B7B5DD3D6D462B43D7C64282AE67DFBEC2559D,
|
||||
0x137478A9F721C73932EA06B45CF72E37EB78A63F29A542E563C614650C8B6399,
|
||||
)
|
||||
self.assertEqual(
|
||||
c.exp(bytes2long(hexdec(
|
||||
"BD04673F7149B18E98155BD1E2724E71D0099AA25174F792D3326C6F18127067"
|
||||
)[::-1]), x=q_ind[0], y=q_ind[1]),
|
||||
(
|
||||
0x945821DAF91E158B839939630655A3B21FF3E146D27041E86C05650EB3B46B59,
|
||||
0x3A0C2816AC97421FA0E879605F17F0C9C3EB734CFF196937F6284438D70BDC48,
|
||||
)
|
||||
)
|
||||
self.assertEqual(
|
||||
c.exp(0x3A54AC3F19AD9D0B1EAC8ACDCEA70E581F1DAC33D13FEAFD81E762378639C1A8),
|
||||
(
|
||||
0x96B7F09C94D297C257A7DA48364C0076E59E48D221CBA604AE111CA3933B446A,
|
||||
0x54E4953D86B77ECCEB578500931E822300F7E091F79592CA202A020D762C34A6,
|
||||
)
|
||||
)
|
||||
self.assertEqual(
|
||||
c.exp(0x448781782BF7C0E52A1DD9E6758FD3482D90D3CFCCF42232CF357E59A4D49FD4),
|
||||
(
|
||||
0x4B9C0AB55A938121F282F48A2CC4396EB16E7E0068B495B0C1DD4667786A3EB7,
|
||||
0x223460AA8E09383E9DF9844C5A0F2766484738E5B30128A171B69A77D9509B96,
|
||||
),
|
||||
)
|
||||
|
||||
def test_curve4(self):
|
||||
c = CURVES["id-tc26-gost-3410-12-512-paramSetA"]
|
||||
q_ind = (
|
||||
0x2A17F8833A32795327478871B5C5E88AEFB91126C64B4B8327289BEA62559425D18198F133F400874328B220C74497CD240586CB249E158532CB8090776CD61C,
|
||||
0x728F0C4A73B48DA41CE928358FAD26B47A6E094E9362BAE82559F83CDDC4EC3A4676BD3707EDEAF4CD85E99695C64C241EDC622BE87DC0CF87F51F4367F723C5,
|
||||
)
|
||||
self.assertEqual(
|
||||
c.exp(bytes2long(hexdec(
|
||||
"BD04673F7149B18E98155BD1E2724E71D0099AA25174F792D3326C6F181270671C6213E3930EFDDA26451792C6208122EE60D200520D695DFD9F5F0FD5ABA702"
|
||||
)[::-1]), x=q_ind[0], y=q_ind[1]),
|
||||
(
|
||||
0x0C0AB53D0E0A9C607CAD758F558915A0A7DC5DC87B45E9A58FDDF30EC3385960283E030CD322D9E46B070637785FD49D2CD711F46807A24C40AF9A42C8E2D740,
|
||||
0xDF93A8012B86D3A3D4F8A4D487DA15FC739EB31B20B3B0E8C8C032AAF8072C6337CF7D5B404719E5B4407C41D9A3216A08CA69C271484E9ED72B8AAA52E28B8B,
|
||||
)
|
||||
)
|
||||
self.assertEqual(
|
||||
c.exp(0x3CE54325DB52FE798824AEAD11BB16FA766857D04A4AF7D468672F16D90E7396046A46F815693E85B1CE5464DA9270181F82333B0715057BBE8D61D400505F0E),
|
||||
(
|
||||
0xB93093EB0FCC463239B7DF276E09E592FCFC9B635504EA4531655D76A0A3078E2B4E51CFE2FA400CC5DE9FBE369DB204B3E8ED7EDD85EE5CCA654C1AED70E396,
|
||||
0x809770B8D910EA30BD2FA89736E91DC31815D2D9B31128077EEDC371E9F69466F497DC64DD5B1FADC587F860EE256109138C4A9CD96B628E65A8F590520FC882,
|
||||
)
|
||||
)
|
||||
self.assertEqual(
|
||||
c.exp(0xB5C286A79AA8E97EC0E19BC1959A1D15F12F8C97870BA9D68CC12811A56A3BB11440610825796A49D468CDC9C2D02D76598A27973D5960C5F50BCE28D8D345F4),
|
||||
(
|
||||
0x238B38644E440452A99FA6B93D9FD7DA0CB83C32D3C1E3CFE5DF5C3EB0F9DB91E588DAEDC849EA2FB867AE855A21B4077353C0794716A6480995113D8C20C7AF,
|
||||
0xB2273D5734C1897F8D15A7008B862938C8C74CA7E877423D95243EB7EBD02FD2C456CF9FC956F078A59AA86F19DD1075E5167E4ED35208718EA93161C530ED14,
|
||||
),
|
||||
)
|
||||
|
||||
def test_curve5(self):
|
||||
c = CURVES["id-tc26-gost-3410-12-512-paramSetB"]
|
||||
q_ind = (
|
||||
0x7E1FAE8285E035BEC244BEF2D0E5EBF436633CF50E55231DEA9C9CF21D4C8C33DF85D4305DE92971F0A4B4C07E00D87BDBC720EB66E49079285AAF12E0171149,
|
||||
0x2CC89998B875D4463805BA0D858A196592DB20AB161558FF2F4EF7A85725D20953967AE621AFDEAE89BB77C83A2528EF6FCE02F68BDA4679D7F2704947DBC408,
|
||||
)
|
||||
self.assertEqual(
|
||||
c.exp(bytes2long(hexdec(
|
||||
"BD04673F7149B18E98155BD1E2724E71D0099AA25174F792D3326C6F181270671C6213E3930EFDDA26451792C6208122EE60D200520D695DFD9F5F0FD5ABA702"
|
||||
)[::-1]), x=q_ind[0], y=q_ind[1]),
|
||||
(
|
||||
0x7D03E65B8050D1E12CBB601A17B9273B0E728F5021CD47C8A4DD822E4627BA5F9C696286A2CDDA9A065509866B4DEDEDC4A118409604AD549F87A60AFA621161,
|
||||
0x16037DAD45421EC50B00D50BDC6AC3B85348BC1D3A2F85DB27C3373580FEF87C2C743B7ED30F22BE22958044E716F93A61CA3213A361A2797A16A3AE62957377,
|
||||
)
|
||||
)
|
||||
self.assertEqual(
|
||||
c.exp(0x715E893FA639BF341296E0623E6D29DADF26B163C278767A7982A989462A3863FE12AEF8BD403D59C4DC4720570D4163DB0805C7C10C4E818F9CB785B04B9997),
|
||||
(
|
||||
0x10C479EA1C04D3C2C02B0576A9C42D96226FF033C1191436777F66916030D87D02FB93738ED7669D07619FFCE7C1F3C4DB5E5DF49E2186D6FA1E2EB5767602B9,
|
||||
0x039F6044191404E707F26D59D979136A831CCE43E1C5F0600D1DDF8F39D0CA3D52FBD943BF04DDCED1AA2CE8F5EBD7487ACDEF239C07D015084D796784F35436,
|
||||
)
|
||||
)
|
||||
self.assertEqual(
|
||||
c.exp(0x30FA8C2B4146C2DBBE82BED04D7378877E8C06753BD0A0FF71EBF2BEFE8DA8F3DC0836468E2CE7C5C961281B6505140F8407413F03C2CB1D201EA1286CE30E6D),
|
||||
(
|
||||
0x34C0149E7BB91AE377B02573FCC48AF7BFB7B16DEB8F9CE870F384688E3241A3A868588CC0EF4364CCA67D17E3260CD82485C202ADC76F895D5DF673B1788E67,
|
||||
0x608E944929BD643569ED5189DB871453F13333A1EAF82B2FE1BE8100E775F13DD9925BD317B63BFAF05024D4A738852332B64501195C1B2EF789E34F23DDAFC5,
|
||||
),
|
||||
)
|
||||
|
||||
def test_curve6(self):
|
||||
c = CURVES["id-tc26-gost-3410-2012-256-paramSetA"]
|
||||
q_ind = (
|
||||
0xB51ADF93A40AB15792164FAD3352F95B66369EB2A4EF5EFAE32829320363350E,
|
||||
0x74A358CC08593612F5955D249C96AFB7E8B0BB6D8BD2BBE491046650D822BE18,
|
||||
)
|
||||
self.assertEqual(
|
||||
c.exp(bytes2long(hexdec(
|
||||
"BD04673F7149B18E98155BD1E2724E71D0099AA25174F792D3326C6F18127067"
|
||||
)[::-1]), x=q_ind[0], y=q_ind[1]),
|
||||
(
|
||||
0xDBF99827078956812FA48C6E695DF589DEF1D18A2D4D35A96D75BF6854237629,
|
||||
0x9FDDD48BFBC57BEE1DA0CFF282884F284D471B388893C48F5ECB02FC18D67589,
|
||||
)
|
||||
)
|
||||
self.assertEqual(
|
||||
c.exp(0x147B72F6684FB8FD1B418A899F7DBECAF5FCE60B13685BAA95328654A7F0707F),
|
||||
(
|
||||
0x33FBAC14EAE538275A769417829C431BD9FA622B6F02427EF55BD60EE6BC2888,
|
||||
0x22F2EBCF960A82E6CDB4042D3DDDA511B2FBA925383C2273D952EA2D406EAE46,
|
||||
)
|
||||
)
|
||||
self.assertEqual(
|
||||
c.exp(0x30D5CFADAA0E31B405E6734C03EC4C5DF0F02F4BA25C9A3B320EE6453567B4CB),
|
||||
(
|
||||
0x2B2D89FAB735433970564F2F28CFA1B57D640CB902BC6334A538F44155022CB2,
|
||||
0x10EF6A82EEF1E70F942AA81D6B4CE5DEC0DDB9447512962874870E6F2849A96F,
|
||||
),
|
||||
)
|
||||
|
||||
def test_curve7(self):
|
||||
c = CURVES["id-tc26-gost-3410-2012-512-paramSetC"]
|
||||
q_ind = (
|
||||
0x489C91784E02E98F19A803ABCA319917F37689E5A18965251CE2FF4E8D8B298F5BA7470F9E0E713487F96F4A8397B3D09A270C9D367EB5E0E6561ADEEB51581D,
|
||||
0x684EA885ACA64EAF1B3FEE36C0852A3BE3BD8011B0EF18E203FF87028D6EB5DB2C144A0DCC71276542BFD72CA2A43FA4F4939DA66D9A60793C704A8C94E16F18,
|
||||
)
|
||||
self.assertEqual(
|
||||
c.exp(bytes2long(hexdec(
|
||||
"BD04673F7149B18E98155BD1E2724E71D0099AA25174F792D3326C6F181270671C6213E3930EFDDA26451792C6208122EE60D200520D695DFD9F5F0FD5ABA702"
|
||||
)[::-1]), x=q_ind[0], y=q_ind[1]),
|
||||
(
|
||||
0x0185AE6271A81BB7F236A955F7CAA26FB63849813C0287D96C83A15AE6B6A86467AB13B6D88CE8CD7DC2E5B97FF5F28FAC2C108F2A3CF3DB5515C9E6D7D210E8,
|
||||
0xED0220F92EF771A71C64ECC77986DB7C03D37B3E2AB3E83F32CE5E074A762EC08253C9E2102B87532661275C4B1D16D2789CDABC58ACFDF7318DE70AB64F09B8,
|
||||
)
|
||||
)
|
||||
self.assertEqual(
|
||||
c.exp(0x332F930421D14CFE260042159F18E49FD5A54167E94108AD80B1DE60B13DE7999A34D611E63F3F870E5110247DF8EC7466E648ACF385E52CCB889ABF491EDFF0),
|
||||
(
|
||||
0x561655966D52952E805574F4281F1ED3A2D498932B00CBA9DECB42837F09835BFFBFE2D84D6B6B242FE7B57F92E1A6F2413E12DDD6383E4437E13D72693469AD,
|
||||
0xF6B18328B2715BD7F4178615273A36135BC0BF62F7D8BB9F080164AD36470AD03660F51806C64C6691BADEF30F793720F8E3FEAED631D6A54A4C372DCBF80E82,
|
||||
)
|
||||
)
|
||||
self.assertEqual(
|
||||
c.exp(0x38481771E7D054F96212686B613881880BD8A6C89DDBC656178F014D2C093432A033EE10415F13A160D44C2AD61E6E2E05A7F7EC286BCEA3EA4D4D53F8634FA2),
|
||||
(
|
||||
0xB7C5818687083433BC1AFF61CB5CA79E38232025E0C1F123B8651E62173CE6873F3E6FFE7281C2E45F4F524F66B0C263616ED08FD210AC4355CA3292B51D71C3,
|
||||
0x497F14205DBDC89BDDAF50520ED3B1429AD30777310186BE5E68070F016A44E0C766DB08E8AC23FBDFDE6D675AA4DF591EB18BA0D348DF7AA40973A2F1DCFA55,
|
||||
),
|
||||
)
|
||||
@ -1,125 +0,0 @@
|
||||
# coding: utf-8
|
||||
# PyGOST -- Pure Python GOST cryptographic functions library
|
||||
# Copyright (C) 2015-2023 Sergey Matveev <stargrave@stargrave.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, version 3 of the License.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from os import urandom
|
||||
from unittest import TestCase
|
||||
|
||||
from pygost.gost3410 import CURVES
|
||||
from pygost.gost3410 import prv_unmarshal
|
||||
from pygost.gost3410 import pub_unmarshal
|
||||
from pygost.gost3410 import public_key
|
||||
from pygost.gost3410_vko import kek_34102001
|
||||
from pygost.gost3410_vko import kek_34102012256
|
||||
from pygost.gost3410_vko import kek_34102012512
|
||||
from pygost.gost3410_vko import ukm_unmarshal
|
||||
from pygost.utils import bytes2long
|
||||
from pygost.utils import hexdec
|
||||
|
||||
|
||||
class TestVKO34102001(TestCase):
|
||||
def test_vector(self):
|
||||
curve = CURVES["id-GostR3410-2001-TestParamSet"]
|
||||
ukm = ukm_unmarshal(hexdec("5172be25f852a233"))
|
||||
prv1 = prv_unmarshal(hexdec("1df129e43dab345b68f6a852f4162dc69f36b2f84717d08755cc5c44150bf928"))
|
||||
prv2 = prv_unmarshal(hexdec("5b9356c6474f913f1e83885ea0edd5df1a43fd9d799d219093241157ac9ed473"))
|
||||
kek = hexdec("ee4618a0dbb10cb31777b4b86a53d9e7ef6cb3e400101410f0c0f2af46c494a6")
|
||||
pub1 = public_key(curve, prv1)
|
||||
pub2 = public_key(curve, prv2)
|
||||
self.assertSequenceEqual(kek_34102001(curve, prv1, pub2, ukm), kek)
|
||||
self.assertSequenceEqual(kek_34102001(curve, prv2, pub1, ukm), kek)
|
||||
|
||||
def test_sequence(self):
|
||||
curve = CURVES["id-GostR3410-2001-TestParamSet"]
|
||||
for _ in range(10):
|
||||
ukm = ukm_unmarshal(urandom(8))
|
||||
prv1 = bytes2long(urandom(32))
|
||||
prv2 = bytes2long(urandom(32))
|
||||
pub1 = public_key(curve, prv1)
|
||||
pub2 = public_key(curve, prv2)
|
||||
kek1 = kek_34102001(curve, prv1, pub2, ukm)
|
||||
kek2 = kek_34102001(curve, prv2, pub1, ukm)
|
||||
self.assertSequenceEqual(kek1, kek2)
|
||||
kek1 = kek_34102001(curve, prv1, pub1, ukm)
|
||||
kek2 = kek_34102001(curve, prv2, pub2, ukm)
|
||||
self.assertNotEqual(kek1, kek2)
|
||||
|
||||
|
||||
class TestVKO34102012256(TestCase):
|
||||
"""RFC 7836
|
||||
"""
|
||||
def test_vector(self):
|
||||
curve = CURVES["id-tc26-gost-3410-12-512-paramSetA"]
|
||||
ukm = ukm_unmarshal(hexdec("1d80603c8544c727"))
|
||||
prvA = prv_unmarshal(hexdec("c990ecd972fce84ec4db022778f50fcac726f46708384b8d458304962d7147f8c2db41cef22c90b102f2968404f9b9be6d47c79692d81826b32b8daca43cb667"))
|
||||
pubA = pub_unmarshal(hexdec("aab0eda4abff21208d18799fb9a8556654ba783070eba10cb9abb253ec56dcf5d3ccba6192e464e6e5bcb6dea137792f2431f6c897eb1b3c0cc14327b1adc0a7914613a3074e363aedb204d38d3563971bd8758e878c9db11403721b48002d38461f92472d40ea92f9958c0ffa4c93756401b97f89fdbe0b5e46e4a4631cdb5a"))
|
||||
prvB = prv_unmarshal(hexdec("48c859f7b6f11585887cc05ec6ef1390cfea739b1a18c0d4662293ef63b79e3b8014070b44918590b4b996acfea4edfbbbcccc8c06edd8bf5bda92a51392d0db"))
|
||||
pubB = pub_unmarshal(hexdec("192fe183b9713a077253c72c8735de2ea42a3dbc66ea317838b65fa32523cd5efca974eda7c863f4954d1147f1f2b25c395fce1c129175e876d132e94ed5a65104883b414c9b592ec4dc84826f07d0b6d9006dda176ce48c391e3f97d102e03bb598bf132a228a45f7201aba08fc524a2d77e43a362ab022ad4028f75bde3b79"))
|
||||
vko = hexdec("c9a9a77320e2cc559ed72dce6f47e2192ccea95fa648670582c054c0ef36c221")
|
||||
self.assertSequenceEqual(kek_34102012256(curve, prvA, pubB, ukm), vko)
|
||||
self.assertSequenceEqual(kek_34102012256(curve, prvB, pubA, ukm), vko)
|
||||
|
||||
def test_sequence(self):
|
||||
curve = CURVES["id-tc26-gost-3410-2012-256-paramSetA"]
|
||||
for _ in range(10):
|
||||
ukm = ukm_unmarshal(urandom(8))
|
||||
prv1 = bytes2long(urandom(32))
|
||||
prv2 = bytes2long(urandom(32))
|
||||
pub1 = public_key(curve, prv1)
|
||||
pub2 = public_key(curve, prv2)
|
||||
kek1 = kek_34102012256(curve, prv1, pub2, ukm)
|
||||
kek2 = kek_34102012256(curve, prv2, pub1, ukm)
|
||||
self.assertSequenceEqual(kek1, kek2)
|
||||
kek1 = kek_34102012256(curve, prv1, pub1, ukm)
|
||||
kek2 = kek_34102012256(curve, prv2, pub2, ukm)
|
||||
self.assertNotEqual(kek1, kek2)
|
||||
|
||||
def test_pub_is_not_on_curve(self):
|
||||
with self.assertRaises(ValueError):
|
||||
kek_34102012256(
|
||||
CURVES["id-tc26-gost-3410-2012-256-paramSetA"],
|
||||
bytes2long(urandom(32)),
|
||||
pub_unmarshal(urandom(64)),
|
||||
)
|
||||
|
||||
|
||||
class TestVKO34102012512(TestCase):
|
||||
"""RFC 7836
|
||||
"""
|
||||
def test_vector(self):
|
||||
curve = CURVES["id-tc26-gost-3410-12-512-paramSetA"]
|
||||
ukm = ukm_unmarshal(hexdec("1d80603c8544c727"))
|
||||
prvA = prv_unmarshal(hexdec("c990ecd972fce84ec4db022778f50fcac726f46708384b8d458304962d7147f8c2db41cef22c90b102f2968404f9b9be6d47c79692d81826b32b8daca43cb667"))
|
||||
pubA = pub_unmarshal(hexdec("aab0eda4abff21208d18799fb9a8556654ba783070eba10cb9abb253ec56dcf5d3ccba6192e464e6e5bcb6dea137792f2431f6c897eb1b3c0cc14327b1adc0a7914613a3074e363aedb204d38d3563971bd8758e878c9db11403721b48002d38461f92472d40ea92f9958c0ffa4c93756401b97f89fdbe0b5e46e4a4631cdb5a"))
|
||||
prvB = prv_unmarshal(hexdec("48c859f7b6f11585887cc05ec6ef1390cfea739b1a18c0d4662293ef63b79e3b8014070b44918590b4b996acfea4edfbbbcccc8c06edd8bf5bda92a51392d0db"))
|
||||
pubB = pub_unmarshal(hexdec("192fe183b9713a077253c72c8735de2ea42a3dbc66ea317838b65fa32523cd5efca974eda7c863f4954d1147f1f2b25c395fce1c129175e876d132e94ed5a65104883b414c9b592ec4dc84826f07d0b6d9006dda176ce48c391e3f97d102e03bb598bf132a228a45f7201aba08fc524a2d77e43a362ab022ad4028f75bde3b79"))
|
||||
vko = hexdec("79f002a96940ce7bde3259a52e015297adaad84597a0d205b50e3e1719f97bfa7ee1d2661fa9979a5aa235b558a7e6d9f88f982dd63fc35a8ec0dd5e242d3bdf")
|
||||
self.assertSequenceEqual(kek_34102012512(curve, prvA, pubB, ukm), vko)
|
||||
self.assertSequenceEqual(kek_34102012512(curve, prvB, pubA, ukm), vko)
|
||||
|
||||
def test_sequence(self):
|
||||
curve = CURVES["id-tc26-gost-3410-12-512-paramSetA"]
|
||||
for _ in range(10):
|
||||
ukm = ukm_unmarshal(urandom(8))
|
||||
prv1 = bytes2long(urandom(32))
|
||||
prv2 = bytes2long(urandom(32))
|
||||
pub1 = public_key(curve, prv1)
|
||||
pub2 = public_key(curve, prv2)
|
||||
kek1 = kek_34102012512(curve, prv1, pub2, ukm)
|
||||
kek2 = kek_34102012512(curve, prv2, pub1, ukm)
|
||||
self.assertSequenceEqual(kek1, kek2)
|
||||
kek1 = kek_34102012512(curve, prv1, pub1, ukm)
|
||||
kek2 = kek_34102012512(curve, prv2, pub2, ukm)
|
||||
self.assertNotEqual(kek1, kek2)
|
||||
@ -1,159 +0,0 @@
|
||||
# coding: utf-8
|
||||
# PyGOST -- Pure Python GOST cryptographic functions library
|
||||
# Copyright (C) 2015-2023 Sergey Matveev <stargrave@stargrave.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, version 3 of the License.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from os import urandom
|
||||
from random import randint
|
||||
from unittest import skip
|
||||
from unittest import TestCase
|
||||
import hmac
|
||||
|
||||
from pygost import gost34112012256
|
||||
from pygost import gost34112012512
|
||||
from pygost.gost34112012256 import GOST34112012256
|
||||
from pygost.gost34112012512 import GOST34112012512
|
||||
from pygost.gost34112012512 import pbkdf2
|
||||
from pygost.utils import hexdec
|
||||
from pygost.utils import hexenc
|
||||
|
||||
|
||||
class TestCopy(TestCase):
|
||||
def runTest(self):
|
||||
m = GOST34112012256()
|
||||
c = m.copy()
|
||||
m.update(b"foobar")
|
||||
c.update(b"foo")
|
||||
c.update(b"bar")
|
||||
self.assertSequenceEqual(m.digest(), c.digest())
|
||||
|
||||
|
||||
class TestSymmetric(TestCase):
|
||||
def runTest(self):
|
||||
chunks = []
|
||||
for _ in range(randint(1, 10)):
|
||||
chunks.append(urandom(randint(20, 80)))
|
||||
m = GOST34112012256()
|
||||
for chunk in chunks:
|
||||
m.update(chunk)
|
||||
self.assertSequenceEqual(
|
||||
m.hexdigest(),
|
||||
GOST34112012256(b"".join(chunks)).hexdigest(),
|
||||
)
|
||||
|
||||
|
||||
class TestHMAC(TestCase):
|
||||
"""RFC 7836
|
||||
"""
|
||||
def test_256(self):
|
||||
for digestmod in (GOST34112012256, gost34112012256):
|
||||
self.assertSequenceEqual(
|
||||
hmac.new(
|
||||
key=hexdec("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"),
|
||||
msg=hexdec("0126bdb87800af214341456563780100"),
|
||||
digestmod=digestmod,
|
||||
).hexdigest(),
|
||||
"a1aa5f7de402d7b3d323f2991c8d4534013137010a83754fd0af6d7cd4922ed9",
|
||||
)
|
||||
|
||||
def test_512(self):
|
||||
for digestmod in (GOST34112012512, gost34112012512):
|
||||
self.assertSequenceEqual(
|
||||
hmac.new(
|
||||
key=hexdec("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"),
|
||||
msg=hexdec("0126bdb87800af214341456563780100"),
|
||||
digestmod=digestmod,
|
||||
).hexdigest(),
|
||||
"a59bab22ecae19c65fbde6e5f4e9f5d8549d31f037f9df9b905500e171923a773d5f1530f2ed7e964cb2eedc29e9ad2f3afe93b2814f79f5000ffc0366c251e6",
|
||||
)
|
||||
|
||||
|
||||
class TestVectors(TestCase):
|
||||
def test_m1(self):
|
||||
m = hexdec("323130393837363534333231303938373635343332313039383736353433323130393837363534333231303938373635343332313039383736353433323130")[::-1]
|
||||
self.assertSequenceEqual(
|
||||
GOST34112012512(m).digest(),
|
||||
hexdec("486f64c1917879417fef082b3381a4e211c324f074654c38823a7b76f830ad00fa1fbae42b1285c0352f227524bc9ab16254288dd6863dccd5b9f54a1ad0541b")[::-1]
|
||||
)
|
||||
self.assertSequenceEqual(
|
||||
GOST34112012256(m).digest(),
|
||||
hexdec("00557be5e584fd52a449b16b0251d05d27f94ab76cbaa6da890b59d8ef1e159d")[::-1]
|
||||
)
|
||||
|
||||
def test_m2(self):
|
||||
m = u"Се ветри, Стрибожи внуци, веютъ с моря стрелами на храбрыя плъкы Игоревы".encode("cp1251")
|
||||
self.assertSequenceEqual(m, hexdec("fbe2e5f0eee3c820fbeafaebef20fffbf0e1e0f0f520e0ed20e8ece0ebe5f0f2f120fff0eeec20f120faf2fee5e2202ce8f6f3ede220e8e6eee1e8f0f2d1202ce8f0f2e5e220e5d1")[::-1])
|
||||
self.assertSequenceEqual(
|
||||
GOST34112012512(m).digest(),
|
||||
hexdec("28fbc9bada033b1460642bdcddb90c3fb3e56c497ccd0f62b8a2ad4935e85f037613966de4ee00531ae60f3b5a47f8dae06915d5f2f194996fcabf2622e6881e")[::-1]
|
||||
)
|
||||
self.assertSequenceEqual(
|
||||
GOST34112012256(m).digest(),
|
||||
hexdec("508f7e553c06501d749a66fc28c6cac0b005746d97537fa85d9e40904efed29d")[::-1]
|
||||
)
|
||||
|
||||
def test_habr144(self):
|
||||
"""Test vector from https://habr.com/ru/post/452200/
|
||||
"""
|
||||
m = hexdec("d0cf11e0a1b11ae1000000000000000000000000000000003e000300feff0900060000000000000000000000010000000100000000000000001000002400000001000000feffffff0000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")
|
||||
self.assertSequenceEqual(
|
||||
GOST34112012256(m).hexdigest(),
|
||||
"c766085540caaa8953bfcf7a1ba220619cee50d65dc242f82f23ba4b180b18e0",
|
||||
)
|
||||
|
||||
|
||||
class TestPBKDF2(TestCase):
|
||||
"""http://tc26.ru/.../R_50.1.111-2016.pdf
|
||||
"""
|
||||
def test_1(self):
|
||||
self.assertSequenceEqual(
|
||||
hexenc(pbkdf2(b"password", b"salt", 1, 64)),
|
||||
"64770af7f748c3b1c9ac831dbcfd85c26111b30a8a657ddc3056b80ca73e040d2854fd36811f6d825cc4ab66ec0a68a490a9e5cf5156b3a2b7eecddbf9a16b47",
|
||||
)
|
||||
|
||||
def test_2(self):
|
||||
self.assertSequenceEqual(
|
||||
hexenc(pbkdf2(b"password", b"salt", 2, 64)),
|
||||
"5a585bafdfbb6e8830d6d68aa3b43ac00d2e4aebce01c9b31c2caed56f0236d4d34b2b8fbd2c4e89d54d46f50e47d45bbac301571743119e8d3c42ba66d348de",
|
||||
)
|
||||
|
||||
def test_3(self):
|
||||
self.assertSequenceEqual(
|
||||
hexenc(pbkdf2(b"password", b"salt", 4096, 64)),
|
||||
"e52deb9a2d2aaff4e2ac9d47a41f34c20376591c67807f0477e32549dc341bc7867c09841b6d58e29d0347c996301d55df0d34e47cf68f4e3c2cdaf1d9ab86c3",
|
||||
)
|
||||
|
||||
@skip("it takes too long")
|
||||
def test_4(self):
|
||||
self.assertSequenceEqual(
|
||||
hexenc(pbkdf2(b"password", b"salt", 1677216, 64)),
|
||||
"49e4843bba76e300afe24c4d23dc7392def12f2c0e244172367cd70a8982ac361adb601c7e2a314e8cb7b1e9df840e36ab5615be5d742b6cf203fb55fdc48071",
|
||||
)
|
||||
|
||||
def test_5(self):
|
||||
self.assertSequenceEqual(
|
||||
hexenc(pbkdf2(
|
||||
b"passwordPASSWORDpassword",
|
||||
b"saltSALTsaltSALTsaltSALTsaltSALTsalt",
|
||||
4096,
|
||||
100,
|
||||
)),
|
||||
"b2d8f1245fc4d29274802057e4b54e0a0753aa22fc53760b301cf008679e58fe4bee9addcae99ba2b0b20f431a9c5e50f395c89387d0945aedeca6eb4015dfc2bd2421ee9bb71183ba882ceebfef259f33f9e27dc6178cb89dc37428cf9cc52a2baa2d3a",
|
||||
)
|
||||
|
||||
def test_6(self):
|
||||
self.assertSequenceEqual(
|
||||
hexenc(pbkdf2(b"pass\x00word", b"sa\x00lt", 4096, 64)),
|
||||
"50df062885b69801a3c10248eb0a27ab6e522ffeb20c991c660f001475d73a4e167f782c18e97e92976d9c1d970831ea78ccb879f67068cdac1910740844e830",
|
||||
)
|
||||
@ -1,200 +0,0 @@
|
||||
# coding: utf-8
|
||||
# PyGOST -- Pure Python GOST cryptographic functions library
|
||||
# Copyright (C) 2015-2023 Sergey Matveev <stargrave@stargrave.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, version 3 of the License.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from unittest import skip
|
||||
from unittest import TestCase
|
||||
import hmac
|
||||
|
||||
from pygost import gost341194
|
||||
from pygost.gost341194 import GOST341194
|
||||
from pygost.gost341194 import pbkdf2
|
||||
from pygost.utils import hexenc
|
||||
|
||||
|
||||
class TestCopy(TestCase):
|
||||
def runTest(self):
|
||||
m = GOST341194()
|
||||
c = m.copy()
|
||||
m.update(b"foobar")
|
||||
c.update(b"foo")
|
||||
c.update(b"bar")
|
||||
self.assertSequenceEqual(m.digest(), c.digest())
|
||||
|
||||
|
||||
class TestHMACPEP247(TestCase):
|
||||
def runTest(self):
|
||||
h = hmac.new(b"foo", digestmod=gost341194)
|
||||
h.update(b"foobar")
|
||||
h.digest()
|
||||
|
||||
|
||||
class TestVectors(TestCase):
|
||||
def test_empty(self):
|
||||
self.assertSequenceEqual(
|
||||
GOST341194(b"", "id-GostR3411-94-TestParamSet").hexdigest(),
|
||||
"ce85b99cc46752fffee35cab9a7b0278abb4c2d2055cff685af4912c49490f8d",
|
||||
)
|
||||
|
||||
def test_a(self):
|
||||
self.assertSequenceEqual(
|
||||
GOST341194(b"a", "id-GostR3411-94-TestParamSet").hexdigest(),
|
||||
"d42c539e367c66e9c88a801f6649349c21871b4344c6a573f849fdce62f314dd",
|
||||
)
|
||||
|
||||
def test_abc(self):
|
||||
self.assertSequenceEqual(
|
||||
GOST341194(b"abc", "id-GostR3411-94-TestParamSet").hexdigest(),
|
||||
"f3134348c44fb1b2a277729e2285ebb5cb5e0f29c975bc753b70497c06a4d51d",
|
||||
)
|
||||
|
||||
def test_message_digest(self):
|
||||
self.assertSequenceEqual(
|
||||
GOST341194(b"message digest", "id-GostR3411-94-TestParamSet").hexdigest(),
|
||||
"ad4434ecb18f2c99b60cbe59ec3d2469582b65273f48de72db2fde16a4889a4d",
|
||||
)
|
||||
|
||||
def test_Us(self):
|
||||
self.assertSequenceEqual(
|
||||
GOST341194(128 * b"U", "id-GostR3411-94-TestParamSet").hexdigest(),
|
||||
"53a3a3ed25180cef0c1d85a074273e551c25660a87062a52d926a9e8fe5733a4",
|
||||
)
|
||||
|
||||
def test_dog(self):
|
||||
self.assertSequenceEqual(
|
||||
GOST341194(b"The quick brown fox jumps over the lazy dog", "id-GostR3411-94-TestParamSet",).hexdigest(),
|
||||
"77b7fa410c9ac58a25f49bca7d0468c9296529315eaca76bd1a10f376d1f4294",
|
||||
)
|
||||
|
||||
def test_cog(self):
|
||||
self.assertSequenceEqual(
|
||||
GOST341194(b"The quick brown fox jumps over the lazy cog", "id-GostR3411-94-TestParamSet",).hexdigest(),
|
||||
"a3ebc4daaab78b0be131dab5737a7f67e602670d543521319150d2e14eeec445",
|
||||
)
|
||||
|
||||
def test_rfc32(self):
|
||||
self.assertSequenceEqual(
|
||||
GOST341194(b"This is message, length=32 bytes", "id-GostR3411-94-TestParamSet",).hexdigest(),
|
||||
"b1c466d37519b82e8319819ff32595e047a28cb6f83eff1c6916a815a637fffa",
|
||||
)
|
||||
|
||||
def test_rfc50(self):
|
||||
self.assertSequenceEqual(
|
||||
GOST341194(b"Suppose the original message has length = 50 bytes", "id-GostR3411-94-TestParamSet",).hexdigest(),
|
||||
"471aba57a60a770d3a76130635c1fbea4ef14de51f78b4ae57dd893b62f55208",
|
||||
)
|
||||
|
||||
|
||||
class TestVectorsCryptoPro(TestCase):
|
||||
"""CryptoPro S-box test vectors
|
||||
"""
|
||||
def test_empty(self):
|
||||
self.assertSequenceEqual(
|
||||
GOST341194(b"", "id-GostR3411-94-CryptoProParamSet").hexdigest(),
|
||||
"981e5f3ca30c841487830f84fb433e13ac1101569b9c13584ac483234cd656c0",
|
||||
)
|
||||
|
||||
def test_a(self):
|
||||
self.assertSequenceEqual(
|
||||
GOST341194(b"a", "id-GostR3411-94-CryptoProParamSet").hexdigest(),
|
||||
"e74c52dd282183bf37af0079c9f78055715a103f17e3133ceff1aacf2f403011",
|
||||
)
|
||||
|
||||
def test_abc(self):
|
||||
self.assertSequenceEqual(
|
||||
GOST341194(b"abc", "id-GostR3411-94-CryptoProParamSet").hexdigest(),
|
||||
"b285056dbf18d7392d7677369524dd14747459ed8143997e163b2986f92fd42c",
|
||||
)
|
||||
|
||||
def test_message_digest(self):
|
||||
self.assertSequenceEqual(
|
||||
GOST341194(b"message digest", "id-GostR3411-94-CryptoProParamSet",).hexdigest(),
|
||||
"bc6041dd2aa401ebfa6e9886734174febdb4729aa972d60f549ac39b29721ba0",
|
||||
)
|
||||
|
||||
def test_dog(self):
|
||||
self.assertSequenceEqual(
|
||||
GOST341194(b"The quick brown fox jumps over the lazy dog", "id-GostR3411-94-CryptoProParamSet",).hexdigest(),
|
||||
"9004294a361a508c586fe53d1f1b02746765e71b765472786e4770d565830a76",
|
||||
)
|
||||
|
||||
def test_32(self):
|
||||
self.assertSequenceEqual(
|
||||
GOST341194(b"This is message, length=32 bytes", "id-GostR3411-94-CryptoProParamSet",).hexdigest(),
|
||||
"2cefc2f7b7bdc514e18ea57fa74ff357e7fa17d652c75f69cb1be7893ede48eb",
|
||||
)
|
||||
|
||||
def test_50(self):
|
||||
self.assertSequenceEqual(
|
||||
GOST341194(b"Suppose the original message has length = 50 bytes", "id-GostR3411-94-CryptoProParamSet",).hexdigest(),
|
||||
"c3730c5cbccacf915ac292676f21e8bd4ef75331d9405e5f1a61dc3130a65011",
|
||||
)
|
||||
|
||||
def test_Us(self):
|
||||
self.assertSequenceEqual(
|
||||
GOST341194(128 * b"U", "id-GostR3411-94-CryptoProParamSet").hexdigest(),
|
||||
"1c4ac7614691bbf427fa2316216be8f10d92edfd37cd1027514c1008f649c4e8",
|
||||
)
|
||||
|
||||
|
||||
class TestPBKDF2(TestCase):
|
||||
"""http://tc26.ru/methods/containers_v1/Addition_to_PKCS5_v1_0.pdf test vectors
|
||||
"""
|
||||
def test_1(self):
|
||||
self.assertSequenceEqual(
|
||||
hexenc(pbkdf2(b"password", b"salt", 1, 32)),
|
||||
"7314e7c04fb2e662c543674253f68bd0b73445d07f241bed872882da21662d58",
|
||||
)
|
||||
|
||||
def test_2(self):
|
||||
self.assertSequenceEqual(
|
||||
hexenc(pbkdf2(b"password", b"salt", 2, 32)),
|
||||
"990dfa2bd965639ba48b07b792775df79f2db34fef25f274378872fed7ed1bb3",
|
||||
)
|
||||
|
||||
def test_3(self):
|
||||
self.assertSequenceEqual(
|
||||
hexenc(pbkdf2(b"password", b"salt", 4096, 32)),
|
||||
"1f1829a94bdff5be10d0aeb36af498e7a97467f3b31116a5a7c1afff9deadafe",
|
||||
)
|
||||
|
||||
@skip("it takes too long")
|
||||
def test_4(self):
|
||||
self.assertSequenceEqual(
|
||||
hexenc(pbkdf2(b"password", b"salt", 16777216, 32)),
|
||||
"a57ae5a6088396d120850c5c09de0a525100938a59b1b5c3f7810910d05fcd97",
|
||||
)
|
||||
|
||||
def test_5(self):
|
||||
self.assertSequenceEqual(
|
||||
hexenc(pbkdf2(
|
||||
b"passwordPASSWORDpassword",
|
||||
b"saltSALTsaltSALTsaltSALTsaltSALTsalt",
|
||||
4096,
|
||||
40,
|
||||
)),
|
||||
"788358c69cb2dbe251a7bb17d5f4241f265a792a35becde8d56f326b49c85047b7638acb4764b1fd",
|
||||
)
|
||||
|
||||
def test_6(self):
|
||||
self.assertSequenceEqual(
|
||||
hexenc(pbkdf2(
|
||||
b"pass\x00word",
|
||||
b"sa\x00lt",
|
||||
4096,
|
||||
20,
|
||||
)),
|
||||
"43e06c5590b08c0225242373127edf9c8e9c3291",
|
||||
)
|
||||
@ -1,137 +0,0 @@
|
||||
# coding: utf-8
|
||||
# PyGOST -- Pure Python GOST cryptographic functions library
|
||||
# Copyright (C) 2015-2023 Sergey Matveev <stargrave@stargrave.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, version 3 of the License.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from unittest import TestCase
|
||||
|
||||
from pygost.gost3412 import C
|
||||
from pygost.gost3412 import GOST3412Kuznechik
|
||||
from pygost.gost3412 import GOST3412Magma
|
||||
from pygost.gost3412 import L
|
||||
from pygost.gost3412 import PI
|
||||
from pygost.utils import hexdec
|
||||
|
||||
|
||||
def S(blk):
|
||||
return bytearray(PI[v] for v in blk)
|
||||
|
||||
|
||||
def R(blk):
|
||||
return L(blk, rounds=1)
|
||||
|
||||
|
||||
class STest(TestCase):
|
||||
def test_vec1(self):
|
||||
blk = bytearray(hexdec("ffeeddccbbaa99881122334455667700"))
|
||||
self.assertSequenceEqual(S(blk), hexdec("b66cd8887d38e8d77765aeea0c9a7efc"))
|
||||
|
||||
def test_vec2(self):
|
||||
blk = bytearray(hexdec("b66cd8887d38e8d77765aeea0c9a7efc"))
|
||||
self.assertSequenceEqual(S(blk), hexdec("559d8dd7bd06cbfe7e7b262523280d39"))
|
||||
|
||||
def test_vec3(self):
|
||||
blk = bytearray(hexdec("559d8dd7bd06cbfe7e7b262523280d39"))
|
||||
self.assertSequenceEqual(S(blk), hexdec("0c3322fed531e4630d80ef5c5a81c50b"))
|
||||
|
||||
def test_vec4(self):
|
||||
blk = bytearray(hexdec("0c3322fed531e4630d80ef5c5a81c50b"))
|
||||
self.assertSequenceEqual(S(blk), hexdec("23ae65633f842d29c5df529c13f5acda"))
|
||||
|
||||
|
||||
class RTest(TestCase):
|
||||
def test_vec1(self):
|
||||
blk = bytearray(hexdec("00000000000000000000000000000100"))
|
||||
self.assertSequenceEqual(R(blk), hexdec("94000000000000000000000000000001"))
|
||||
|
||||
def test_vec2(self):
|
||||
blk = bytearray(hexdec("94000000000000000000000000000001"))
|
||||
self.assertSequenceEqual(R(blk), hexdec("a5940000000000000000000000000000"))
|
||||
|
||||
def test_vec3(self):
|
||||
blk = bytearray(hexdec("a5940000000000000000000000000000"))
|
||||
self.assertSequenceEqual(R(blk), hexdec("64a59400000000000000000000000000"))
|
||||
|
||||
def test_vec4(self):
|
||||
blk = bytearray(hexdec("64a59400000000000000000000000000"))
|
||||
self.assertSequenceEqual(R(blk), hexdec("0d64a594000000000000000000000000"))
|
||||
|
||||
|
||||
class LTest(TestCase):
|
||||
def test_vec1(self):
|
||||
blk = bytearray(hexdec("64a59400000000000000000000000000"))
|
||||
self.assertSequenceEqual(L(blk), hexdec("d456584dd0e3e84cc3166e4b7fa2890d"))
|
||||
|
||||
def test_vec2(self):
|
||||
blk = bytearray(hexdec("d456584dd0e3e84cc3166e4b7fa2890d"))
|
||||
self.assertSequenceEqual(L(blk), hexdec("79d26221b87b584cd42fbc4ffea5de9a"))
|
||||
|
||||
def test_vec3(self):
|
||||
blk = bytearray(hexdec("79d26221b87b584cd42fbc4ffea5de9a"))
|
||||
self.assertSequenceEqual(L(blk), hexdec("0e93691a0cfc60408b7b68f66b513c13"))
|
||||
|
||||
def test_vec4(self):
|
||||
blk = bytearray(hexdec("0e93691a0cfc60408b7b68f66b513c13"))
|
||||
self.assertSequenceEqual(L(blk), hexdec("e6a8094fee0aa204fd97bcb0b44b8580"))
|
||||
|
||||
|
||||
class KuznechikTest(TestCase):
|
||||
key = hexdec("8899aabbccddeeff0011223344556677fedcba98765432100123456789abcdef")
|
||||
plaintext = hexdec("1122334455667700ffeeddccbbaa9988")
|
||||
ciphertext = hexdec("7f679d90bebc24305a468d42b9d4edcd")
|
||||
|
||||
def test_c(self):
|
||||
self.assertSequenceEqual(C[0], hexdec("6ea276726c487ab85d27bd10dd849401"))
|
||||
self.assertSequenceEqual(C[1], hexdec("dc87ece4d890f4b3ba4eb92079cbeb02"))
|
||||
self.assertSequenceEqual(C[2], hexdec("b2259a96b4d88e0be7690430a44f7f03"))
|
||||
self.assertSequenceEqual(C[3], hexdec("7bcd1b0b73e32ba5b79cb140f2551504"))
|
||||
self.assertSequenceEqual(C[4], hexdec("156f6d791fab511deabb0c502fd18105"))
|
||||
self.assertSequenceEqual(C[5], hexdec("a74af7efab73df160dd208608b9efe06"))
|
||||
self.assertSequenceEqual(C[6], hexdec("c9e8819dc73ba5ae50f5b570561a6a07"))
|
||||
self.assertSequenceEqual(C[7], hexdec("f6593616e6055689adfba18027aa2a08"))
|
||||
|
||||
def test_roundkeys(self):
|
||||
ciph = GOST3412Kuznechik(self.key)
|
||||
self.assertSequenceEqual(ciph.ks[0], hexdec("8899aabbccddeeff0011223344556677"))
|
||||
self.assertSequenceEqual(ciph.ks[1], hexdec("fedcba98765432100123456789abcdef"))
|
||||
self.assertSequenceEqual(ciph.ks[2], hexdec("db31485315694343228d6aef8cc78c44"))
|
||||
self.assertSequenceEqual(ciph.ks[3], hexdec("3d4553d8e9cfec6815ebadc40a9ffd04"))
|
||||
self.assertSequenceEqual(ciph.ks[4], hexdec("57646468c44a5e28d3e59246f429f1ac"))
|
||||
self.assertSequenceEqual(ciph.ks[5], hexdec("bd079435165c6432b532e82834da581b"))
|
||||
self.assertSequenceEqual(ciph.ks[6], hexdec("51e640757e8745de705727265a0098b1"))
|
||||
self.assertSequenceEqual(ciph.ks[7], hexdec("5a7925017b9fdd3ed72a91a22286f984"))
|
||||
self.assertSequenceEqual(ciph.ks[8], hexdec("bb44e25378c73123a5f32f73cdb6e517"))
|
||||
self.assertSequenceEqual(ciph.ks[9], hexdec("72e9dd7416bcf45b755dbaa88e4a4043"))
|
||||
|
||||
def test_encrypt(self):
|
||||
ciph = GOST3412Kuznechik(self.key)
|
||||
self.assertSequenceEqual(ciph.encrypt(self.plaintext), self.ciphertext)
|
||||
|
||||
def test_decrypt(self):
|
||||
ciph = GOST3412Kuznechik(self.key)
|
||||
self.assertSequenceEqual(ciph.decrypt(self.ciphertext), self.plaintext)
|
||||
|
||||
|
||||
class MagmaTest(TestCase):
|
||||
key = hexdec("ffeeddccbbaa99887766554433221100f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff")
|
||||
plaintext = hexdec("fedcba9876543210")
|
||||
ciphertext = hexdec("4ee901e5c2d8ca3d")
|
||||
|
||||
def test_encrypt(self):
|
||||
ciph = GOST3412Magma(self.key)
|
||||
self.assertSequenceEqual(ciph.encrypt(self.plaintext), self.ciphertext)
|
||||
|
||||
def test_decrypt(self):
|
||||
ciph = GOST3412Magma(self.key)
|
||||
self.assertSequenceEqual(ciph.decrypt(self.ciphertext), self.plaintext)
|
||||
@ -1,766 +0,0 @@
|
||||
# coding: utf-8
|
||||
# PyGOST -- Pure Python GOST cryptographic functions library
|
||||
# Copyright (C) 2015-2023 Sergey Matveev <stargrave@stargrave.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, version 3 of the License.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from os import urandom
|
||||
from random import randint
|
||||
from unittest import TestCase
|
||||
|
||||
from pygost.gost3412 import GOST3412Kuznechik
|
||||
from pygost.gost3412 import GOST3412Magma
|
||||
from pygost.gost3413 import _mac_ks
|
||||
from pygost.gost3413 import acpkm
|
||||
from pygost.gost3413 import acpkm_master
|
||||
from pygost.gost3413 import cbc_decrypt
|
||||
from pygost.gost3413 import cbc_encrypt
|
||||
from pygost.gost3413 import cfb_decrypt
|
||||
from pygost.gost3413 import cfb_encrypt
|
||||
from pygost.gost3413 import ctr
|
||||
from pygost.gost3413 import ctr_acpkm
|
||||
from pygost.gost3413 import ecb_decrypt
|
||||
from pygost.gost3413 import ecb_encrypt
|
||||
from pygost.gost3413 import KEYSIZE
|
||||
from pygost.gost3413 import mac
|
||||
from pygost.gost3413 import mac_acpkm_master
|
||||
from pygost.gost3413 import ofb
|
||||
from pygost.gost3413 import pad2
|
||||
from pygost.gost3413 import pad_iso10126
|
||||
from pygost.gost3413 import unpad2
|
||||
from pygost.gost3413 import unpad_iso10126
|
||||
from pygost.utils import hexdec
|
||||
from pygost.utils import hexenc
|
||||
from pygost.utils import strxor
|
||||
|
||||
|
||||
class Pad2Test(TestCase):
|
||||
def test_symmetric(self):
|
||||
for _ in range(100):
|
||||
for blocksize in (GOST3412Magma.blocksize, GOST3412Kuznechik.blocksize):
|
||||
data = urandom(randint(0, blocksize * 3))
|
||||
self.assertSequenceEqual(
|
||||
unpad2(pad2(data, blocksize), blocksize),
|
||||
data,
|
||||
)
|
||||
|
||||
|
||||
class GOST3412KuznechikModesTest(TestCase):
|
||||
key = hexdec("8899aabbccddeeff0011223344556677fedcba98765432100123456789abcdef")
|
||||
ciph = GOST3412Kuznechik(key)
|
||||
plaintext = ""
|
||||
plaintext += "1122334455667700ffeeddccbbaa9988"
|
||||
plaintext += "00112233445566778899aabbcceeff0a"
|
||||
plaintext += "112233445566778899aabbcceeff0a00"
|
||||
plaintext += "2233445566778899aabbcceeff0a0011"
|
||||
iv = hexdec("1234567890abcef0a1b2c3d4e5f0011223344556677889901213141516171819")
|
||||
|
||||
def test_ecb_vectors(self):
|
||||
ciphtext = ""
|
||||
ciphtext += "7f679d90bebc24305a468d42b9d4edcd"
|
||||
ciphtext += "b429912c6e0032f9285452d76718d08b"
|
||||
ciphtext += "f0ca33549d247ceef3f5a5313bd4b157"
|
||||
ciphtext += "d0b09ccde830b9eb3a02c4c5aa8ada98"
|
||||
self.assertSequenceEqual(
|
||||
hexenc(ecb_encrypt(
|
||||
self.ciph.encrypt,
|
||||
GOST3412Kuznechik.blocksize,
|
||||
hexdec(self.plaintext),
|
||||
)),
|
||||
ciphtext,
|
||||
)
|
||||
self.assertSequenceEqual(
|
||||
hexenc(ecb_decrypt(
|
||||
self.ciph.decrypt,
|
||||
GOST3412Kuznechik.blocksize,
|
||||
hexdec(ciphtext),
|
||||
)),
|
||||
self.plaintext,
|
||||
)
|
||||
|
||||
def test_ecb_symmetric(self):
|
||||
for _ in range(100):
|
||||
pt = pad2(urandom(randint(0, 16 * 2)), GOST3412Kuznechik.blocksize)
|
||||
ciph = GOST3412Kuznechik(urandom(KEYSIZE))
|
||||
ct = ecb_encrypt(ciph.encrypt, GOST3412Kuznechik.blocksize, pt)
|
||||
self.assertSequenceEqual(ecb_decrypt(
|
||||
ciph.decrypt,
|
||||
GOST3412Kuznechik.blocksize,
|
||||
ct,
|
||||
), pt)
|
||||
|
||||
def test_ctr_vectors(self):
|
||||
ciphtext = ""
|
||||
ciphtext += "f195d8bec10ed1dbd57b5fa240bda1b8"
|
||||
ciphtext += "85eee733f6a13e5df33ce4b33c45dee4"
|
||||
ciphtext += "a5eae88be6356ed3d5e877f13564a3a5"
|
||||
ciphtext += "cb91fab1f20cbab6d1c6d15820bdba73"
|
||||
iv = self.iv[:GOST3412Kuznechik.blocksize // 2]
|
||||
self.assertSequenceEqual(
|
||||
hexenc(ctr(
|
||||
self.ciph.encrypt,
|
||||
GOST3412Kuznechik.blocksize,
|
||||
hexdec(self.plaintext),
|
||||
iv,
|
||||
)),
|
||||
ciphtext,
|
||||
)
|
||||
self.assertSequenceEqual(
|
||||
hexenc(ctr(
|
||||
self.ciph.encrypt,
|
||||
GOST3412Kuznechik.blocksize,
|
||||
hexdec(ciphtext),
|
||||
iv,
|
||||
)),
|
||||
self.plaintext,
|
||||
)
|
||||
|
||||
def test_ctr_symmetric(self):
|
||||
for _ in range(100):
|
||||
pt = urandom(randint(0, 16 * 2))
|
||||
iv = urandom(GOST3412Kuznechik.blocksize // 2)
|
||||
ciph = GOST3412Kuznechik(urandom(KEYSIZE))
|
||||
ct = ctr(ciph.encrypt, GOST3412Kuznechik.blocksize, pt, iv)
|
||||
self.assertSequenceEqual(ctr(
|
||||
ciph.encrypt,
|
||||
GOST3412Kuznechik.blocksize,
|
||||
ct,
|
||||
iv,
|
||||
), pt)
|
||||
|
||||
def test_ofb_vectors(self):
|
||||
ciphtext = ""
|
||||
ciphtext += "81800a59b1842b24ff1f795e897abd95"
|
||||
ciphtext += "ed5b47a7048cfab48fb521369d9326bf"
|
||||
ciphtext += "66a257ac3ca0b8b1c80fe7fc10288a13"
|
||||
ciphtext += "203ebbc066138660a0292243f6903150"
|
||||
self.assertSequenceEqual(
|
||||
hexenc(ofb(
|
||||
self.ciph.encrypt,
|
||||
GOST3412Kuznechik.blocksize,
|
||||
hexdec(self.plaintext),
|
||||
self.iv,
|
||||
)),
|
||||
ciphtext,
|
||||
)
|
||||
self.assertSequenceEqual(
|
||||
hexenc(ofb(
|
||||
self.ciph.encrypt,
|
||||
GOST3412Kuznechik.blocksize,
|
||||
hexdec(ciphtext),
|
||||
self.iv,
|
||||
)),
|
||||
self.plaintext,
|
||||
)
|
||||
|
||||
def test_ofb_symmetric(self):
|
||||
for _ in range(100):
|
||||
pt = urandom(randint(0, 16 * 2))
|
||||
iv = urandom(GOST3412Kuznechik.blocksize * 2)
|
||||
ciph = GOST3412Kuznechik(urandom(KEYSIZE))
|
||||
ct = ofb(ciph.encrypt, GOST3412Kuznechik.blocksize, pt, iv)
|
||||
self.assertSequenceEqual(ofb(
|
||||
ciph.encrypt,
|
||||
GOST3412Kuznechik.blocksize,
|
||||
ct,
|
||||
iv,
|
||||
), pt)
|
||||
|
||||
def test_ofb_manual(self):
|
||||
iv = [urandom(GOST3412Kuznechik.blocksize) for _ in range(randint(2, 10))]
|
||||
pt = [
|
||||
urandom(GOST3412Kuznechik.blocksize)
|
||||
for _ in range(len(iv), len(iv) + randint(1, 10))
|
||||
]
|
||||
ciph = GOST3412Kuznechik(urandom(KEYSIZE))
|
||||
r = [ciph.encrypt(i) for i in iv]
|
||||
for i in range(len(pt) - len(iv)):
|
||||
r.append(ciph.encrypt(r[i]))
|
||||
ct = [strxor(g, r) for g, r in zip(pt, r)]
|
||||
self.assertSequenceEqual(
|
||||
ofb(ciph.encrypt, GOST3412Kuznechik.blocksize, b"".join(pt), b"".join(iv)),
|
||||
b"".join(ct),
|
||||
)
|
||||
|
||||
def test_cbc_vectors(self):
|
||||
ciphtext = ""
|
||||
ciphtext += "689972d4a085fa4d90e52e3d6d7dcc27"
|
||||
ciphtext += "2826e661b478eca6af1e8e448d5ea5ac"
|
||||
ciphtext += "fe7babf1e91999e85640e8b0f49d90d0"
|
||||
ciphtext += "167688065a895c631a2d9a1560b63970"
|
||||
self.assertSequenceEqual(
|
||||
hexenc(cbc_encrypt(
|
||||
self.ciph.encrypt,
|
||||
GOST3412Kuznechik.blocksize,
|
||||
hexdec(self.plaintext),
|
||||
self.iv,
|
||||
)),
|
||||
ciphtext,
|
||||
)
|
||||
self.assertSequenceEqual(
|
||||
hexenc(cbc_decrypt(
|
||||
self.ciph.decrypt,
|
||||
GOST3412Kuznechik.blocksize,
|
||||
hexdec(ciphtext),
|
||||
self.iv,
|
||||
)),
|
||||
self.plaintext,
|
||||
)
|
||||
|
||||
def test_cbc_symmetric(self):
|
||||
for _ in range(100):
|
||||
pt = pad2(urandom(randint(0, 16 * 2)), GOST3412Kuznechik.blocksize)
|
||||
iv = urandom(GOST3412Kuznechik.blocksize * 2)
|
||||
ciph = GOST3412Kuznechik(urandom(KEYSIZE))
|
||||
ct = cbc_encrypt(ciph.encrypt, GOST3412Kuznechik.blocksize, pt, iv)
|
||||
self.assertSequenceEqual(cbc_decrypt(
|
||||
ciph.decrypt,
|
||||
GOST3412Kuznechik.blocksize,
|
||||
ct,
|
||||
iv,
|
||||
), pt)
|
||||
|
||||
def test_cfb_vectors(self):
|
||||
ciphtext = ""
|
||||
ciphtext += "81800a59b1842b24ff1f795e897abd95"
|
||||
ciphtext += "ed5b47a7048cfab48fb521369d9326bf"
|
||||
ciphtext += "79f2a8eb5cc68d38842d264e97a238b5"
|
||||
ciphtext += "4ffebecd4e922de6c75bd9dd44fbf4d1"
|
||||
self.assertSequenceEqual(
|
||||
hexenc(cfb_encrypt(
|
||||
self.ciph.encrypt,
|
||||
GOST3412Kuznechik.blocksize,
|
||||
hexdec(self.plaintext),
|
||||
self.iv,
|
||||
)),
|
||||
ciphtext,
|
||||
)
|
||||
self.assertSequenceEqual(
|
||||
hexenc(cfb_decrypt(
|
||||
self.ciph.encrypt,
|
||||
GOST3412Kuznechik.blocksize,
|
||||
hexdec(ciphtext),
|
||||
self.iv,
|
||||
)),
|
||||
self.plaintext,
|
||||
)
|
||||
|
||||
def test_cfb_symmetric(self):
|
||||
for _ in range(100):
|
||||
pt = urandom(randint(0, 16 * 2))
|
||||
iv = urandom(GOST3412Kuznechik.blocksize * 2)
|
||||
ciph = GOST3412Kuznechik(urandom(KEYSIZE))
|
||||
ct = cfb_encrypt(ciph.encrypt, GOST3412Kuznechik.blocksize, pt, iv)
|
||||
self.assertSequenceEqual(cfb_decrypt(
|
||||
ciph.encrypt,
|
||||
GOST3412Kuznechik.blocksize,
|
||||
ct,
|
||||
iv,
|
||||
), pt)
|
||||
|
||||
def test_mac_vectors(self):
|
||||
k1, k2 = _mac_ks(self.ciph.encrypt, GOST3412Kuznechik.blocksize)
|
||||
self.assertSequenceEqual(hexenc(k1), "297d82bc4d39e3ca0de0573298151dc7")
|
||||
self.assertSequenceEqual(hexenc(k2), "52fb05789a73c7941bc0ae65302a3b8e")
|
||||
self.assertSequenceEqual(
|
||||
hexenc(mac(
|
||||
self.ciph.encrypt,
|
||||
GOST3412Kuznechik.blocksize,
|
||||
hexdec(self.plaintext),
|
||||
)[:8]),
|
||||
"336f4d296059fbe3",
|
||||
)
|
||||
|
||||
def test_mac_applies(self):
|
||||
for _ in range(100):
|
||||
data = urandom(randint(0, 16 * 2))
|
||||
ciph = GOST3412Kuznechik(urandom(KEYSIZE))
|
||||
mac(ciph.encrypt, GOST3412Kuznechik.blocksize, data)
|
||||
|
||||
|
||||
class GOST3412MagmaModesTest(TestCase):
|
||||
key = hexdec("ffeeddccbbaa99887766554433221100f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff")
|
||||
ciph = GOST3412Magma(key)
|
||||
plaintext = ""
|
||||
plaintext += "92def06b3c130a59"
|
||||
plaintext += "db54c704f8189d20"
|
||||
plaintext += "4a98fb2e67a8024c"
|
||||
plaintext += "8912409b17b57e41"
|
||||
iv = hexdec("1234567890abcdef234567890abcdef134567890abcdef12")
|
||||
|
||||
def test_ecb_vectors(self):
|
||||
ciphtext = ""
|
||||
ciphtext += "2b073f0494f372a0"
|
||||
ciphtext += "de70e715d3556e48"
|
||||
ciphtext += "11d8d9e9eacfbc1e"
|
||||
ciphtext += "7c68260996c67efb"
|
||||
self.assertSequenceEqual(
|
||||
hexenc(ecb_encrypt(
|
||||
self.ciph.encrypt,
|
||||
GOST3412Magma.blocksize,
|
||||
hexdec(self.plaintext),
|
||||
)),
|
||||
ciphtext,
|
||||
)
|
||||
self.assertSequenceEqual(
|
||||
hexenc(ecb_decrypt(
|
||||
self.ciph.decrypt,
|
||||
GOST3412Magma.blocksize,
|
||||
hexdec(ciphtext),
|
||||
)),
|
||||
self.plaintext,
|
||||
)
|
||||
|
||||
def test_ecb_symmetric(self):
|
||||
for _ in range(100):
|
||||
pt = pad2(urandom(randint(0, 16 * 2)), 16)
|
||||
ciph = GOST3412Magma(urandom(KEYSIZE))
|
||||
ct = ecb_encrypt(ciph.encrypt, GOST3412Magma.blocksize, pt)
|
||||
self.assertSequenceEqual(ecb_decrypt(
|
||||
ciph.decrypt,
|
||||
GOST3412Magma.blocksize,
|
||||
ct,
|
||||
), pt)
|
||||
|
||||
def test_ctr_vectors(self):
|
||||
ciphtext = ""
|
||||
ciphtext += "4e98110c97b7b93c"
|
||||
ciphtext += "3e250d93d6e85d69"
|
||||
ciphtext += "136d868807b2dbef"
|
||||
ciphtext += "568eb680ab52a12d"
|
||||
iv = self.iv[:4]
|
||||
self.assertSequenceEqual(
|
||||
hexenc(ctr(
|
||||
self.ciph.encrypt,
|
||||
GOST3412Magma.blocksize,
|
||||
hexdec(self.plaintext),
|
||||
iv,
|
||||
)),
|
||||
ciphtext,
|
||||
)
|
||||
self.assertSequenceEqual(
|
||||
hexenc(ctr(
|
||||
self.ciph.encrypt,
|
||||
GOST3412Magma.blocksize,
|
||||
hexdec(ciphtext),
|
||||
iv,
|
||||
)),
|
||||
self.plaintext,
|
||||
)
|
||||
|
||||
def test_ctr_symmetric(self):
|
||||
for _ in range(100):
|
||||
pt = urandom(randint(0, 16 * 2))
|
||||
iv = urandom(GOST3412Magma.blocksize // 2)
|
||||
ciph = GOST3412Magma(urandom(KEYSIZE))
|
||||
ct = ctr(ciph.encrypt, GOST3412Magma.blocksize, pt, iv)
|
||||
self.assertSequenceEqual(ctr(
|
||||
ciph.encrypt,
|
||||
GOST3412Magma.blocksize,
|
||||
ct,
|
||||
iv,
|
||||
), pt)
|
||||
|
||||
def test_ofb_vectors(self):
|
||||
iv = self.iv[:16]
|
||||
ciphtext = ""
|
||||
ciphtext += "db37e0e266903c83"
|
||||
ciphtext += "0d46644c1f9a089c"
|
||||
ciphtext += "a0f83062430e327e"
|
||||
ciphtext += "c824efb8bd4fdb05"
|
||||
self.assertSequenceEqual(
|
||||
hexenc(ofb(
|
||||
self.ciph.encrypt,
|
||||
GOST3412Magma.blocksize,
|
||||
hexdec(self.plaintext),
|
||||
iv,
|
||||
)),
|
||||
ciphtext,
|
||||
)
|
||||
self.assertSequenceEqual(
|
||||
hexenc(ofb(
|
||||
self.ciph.encrypt,
|
||||
GOST3412Magma.blocksize,
|
||||
hexdec(ciphtext),
|
||||
iv,
|
||||
)),
|
||||
self.plaintext,
|
||||
)
|
||||
|
||||
def test_ofb_symmetric(self):
|
||||
for _ in range(100):
|
||||
pt = urandom(randint(0, 16 * 2))
|
||||
iv = urandom(GOST3412Magma.blocksize * 2)
|
||||
ciph = GOST3412Magma(urandom(KEYSIZE))
|
||||
ct = ofb(ciph.encrypt, GOST3412Magma.blocksize, pt, iv)
|
||||
self.assertSequenceEqual(ofb(
|
||||
ciph.encrypt,
|
||||
GOST3412Magma.blocksize,
|
||||
ct,
|
||||
iv,
|
||||
), pt)
|
||||
|
||||
def test_cbc_vectors(self):
|
||||
ciphtext = ""
|
||||
ciphtext += "96d1b05eea683919"
|
||||
ciphtext += "aff76129abb937b9"
|
||||
ciphtext += "5058b4a1c4bc0019"
|
||||
ciphtext += "20b78b1a7cd7e667"
|
||||
self.assertSequenceEqual(
|
||||
hexenc(cbc_encrypt(
|
||||
self.ciph.encrypt,
|
||||
GOST3412Magma.blocksize,
|
||||
hexdec(self.plaintext),
|
||||
self.iv,
|
||||
)),
|
||||
ciphtext,
|
||||
)
|
||||
self.assertSequenceEqual(
|
||||
hexenc(cbc_decrypt(
|
||||
self.ciph.decrypt,
|
||||
GOST3412Magma.blocksize,
|
||||
hexdec(ciphtext),
|
||||
self.iv,
|
||||
)),
|
||||
self.plaintext,
|
||||
)
|
||||
|
||||
def test_cbc_symmetric(self):
|
||||
for _ in range(100):
|
||||
pt = pad2(urandom(randint(0, 16 * 2)), 16)
|
||||
iv = urandom(GOST3412Magma.blocksize * 2)
|
||||
ciph = GOST3412Magma(urandom(KEYSIZE))
|
||||
ct = cbc_encrypt(ciph.encrypt, GOST3412Magma.blocksize, pt, iv)
|
||||
self.assertSequenceEqual(cbc_decrypt(
|
||||
ciph.decrypt,
|
||||
GOST3412Magma.blocksize,
|
||||
ct,
|
||||
iv,
|
||||
), pt)
|
||||
|
||||
def test_cfb_vectors(self):
|
||||
iv = self.iv[:16]
|
||||
ciphtext = ""
|
||||
ciphtext += "db37e0e266903c83"
|
||||
ciphtext += "0d46644c1f9a089c"
|
||||
ciphtext += "24bdd2035315d38b"
|
||||
ciphtext += "bcc0321421075505"
|
||||
self.assertSequenceEqual(
|
||||
hexenc(cfb_encrypt(
|
||||
self.ciph.encrypt,
|
||||
GOST3412Magma.blocksize,
|
||||
hexdec(self.plaintext),
|
||||
iv,
|
||||
)),
|
||||
ciphtext,
|
||||
)
|
||||
self.assertSequenceEqual(
|
||||
hexenc(cfb_decrypt(
|
||||
self.ciph.encrypt,
|
||||
GOST3412Magma.blocksize,
|
||||
hexdec(ciphtext),
|
||||
iv,
|
||||
)),
|
||||
self.plaintext,
|
||||
)
|
||||
|
||||
def test_cfb_symmetric(self):
|
||||
for _ in range(100):
|
||||
pt = urandom(randint(0, 16 * 2))
|
||||
iv = urandom(GOST3412Magma.blocksize * 2)
|
||||
ciph = GOST3412Magma(urandom(KEYSIZE))
|
||||
ct = cfb_encrypt(ciph.encrypt, GOST3412Magma.blocksize, pt, iv)
|
||||
self.assertSequenceEqual(cfb_decrypt(
|
||||
ciph.encrypt,
|
||||
GOST3412Magma.blocksize,
|
||||
ct,
|
||||
iv,
|
||||
), pt)
|
||||
|
||||
def test_mac_vectors(self):
|
||||
k1, k2 = _mac_ks(self.ciph.encrypt, GOST3412Magma.blocksize)
|
||||
self.assertSequenceEqual(hexenc(k1), "5f459b3342521424")
|
||||
self.assertSequenceEqual(hexenc(k2), "be8b366684a42848")
|
||||
self.assertSequenceEqual(
|
||||
hexenc(mac(
|
||||
self.ciph.encrypt,
|
||||
GOST3412Magma.blocksize,
|
||||
hexdec(self.plaintext),
|
||||
)[:4]),
|
||||
"154e7210",
|
||||
)
|
||||
|
||||
def test_mac_applies(self):
|
||||
for _ in range(100):
|
||||
data = urandom(randint(0, 16 * 2))
|
||||
ciph = GOST3412Magma(urandom(KEYSIZE))
|
||||
mac(ciph.encrypt, GOST3412Magma.blocksize, data)
|
||||
|
||||
|
||||
class TestVectorACPKM(TestCase):
|
||||
"""Test vectors from Р 1323565.1.017-2018
|
||||
"""
|
||||
key = hexdec("8899AABBCCDDEEFF0011223344556677FEDCBA98765432100123456789ABCDEF")
|
||||
|
||||
def test_magma_ctr_acpkm(self):
|
||||
key = acpkm(GOST3412Magma(self.key).encrypt, GOST3412Magma.blocksize)
|
||||
self.assertSequenceEqual(key, hexdec("863EA017842C3D372B18A85A28E2317D74BEFC107720DE0C9E8AB974ABD00CA0"))
|
||||
key = acpkm(GOST3412Magma(key).encrypt, GOST3412Magma.blocksize)
|
||||
self.assertSequenceEqual(key, hexdec("49A5E2677DE555982B8AD5E826652D17EEC847BF5B3997A81CF7FE7F1187BD27"))
|
||||
key = acpkm(GOST3412Magma(key).encrypt, GOST3412Magma.blocksize)
|
||||
self.assertSequenceEqual(key, hexdec("3256BF3F97B5667426A9FB1C5EAABE41893CCDD5A868F9B63B0AA90720FA43C4"))
|
||||
|
||||
def test_magma_ctr(self):
|
||||
encrypter = GOST3412Magma(self.key).encrypt
|
||||
plaintext = hexdec("""
|
||||
11 22 33 44 55 66 77 00 FF EE DD CC BB AA 99 88
|
||||
00 11 22 33 44 55 66 77 88 99 AA BB CC EE FF 0A
|
||||
11 22 33 44 55 66 77 88 99 AA BB CC EE FF 0A 00
|
||||
22 33 44 55 66 77 88 99
|
||||
""".replace("\n", "").replace(" ", ""))
|
||||
iv = hexdec("12345678")
|
||||
ciphertext = hexdec("""
|
||||
2A B8 1D EE EB 1E 4C AB 68 E1 04 C4 BD 6B 94 EA
|
||||
C7 2C 67 AF 6C 2E 5B 6B 0E AF B6 17 70 F1 B3 2E
|
||||
A1 AE 71 14 9E ED 13 82 AB D4 67 18 06 72 EC 6F
|
||||
84 A2 F1 5B 3F CA 72 C1
|
||||
""".replace("\n", "").replace(" ", ""))
|
||||
self.assertSequenceEqual(
|
||||
ctr_acpkm(
|
||||
GOST3412Magma,
|
||||
encrypter,
|
||||
bs=GOST3412Magma.blocksize,
|
||||
section_size=GOST3412Magma.blocksize * 2,
|
||||
data=plaintext,
|
||||
iv=iv
|
||||
),
|
||||
ciphertext,
|
||||
)
|
||||
self.assertSequenceEqual(
|
||||
ctr_acpkm(
|
||||
GOST3412Magma,
|
||||
encrypter,
|
||||
bs=GOST3412Magma.blocksize,
|
||||
section_size=GOST3412Magma.blocksize * 2,
|
||||
data=ciphertext,
|
||||
iv=iv
|
||||
),
|
||||
plaintext,
|
||||
)
|
||||
|
||||
def test_kuznechik_ctr_acpkm(self):
|
||||
key = acpkm(GOST3412Kuznechik(self.key).encrypt, GOST3412Kuznechik.blocksize)
|
||||
self.assertSequenceEqual(key, hexdec("2666ED40AE687811745CA0B448F57A7B390ADB5780307E8E9659AC403AE60C60"))
|
||||
key = acpkm(GOST3412Kuznechik(key).encrypt, GOST3412Kuznechik.blocksize)
|
||||
self.assertSequenceEqual(key, hexdec("BB3DD5402E999B7A3DEBB0DB45448EC530F07365DFEE3ABA8415F77AC8F34CE8"))
|
||||
key = acpkm(GOST3412Kuznechik(key).encrypt, GOST3412Kuznechik.blocksize)
|
||||
self.assertSequenceEqual(key, hexdec("23362FD553CAD2178299A5B5A2D4722E3BB83C730A8BF57CE2DD004017F8C565"))
|
||||
|
||||
def test_kuznechik_ctr(self):
|
||||
encrypter = GOST3412Kuznechik(self.key).encrypt
|
||||
iv = hexdec("1234567890ABCEF0")
|
||||
plaintext = hexdec("""
|
||||
11 22 33 44 55 66 77 00 FF EE DD CC BB AA 99 88
|
||||
00 11 22 33 44 55 66 77 88 99 AA BB CC EE FF 0A
|
||||
11 22 33 44 55 66 77 88 99 AA BB CC EE FF 0A 00
|
||||
22 33 44 55 66 77 88 99 AA BB CC EE FF 0A 00 11
|
||||
33 44 55 66 77 88 99 AA BB CC EE FF 0A 00 11 22
|
||||
44 55 66 77 88 99 AA BB CC EE FF 0A 00 11 22 33
|
||||
55 66 77 88 99 AA BB CC EE FF 0A 00 11 22 33 44
|
||||
""".replace("\n", "").replace(" ", ""))
|
||||
ciphertext = hexdec("""
|
||||
F1 95 D8 BE C1 0E D1 DB D5 7B 5F A2 40 BD A1 B8
|
||||
85 EE E7 33 F6 A1 3E 5D F3 3C E4 B3 3C 45 DE E4
|
||||
4B CE EB 8F 64 6F 4C 55 00 17 06 27 5E 85 E8 00
|
||||
58 7C 4D F5 68 D0 94 39 3E 48 34 AF D0 80 50 46
|
||||
CF 30 F5 76 86 AE EC E1 1C FC 6C 31 6B 8A 89 6E
|
||||
DF FD 07 EC 81 36 36 46 0C 4F 3B 74 34 23 16 3E
|
||||
64 09 A9 C2 82 FA C8 D4 69 D2 21 E7 FB D6 DE 5D
|
||||
""".replace("\n", "").replace(" ", ""))
|
||||
self.assertSequenceEqual(
|
||||
ctr_acpkm(
|
||||
GOST3412Kuznechik,
|
||||
encrypter,
|
||||
bs=GOST3412Kuznechik.blocksize,
|
||||
section_size=GOST3412Kuznechik.blocksize * 2,
|
||||
data=plaintext,
|
||||
iv=iv,
|
||||
),
|
||||
ciphertext,
|
||||
)
|
||||
self.assertSequenceEqual(
|
||||
ctr_acpkm(
|
||||
GOST3412Kuznechik,
|
||||
encrypter,
|
||||
bs=GOST3412Kuznechik.blocksize,
|
||||
section_size=GOST3412Kuznechik.blocksize * 2,
|
||||
data=ciphertext,
|
||||
iv=iv,
|
||||
),
|
||||
plaintext,
|
||||
)
|
||||
|
||||
def test_magma_omac_1_5_blocks(self):
|
||||
encrypter = GOST3412Magma(self.key).encrypt
|
||||
key_section_size = 640 // 8
|
||||
self.assertSequenceEqual(
|
||||
acpkm_master(
|
||||
GOST3412Magma,
|
||||
encrypter,
|
||||
key_section_size=key_section_size,
|
||||
bs=GOST3412Magma.blocksize,
|
||||
keymat_len=KEYSIZE + GOST3412Magma.blocksize,
|
||||
),
|
||||
hexdec("0DF2F5273DA328932AC49D81D36B2558A50DBF9BBCAC74A614B2CCB2F1CBCD8A70638E3DE8B3571E"),
|
||||
)
|
||||
text = hexdec("1122334455667700FFEEDDCC")
|
||||
self.assertSequenceEqual(
|
||||
mac_acpkm_master(
|
||||
GOST3412Magma,
|
||||
encrypter,
|
||||
key_section_size,
|
||||
section_size=GOST3412Magma.blocksize * 2,
|
||||
bs=GOST3412Magma.blocksize,
|
||||
data=text,
|
||||
),
|
||||
hexdec("A0540E3730ACBCF3"),
|
||||
)
|
||||
|
||||
def test_magma_omac_5_blocks(self):
|
||||
encrypter = GOST3412Magma(self.key).encrypt
|
||||
key_section_size = 640 // 8
|
||||
self.assertSequenceEqual(
|
||||
acpkm_master(
|
||||
GOST3412Magma,
|
||||
encrypter,
|
||||
key_section_size=key_section_size,
|
||||
bs=GOST3412Magma.blocksize,
|
||||
keymat_len=3 * (KEYSIZE + GOST3412Magma.blocksize),
|
||||
),
|
||||
hexdec("""
|
||||
0D F2 F5 27 3D A3 28 93 2A C4 9D 81 D3 6B 25 58
|
||||
A5 0D BF 9B BC AC 74 A6 14 B2 CC B2 F1 CB CD 8A
|
||||
70 63 8E 3D E8 B3 57 1E 8D 38 26 D5 5E 63 A1 67
|
||||
E2 40 66 40 54 7B 9F 1F 5F 2B 43 61 2A AE AF DA
|
||||
18 0B AC 86 04 DF A6 FE 53 C2 CE 27 0E 9C 9F 52
|
||||
68 D0 FD BF E1 A3 BD D9 BE 5B 96 D0 A1 20 23 48
|
||||
6E F1 71 0F 92 4A E0 31 30 52 CB 5F CA 0B 79 1E
|
||||
1B AB E8 57 6D 0F E3 A8
|
||||
""".replace("\n", "").replace(" ", "")),
|
||||
)
|
||||
text = hexdec("""
|
||||
11 22 33 44 55 66 77 00 FF EE DD CC BB AA 99 88
|
||||
00 11 22 33 44 55 66 77 88 99 AA BB CC EE FF 0A
|
||||
11 22 33 44 55 66 77 88
|
||||
""".replace("\n", "").replace(" ", ""))
|
||||
self.assertSequenceEqual(
|
||||
mac_acpkm_master(
|
||||
GOST3412Magma,
|
||||
encrypter,
|
||||
key_section_size,
|
||||
section_size=GOST3412Magma.blocksize * 2,
|
||||
bs=GOST3412Magma.blocksize,
|
||||
data=text,
|
||||
),
|
||||
hexdec("34008DAD5496BB8E"),
|
||||
)
|
||||
|
||||
def test_kuznechik_omac_1_5_blocks(self):
|
||||
encrypter = GOST3412Kuznechik(self.key).encrypt
|
||||
key_section_size = 768 // 8
|
||||
self.assertSequenceEqual(
|
||||
acpkm_master(
|
||||
GOST3412Kuznechik,
|
||||
encrypter,
|
||||
key_section_size=key_section_size,
|
||||
bs=GOST3412Kuznechik.blocksize,
|
||||
keymat_len=KEYSIZE + GOST3412Kuznechik.blocksize,
|
||||
),
|
||||
hexdec("""
|
||||
0C AB F1 F2 EF BC 4A C1 60 48 DF 1A 24 C6 05 B2
|
||||
C0 D1 67 3D 75 86 A8 EC 0D D4 2C 45 A4 F9 5B AE
|
||||
0F 2E 26 17 E4 71 48 68 0F C3 E6 17 8D F2 C1 37
|
||||
""".replace("\n", "").replace(" ", ""))
|
||||
)
|
||||
text = hexdec("""
|
||||
11 22 33 44 55 66 77 00 FF EE DD CC BB AA 99 88
|
||||
00 11 22 33 44 55 66 77
|
||||
""".replace("\n", "").replace(" ", ""))
|
||||
self.assertSequenceEqual(
|
||||
mac_acpkm_master(
|
||||
GOST3412Kuznechik,
|
||||
encrypter,
|
||||
key_section_size,
|
||||
section_size=GOST3412Kuznechik.blocksize * 2,
|
||||
bs=GOST3412Kuznechik.blocksize,
|
||||
data=text,
|
||||
),
|
||||
hexdec("B5367F47B62B995EEB2A648C5843145E"),
|
||||
)
|
||||
|
||||
def test_kuznechik_omac_5_blocks(self):
|
||||
encrypter = GOST3412Kuznechik(self.key).encrypt
|
||||
key_section_size = 768 // 8
|
||||
self.assertSequenceEqual(
|
||||
acpkm_master(
|
||||
GOST3412Kuznechik,
|
||||
encrypter,
|
||||
key_section_size=key_section_size,
|
||||
bs=GOST3412Kuznechik.blocksize,
|
||||
keymat_len=3 * (KEYSIZE + GOST3412Kuznechik.blocksize),
|
||||
),
|
||||
hexdec("""
|
||||
0C AB F1 F2 EF BC 4A C1 60 48 DF 1A 24 C6 05 B2
|
||||
C0 D1 67 3D 75 86 A8 EC 0D D4 2C 45 A4 F9 5B AE
|
||||
0F 2E 26 17 E4 71 48 68 0F C3 E6 17 8D F2 C1 37
|
||||
C9 DD A8 9C FF A4 91 FE AD D9 B3 EA B7 03 BB 31
|
||||
BC 7E 92 7F 04 94 72 9F 51 B4 9D 3D F9 C9 46 08
|
||||
00 FB BC F5 ED EE 61 0E A0 2F 01 09 3C 7B C7 42
|
||||
D7 D6 27 15 01 B1 77 77 52 63 C2 A3 49 5A 83 18
|
||||
A8 1C 79 A0 4F 29 66 0E A3 FD A8 74 C6 30 79 9E
|
||||
14 2C 57 79 14 FE A9 0D 3B C2 50 2E 83 36 85 D9
|
||||
""".replace("\n", "").replace(" ", "")),
|
||||
)
|
||||
text = hexdec("""
|
||||
11 22 33 44 55 66 77 00 FF EE DD CC BB AA 99 88
|
||||
00 11 22 33 44 55 66 77 88 99 AA BB CC EE FF 0A
|
||||
11 22 33 44 55 66 77 88 99 AA BB CC EE FF 0A 00
|
||||
22 33 44 55 66 77 88 99 AA BB CC EE FF 0A 00 11
|
||||
33 44 55 66 77 88 99 AA BB CC EE FF 0A 00 11 22
|
||||
""".replace("\n", "").replace(" ", ""))
|
||||
self.assertSequenceEqual(
|
||||
mac_acpkm_master(
|
||||
GOST3412Kuznechik,
|
||||
encrypter,
|
||||
key_section_size,
|
||||
section_size=GOST3412Kuznechik.blocksize * 2,
|
||||
bs=GOST3412Kuznechik.blocksize,
|
||||
data=text,
|
||||
),
|
||||
hexdec("FBB8DCEE45BEA67C35F58C5700898E5D"),
|
||||
)
|
||||
|
||||
|
||||
class ISO10126Test(TestCase):
|
||||
def test_symmetric(self):
|
||||
for _ in range(100):
|
||||
for blocksize in (GOST3412Magma.blocksize, GOST3412Kuznechik.blocksize):
|
||||
data = urandom(randint(0, blocksize * 3))
|
||||
padded = pad_iso10126(data, blocksize)
|
||||
self.assertSequenceEqual(unpad_iso10126(padded, blocksize), data)
|
||||
with self.assertRaises(ValueError):
|
||||
unpad_iso10126(padded[1:], blocksize)
|
||||
|
||||
def test_small(self):
|
||||
with self.assertRaises(ValueError):
|
||||
unpad_iso10126(b"foobar\x00\x09", 8)
|
||||
@ -1,58 +0,0 @@
|
||||
# coding: utf-8
|
||||
# PyGOST -- Pure Python GOST cryptographic functions library
|
||||
# Copyright (C) 2015-2023 Sergey Matveev <stargrave@stargrave.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, version 3 of the License.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from unittest import TestCase
|
||||
|
||||
from pygost.kdf import kdf_gostr3411_2012_256
|
||||
from pygost.kdf import kdf_tree_gostr3411_2012_256
|
||||
from pygost.utils import hexdec
|
||||
|
||||
|
||||
class TestKDFGOSTR34112012256(TestCase):
|
||||
def runTest(self):
|
||||
self.assertEqual(
|
||||
kdf_gostr3411_2012_256(
|
||||
hexdec("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"),
|
||||
hexdec("26bdb878"),
|
||||
hexdec("af21434145656378"),
|
||||
),
|
||||
hexdec("a1aa5f7de402d7b3d323f2991c8d4534013137010a83754fd0af6d7cd4922ed9"),
|
||||
)
|
||||
|
||||
|
||||
class TestKDFTREEGOSTR34112012256(TestCase):
|
||||
def runTest(self):
|
||||
self.assertSequenceEqual(
|
||||
kdf_tree_gostr3411_2012_256(
|
||||
hexdec("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"),
|
||||
hexdec("26bdb878"),
|
||||
hexdec("af21434145656378"),
|
||||
1,
|
||||
),
|
||||
(hexdec("a1aa5f7de402d7b3d323f2991c8d4534013137010a83754fd0af6d7cd4922ed9"),),
|
||||
)
|
||||
self.assertSequenceEqual(
|
||||
kdf_tree_gostr3411_2012_256(
|
||||
hexdec("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"),
|
||||
hexdec("26bdb878"),
|
||||
hexdec("af21434145656378"),
|
||||
2,
|
||||
),
|
||||
(
|
||||
hexdec("22b6837845c6bef65ea71672b265831086d3c76aebe6dae91cad51d83f79d16b"),
|
||||
hexdec("074c9330599d7f8d712fca54392f4ddde93751206b3584c8f43f9e6dc51531f9"),
|
||||
),
|
||||
)
|
||||
@ -1,75 +0,0 @@
|
||||
# coding: utf-8
|
||||
# PyGOST -- Pure Python GOST cryptographic functions library
|
||||
# Copyright (C) 2015-2023 Sergey Matveev <stargrave@stargrave.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, version 3 of the License.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from os import urandom
|
||||
from random import randint
|
||||
from unittest import TestCase
|
||||
|
||||
from pygost.gost3412 import GOST3412Kuznechik
|
||||
from pygost.gost3412 import GOST3412Magma
|
||||
from pygost.gost3412 import KEYSIZE
|
||||
from pygost.mgm import MGM
|
||||
from pygost.mgm import nonce_prepare
|
||||
from pygost.utils import hexdec
|
||||
|
||||
|
||||
class TestVector(TestCase):
|
||||
def runTest(self):
|
||||
key = hexdec("8899AABBCCDDEEFF0011223344556677FEDCBA98765432100123456789ABCDEF")
|
||||
ad = hexdec("0202020202020202010101010101010104040404040404040303030303030303EA0505050505050505")
|
||||
plaintext = hexdec("1122334455667700FFEEDDCCBBAA998800112233445566778899AABBCCEEFF0A112233445566778899AABBCCEEFF0A002233445566778899AABBCCEEFF0A0011AABBCC")
|
||||
mgm = MGM(GOST3412Kuznechik(key).encrypt, GOST3412Kuznechik.blocksize)
|
||||
ciphertext = mgm.seal(plaintext[:16], plaintext, ad)
|
||||
self.assertSequenceEqual(ciphertext[:len(plaintext)], hexdec("A9757B8147956E9055B8A33DE89F42FC8075D2212BF9FD5BD3F7069AADC16B39497AB15915A6BA85936B5D0EA9F6851CC60C14D4D3F883D0AB94420695C76DEB2C7552"))
|
||||
self.assertSequenceEqual(ciphertext[len(plaintext):], hexdec("CF5D656F40C34F5C46E8BB0E29FCDB4C"))
|
||||
self.assertSequenceEqual(mgm.open(plaintext[:16], ciphertext, ad), plaintext)
|
||||
|
||||
|
||||
class TestSymmetric(TestCase):
|
||||
def _itself(self, mgm, bs, tag_size):
|
||||
for _ in range(1000):
|
||||
nonce = nonce_prepare(urandom(bs))
|
||||
ad = urandom(randint(0, 20))
|
||||
pt = urandom(randint(0, 20))
|
||||
if len(ad) + len(pt) == 0:
|
||||
continue
|
||||
ct = mgm.seal(nonce, pt, ad)
|
||||
self.assertEqual(len(ct) - tag_size, len(pt))
|
||||
self.assertSequenceEqual(mgm.open(nonce, ct, ad), pt)
|
||||
|
||||
def test_magma(self):
|
||||
for tag_size in (
|
||||
GOST3412Magma.blocksize,
|
||||
GOST3412Magma.blocksize - 2,
|
||||
):
|
||||
mgm = MGM(
|
||||
GOST3412Magma(urandom(KEYSIZE)).encrypt,
|
||||
GOST3412Magma.blocksize,
|
||||
tag_size,
|
||||
)
|
||||
self._itself(mgm, GOST3412Magma.blocksize, tag_size)
|
||||
|
||||
def test_kuznechik(self):
|
||||
for tag_size in (
|
||||
GOST3412Kuznechik.blocksize,
|
||||
GOST3412Kuznechik.blocksize - 2,
|
||||
):
|
||||
mgm = MGM(
|
||||
GOST3412Kuznechik(urandom(KEYSIZE)).encrypt,
|
||||
GOST3412Kuznechik.blocksize,
|
||||
tag_size,
|
||||
)
|
||||
self._itself(mgm, GOST3412Kuznechik.blocksize, tag_size)
|
||||
@ -1,680 +0,0 @@
|
||||
# coding: utf-8
|
||||
# PyGOST -- Pure Python GOST cryptographic functions library
|
||||
# Copyright (C) 2015-2023 Sergey Matveev <stargrave@stargrave.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, version 3 of the License.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from base64 import b64decode
|
||||
from hmac import new as hmac_new
|
||||
from unittest import skipIf
|
||||
from unittest import TestCase
|
||||
|
||||
from pygost import gost3410
|
||||
from pygost.gost28147 import cfb_decrypt
|
||||
from pygost.gost34112012256 import GOST34112012256
|
||||
from pygost.gost34112012512 import GOST34112012512
|
||||
from pygost.gost34112012512 import pbkdf2 as gost34112012_pbkdf2
|
||||
from pygost.gost3412 import GOST3412Kuznechik
|
||||
from pygost.gost3412 import GOST3412Magma
|
||||
from pygost.gost3412 import KEYSIZE
|
||||
from pygost.gost3413 import ctr_acpkm
|
||||
from pygost.gost3413 import mac as omac
|
||||
from pygost.kdf import kdf_tree_gostr3411_2012_256
|
||||
from pygost.kdf import keg
|
||||
from pygost.utils import hexdec
|
||||
from pygost.wrap import kimp15
|
||||
|
||||
|
||||
try:
|
||||
from pyderasn import OctetString
|
||||
|
||||
from pygost.asn1schemas.cms import EncryptedData
|
||||
from pygost.asn1schemas.cms import EnvelopedData
|
||||
from pygost.asn1schemas.cms import SignedAttributes
|
||||
from pygost.asn1schemas.cms import SignedData
|
||||
from pygost.asn1schemas.oids import id_data
|
||||
from pygost.asn1schemas.oids import id_envelopedData
|
||||
from pygost.asn1schemas.oids import id_gostr3412_2015_kuznyechik_ctracpkm
|
||||
from pygost.asn1schemas.oids import id_gostr3412_2015_kuznyechik_wrap_kexp15
|
||||
from pygost.asn1schemas.oids import id_messageDigest
|
||||
from pygost.asn1schemas.oids import id_pbes2
|
||||
from pygost.asn1schemas.oids import id_pkcs12_bagtypes_certBag
|
||||
from pygost.asn1schemas.oids import id_pkcs12_bagtypes_keyBag
|
||||
from pygost.asn1schemas.oids import id_pkcs12_bagtypes_pkcs8ShroudedKeyBag
|
||||
from pygost.asn1schemas.oids import id_pkcs9_certTypes_x509Certificate
|
||||
from pygost.asn1schemas.oids import id_signedData
|
||||
from pygost.asn1schemas.oids import id_tc26_agreement_gost3410_2012_256
|
||||
from pygost.asn1schemas.oids import id_tc26_gost3411_2012_256
|
||||
from pygost.asn1schemas.pfx import CertBag
|
||||
from pygost.asn1schemas.pfx import KeyBag
|
||||
from pygost.asn1schemas.pfx import OctetStringSafeContents
|
||||
from pygost.asn1schemas.pfx import PBES2Params
|
||||
from pygost.asn1schemas.pfx import PFX
|
||||
from pygost.asn1schemas.pfx import PKCS8ShroudedKeyBag
|
||||
from pygost.asn1schemas.pfx import SafeContents
|
||||
from pygost.asn1schemas.x509 import Certificate
|
||||
except ImportError:
|
||||
pyderasn_exists = False
|
||||
else:
|
||||
pyderasn_exists = True
|
||||
|
||||
|
||||
@skipIf(not pyderasn_exists, "PyDERASN dependency is required")
|
||||
class TestPFX(TestCase):
|
||||
"""PFX test vectors from "Транспортный ключевой контейнер" (R50.1.112-2016.pdf)
|
||||
"""
|
||||
pfx_raw = b64decode("""
|
||||
MIIFqgIBAzCCBSsGCSqGSIb3DQEHAaCCBRwEggUYMIIFFDCCASIGCSqGSIb3DQEH
|
||||
AaCCARMEggEPMIIBCzCCAQcGCyqGSIb3DQEMCgECoIHgMIHdMHEGCSqGSIb3DQEF
|
||||
DTBkMEEGCSqGSIb3DQEFDDA0BCD5qZr0TTIsBvdgUoq/zFwOzdyJohj6/4Wiyccg
|
||||
j9AK/QICB9AwDAYIKoUDBwEBBAIFADAfBgYqhQMCAhUwFQQI3Ip/Vp0IsyIGCSqF
|
||||
AwcBAgUBAQRoSfLhgx9s/zn+BjnhT0ror07vS55Ys5hgvVpWDx4mXGWWyez/2sMc
|
||||
aFgSr4H4UTGGwoMynGLpF1IOVo+bGJ0ePqHB+gS5OL9oV+PUmZ/ELrRENKlCDqfY
|
||||
WvpSystX29CvCFrnTnDsbBYxFTATBgkqhkiG9w0BCRUxBgQEAQAAADCCA+oGCSqG
|
||||
SIb3DQEHBqCCA9swggPXAgEAMIID0AYJKoZIhvcNAQcBMHEGCSqGSIb3DQEFDTBk
|
||||
MEEGCSqGSIb3DQEFDDA0BCCJTJLZQRi1WIpQHzyjXbq7+Vw2+1280C45x8ff6kMS
|
||||
VAICB9AwDAYIKoUDBwEBBAIFADAfBgYqhQMCAhUwFQQIxepowwvS11MGCSqFAwcB
|
||||
AgUBAYCCA06n09P/o+eDEKoSWpvlpOLKs7dKmVquKzJ81nCngvLQ5fEWL1WkxwiI
|
||||
rEhm53JKLD0wy4hekalEk011Bvc51XP9gkDkmaoBpnV/TyKIY35wl6ATfeGXno1M
|
||||
KoA+Ktdhv4gLnz0k2SXdkUj11JwYskXue+REA0p4m2ZsoaTmvoODamh9JeY/5Qjy
|
||||
Xe58CGnyXFzX3eU86qs4WfdWdS3NzYYOk9zzVl46le9u79O/LnW2j4n2of/Jpk/L
|
||||
YjrRmz5oYeQOqKOKhEyhpO6e+ejr6laduEv7TwJQKRNiygogbVvkNn3VjHTSOUG4
|
||||
W+3NRPhjb0jD9obdyx6MWa6O3B9bUzFMNav8/gYn0vTDxqXMLy/92oTngNrVx6Gc
|
||||
cNl128ISrDS6+RxtAMiEBRK6xNkemqX5yNXG5GrLQQFGP6mbs2nNpjKlgj3pljmX
|
||||
Eky2/G78XiJrv02OgGs6CKnI9nMpa6N7PBHV34MJ6EZzWOWDRQ420xk63mnicrs0
|
||||
WDVJ0xjdu4FW3iEk02EaiRTvGBpa6GL7LBp6QlaXSSwONx725cyRsL9cTlukqXER
|
||||
WHDlMpjYLbkGZRrCc1myWgEfsputfSIPNF/oLv9kJNWacP3uuDOfecg3us7eg2OA
|
||||
xo5zrYfn39GcBMF1WHAYRO/+PnJb9jrDuLAE8+ONNqjNulWNK9CStEhb6Te+yE6q
|
||||
oeP6hJjFLi+nFLE9ymIo0A7gLQD5vzFvl+7v1ZNVnQkwRUsWoRiEVVGnv3Z1iZU6
|
||||
xStxgoHMl62V/P5cz4dr9vJM2adEWNZcVXl6mk1H8DRc1sRGnvs2l237oKWRVntJ
|
||||
hoWnZ8qtD+3ZUqsX79QhVzUQBzKuBt6jwNhaHLGl5B+Or/zA9FezsOh6+Uc+fZaV
|
||||
W7fFfeUyWwGy90XD3ybTrjzep9f3nt55Z2c+fu2iEwhoyImWLuC3+CVhf9Af59j9
|
||||
8/BophMJuATDJEtgi8rt4vLnfxKu250Mv2ZpbfF69EGTgFYbwc55zRfaUG9zlyCu
|
||||
1YwMJ6HC9FUVtJp9gObSrirbzTH7mVaMjQkBLotazWbegzI+be8V3yT06C+ehD+2
|
||||
GdLWAVs9hp8gPHEUShb/XrgPpDSJmFlOiyeOFBO/j4edDACKqVcwdjBOMAoGCCqF
|
||||
AwcBAQIDBEAIFX0fyZe20QKKhWm6WYX+S92Gt6zaXroXOvAmayzLfZ5Sd9C2t9zZ
|
||||
JSg6M8RBUYpw/8ym5ou1o2nDa09M5zF3BCCpzyCQBI+rzfISeKvPV1ROfcXiYU93
|
||||
mwcl1xQV2G5/fgICB9A=
|
||||
""")
|
||||
password = u"Пароль для PFX"
|
||||
|
||||
def test_shrouded_key_bag(self):
|
||||
private_key_info_expected = b64decode(b"""
|
||||
MGYCAQAwHwYIKoUDBwEBAQEwEwYHKoUDAgIjAQYIKoUDBwEBAgIEQEYbRu86z+1JFKDcPDN9UbTG
|
||||
G2ki9enTqos4KpUU0j9IDpl1UXiaA1YDIwUjlAp+81GkLmyt8Fw6Gt/X5JZySAY=
|
||||
""")
|
||||
|
||||
pfx, tail = PFX().decode(self.pfx_raw)
|
||||
self.assertSequenceEqual(tail, b"")
|
||||
_, outer_safe_contents = pfx["authSafe"]["content"].defined
|
||||
safe_contents, tail = OctetStringSafeContents().decode(
|
||||
bytes(outer_safe_contents[0]["bagValue"]),
|
||||
)
|
||||
self.assertSequenceEqual(tail, b"")
|
||||
safe_bag = safe_contents[0]
|
||||
shrouded_key_bag, tail = PKCS8ShroudedKeyBag().decode(
|
||||
bytes(safe_bag["bagValue"]),
|
||||
)
|
||||
self.assertSequenceEqual(tail, b"")
|
||||
_, pbes2_params = shrouded_key_bag["encryptionAlgorithm"]["parameters"].defined
|
||||
_, pbkdf2_params = pbes2_params["keyDerivationFunc"]["parameters"].defined
|
||||
_, enc_scheme_params = pbes2_params["encryptionScheme"]["parameters"].defined
|
||||
|
||||
key = gost34112012_pbkdf2(
|
||||
password=self.password.encode("utf-8"),
|
||||
salt=bytes(pbkdf2_params["salt"]["specified"]),
|
||||
iterations=int(pbkdf2_params["iterationCount"]),
|
||||
dklen=32,
|
||||
)
|
||||
# key = hexdec("309dd0354c5603739403f2335e9e2055138f8b5c98b63009de0635eea1fd7ba8")
|
||||
self.assertSequenceEqual(
|
||||
cfb_decrypt(
|
||||
key,
|
||||
bytes(shrouded_key_bag["encryptedData"]),
|
||||
iv=bytes(enc_scheme_params["iv"]),
|
||||
sbox="id-tc26-gost-28147-param-Z",
|
||||
),
|
||||
private_key_info_expected,
|
||||
)
|
||||
|
||||
def test_encrypted_data(self):
|
||||
cert_bag_expected = b64decode(b"""
|
||||
MIIDSjCCA0YGCyqGSIb3DQEMCgEDoIIDHjCCAxoGCiqGSIb3DQEJFgGgggMKBIIDBjCCAwIwggKt
|
||||
oAMCAQICEAHQaF8xH5bAAAAACycJAAEwDAYIKoUDBwEBAwIFADBgMQswCQYDVQQGEwJSVTEVMBMG
|
||||
A1UEBwwM0JzQvtGB0LrQstCwMQ8wDQYDVQQKDAbQotCaMjYxKTAnBgNVBAMMIENBIGNlcnRpZmlj
|
||||
YXRlIChQS0NTIzEyIGV4YW1wbGUpMB4XDTE1MDMyNzA3MjUwMFoXDTIwMDMyNzA3MjMwMFowZDEL
|
||||
MAkGA1UEBhMCUlUxFTATBgNVBAcMDNCc0L7RgdC60LLQsDEPMA0GA1UECgwG0KLQmjI2MS0wKwYD
|
||||
VQQDDCRUZXN0IGNlcnRpZmljYXRlIDEgKFBLQ1MjMTIgZXhhbXBsZSkwZjAfBggqhQMHAQEBATAT
|
||||
BgcqhQMCAiMBBggqhQMHAQECAgNDAARA1xzymkpvr2dYJT8WTOX3Dt96/+hGsXNytUQpkWB5ImJM
|
||||
4tg9AsC4RIUwV5H41MhG0uBRFweTzN6AsAdBvhTClYEJADI3MDkwMDAxo4IBKTCCASUwKwYDVR0Q
|
||||
BCQwIoAPMjAxNTAzMjcwNzI1MDBagQ8yMDE2MDMyNzA3MjUwMFowDgYDVR0PAQH/BAQDAgTwMB0G
|
||||
A1UdDgQWBBQhWOsRQ68yYN2Utg/owHoWcqsVbTAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUH
|
||||
AwQwDAYDVR0TAQH/BAIwADCBmQYDVR0jBIGRMIGOgBQmnc7Xh5ykb5t/BMwOkxA4drfEmqFkpGIw
|
||||
YDELMAkGA1UEBhMCUlUxFTATBgNVBAcMDNCc0L7RgdC60LLQsDEPMA0GA1UECgwG0KLQmjI2MSkw
|
||||
JwYDVQQDDCBDQSBjZXJ0aWZpY2F0ZSAoUEtDUyMxMiBleGFtcGxlKYIQAdBoXvL8TSAAAAALJwkA
|
||||
ATAMBggqhQMHAQEDAgUAA0EA9oq0Vvk8kkgIwkp0x0J5eKtia4MNTiwKAm7jgnCZIx3O98BThaTX
|
||||
3ZQhEo2RL9pTCPr6wFMheeJ+YdGMReXvsjEVMBMGCSqGSIb3DQEJFTEGBAQBAAAA
|
||||
""")
|
||||
|
||||
pfx, tail = PFX().decode(self.pfx_raw)
|
||||
self.assertSequenceEqual(tail, b"")
|
||||
_, outer_safe_contents = pfx["authSafe"]["content"].defined
|
||||
_, encrypted_data = outer_safe_contents[1]["bagValue"].defined
|
||||
_, pbes2_params = encrypted_data["encryptedContentInfo"]["contentEncryptionAlgorithm"]["parameters"].defined
|
||||
_, pbkdf2_params = pbes2_params["keyDerivationFunc"]["parameters"].defined
|
||||
_, enc_scheme_params = pbes2_params["encryptionScheme"]["parameters"].defined
|
||||
key = gost34112012_pbkdf2(
|
||||
password=self.password.encode("utf-8"),
|
||||
salt=bytes(pbkdf2_params["salt"]["specified"]),
|
||||
iterations=int(pbkdf2_params["iterationCount"]),
|
||||
dklen=32,
|
||||
)
|
||||
# key = hexdec("0e93d71339e7f53b79a0bc41f9109dd4fb60b30ae10736c1bb77b84c07681cfc")
|
||||
self.assertSequenceEqual(
|
||||
cfb_decrypt(
|
||||
key,
|
||||
bytes(encrypted_data["encryptedContentInfo"]["encryptedContent"]),
|
||||
iv=bytes(enc_scheme_params["iv"]),
|
||||
sbox="id-tc26-gost-28147-param-Z",
|
||||
),
|
||||
cert_bag_expected,
|
||||
)
|
||||
|
||||
def test_mac(self):
|
||||
pfx, tail = PFX().decode(self.pfx_raw)
|
||||
self.assertSequenceEqual(tail, b"")
|
||||
_, outer_safe_contents = pfx["authSafe"]["content"].defined
|
||||
mac_data = pfx["macData"]
|
||||
mac_key = gost34112012_pbkdf2(
|
||||
password=self.password.encode("utf-8"),
|
||||
salt=bytes(mac_data["macSalt"]),
|
||||
iterations=int(mac_data["iterations"]),
|
||||
dklen=96,
|
||||
)[-32:]
|
||||
# mac_key = hexdec("cadbfbf3bceaa9b79f651508fac5abbeb4a13d0bd0e1876bd3c3efb2112128a5")
|
||||
self.assertSequenceEqual(
|
||||
hmac_new(
|
||||
key=mac_key,
|
||||
msg=SafeContents(outer_safe_contents).encode(),
|
||||
digestmod=GOST34112012512,
|
||||
).digest(),
|
||||
bytes(mac_data["mac"]["digest"]),
|
||||
)
|
||||
|
||||
|
||||
@skipIf(not pyderasn_exists, "PyDERASN dependency is required")
|
||||
class TestPFX2020(TestCase):
|
||||
"""PFX test vectors from newer PKCS#12 update
|
||||
"""
|
||||
ca_prv_raw = hexdec("092F8D059E97E22B90B1AE99F0087FC4D26620B91550CBB437C191005A290810")
|
||||
ca_curve = gost3410.CURVES["id-tc26-gost-3410-12-256-paramSetA"]
|
||||
ca_cert = Certificate().decod(b64decode(b"""
|
||||
MIIB+TCCAaagAwIBAgIEAYy6gTAKBggqhQMHAQEDAjA4MQ0wCwYDVQQKEwRUSzI2MS
|
||||
cwJQYDVQQDEx5DQSBUSzI2OiBHT1NUIDM0LjEwLTEyIDI1Ni1iaXQwHhcNMDEwMTAx
|
||||
MDAwMDAwWhcNNDkxMjMxMDAwMDAwWjA4MQ0wCwYDVQQKEwRUSzI2MScwJQYDVQQDEx
|
||||
5DQSBUSzI2OiBHT1NUIDM0LjEwLTEyIDI1Ni1iaXQwXjAXBggqhQMHAQEBATALBgkq
|
||||
hQMHAQIBAQEDQwAEQBpKgpyPDnhQAJyLqy8Qs0XQhgxEhby6tSypqYimgbjpcKqtU6
|
||||
4jpDXc3h3BxGxtl2oHJ/4YLZ/ll87dto3ltMqjgZgwgZUwYwYDVR0jBFwwWoAUrGwO
|
||||
TERmokKW4p8JOyVm88ukUyqhPKQ6MDgxDTALBgNVBAoTBFRLMjYxJzAlBgNVBAMTHk
|
||||
NBIFRLMjY6IEdPU1QgMzQuMTAtMTIgMjU2LWJpdIIEAYy6gTAdBgNVHQ4EFgQUrGwO
|
||||
TERmokKW4p8JOyVm88ukUyowDwYDVR0TAQH/BAUwAwEB/zAKBggqhQMHAQEDAgNBAB
|
||||
Gg3nhgQ5oCKbqlEdVaRxH+1WX4wVkawGXuTYkr1AC2OWw3ZC14Vvg3nazm8UMWUZtk
|
||||
vu1kJcHQ4jFKkjUeg2E=
|
||||
"""))
|
||||
ca_pub = gost3410.pub_unmarshal(bytes(OctetString().decod(bytes(
|
||||
ca_cert["tbsCertificate"]["subjectPublicKeyInfo"]["subjectPublicKey"]
|
||||
))))
|
||||
password = u"Пароль для PFX".encode("utf-8")
|
||||
cert_test = Certificate().decod(b64decode(b"""
|
||||
MIICLjCCAdugAwIBAgIEAYy6hDAKBggqhQMHAQEDAjA4MQ0wCwYDVQQKEwRUSzI2MS
|
||||
cwJQYDVQQDEx5DQSBUSzI2OiBHT1NUIDM0LjEwLTEyIDI1Ni1iaXQwHhcNMDEwMTAx
|
||||
MDAwMDAwWhcNNDkxMjMxMDAwMDAwWjA7MQ0wCwYDVQQKEwRUSzI2MSowKAYDVQQDEy
|
||||
FPUklHSU5BVE9SOiBHT1NUIDM0LjEwLTEyIDUxMi1iaXQwgaAwFwYIKoUDBwEBAQIw
|
||||
CwYJKoUDBwECAQIBA4GEAASBgLSLt1q8KQ4YZVxioU+1LV9QhE7MHR9gBEh7S1yVNG
|
||||
lqt7+rNG5VFqmrPM74rbUsOlhV8M+zZKprXdk35Oz8lSW/n2oIUHZxikXIH/SSHj4r
|
||||
v3K/Puvz7hYTQSZl/xPdp78nUmjrEa6d5wfX8biEy2z0dgufFvAkMw1Ua4gdXqDOo4
|
||||
GHMIGEMGMGA1UdIwRcMFqAFKxsDkxEZqJCluKfCTslZvPLpFMqoTykOjA4MQ0wCwYD
|
||||
VQQKEwRUSzI2MScwJQYDVQQDEx5DQSBUSzI2OiBHT1NUIDM0LjEwLTEyIDI1Ni1iaX
|
||||
SCBAGMuoEwHQYDVR0OBBYEFH4GVwmYDK1rCKhX7nkAWDrJ16CkMAoGCCqFAwcBAQMC
|
||||
A0EACl6p8dAbpi9Hk+3mgMyI0WIh17IrlrSp/mB0F7ZzMt8XUD1Dwz3JrrnxeXnfMv
|
||||
OA5BdUJ9hCyDgMVAGs/IcEEA==
|
||||
"""))
|
||||
prv_test_raw = b64decode("""
|
||||
MIHiAgEBMBcGCCqFAwcBAQECMAsGCSqFAwcBAgECAQRAEWkl+eblsHWs86SNgRKq
|
||||
SxMOgGhbvR/uZ5/WWfdNG1axvUwVhpcXIxDZUmzQuNzqJBkseI7f5/JjXyTFRF1a
|
||||
+YGBgQG0i7davCkOGGVcYqFPtS1fUIROzB0fYARIe0tclTRpare/qzRuVRapqzzO
|
||||
+K21LDpYVfDPs2Sqa13ZN+Ts/JUlv59qCFB2cYpFyB/0kh4+K79yvz7r8+4WE0Em
|
||||
Zf8T3ae/J1Jo6xGunecH1/G4hMts9HYLnxbwJDMNVGuIHV6gzg==
|
||||
""")
|
||||
|
||||
def test_cert_and_encrypted_key(self):
|
||||
pfx_raw = b64decode(b"""
|
||||
MIIFKwIBAzCCBMQGCSqGSIb3DQEHAaCCBLUEggSxMIIErTCCAswGCSqGSIb3DQEH
|
||||
AaCCAr0EggK5MIICtTCCArEGCyqGSIb3DQEMCgEDoIICSjCCAkYGCiqGSIb3DQEJ
|
||||
FgGgggI2BIICMjCCAi4wggHboAMCAQICBAGMuoQwCgYIKoUDBwEBAwIwODENMAsG
|
||||
A1UEChMEVEsyNjEnMCUGA1UEAxMeQ0EgVEsyNjogR09TVCAzNC4xMC0xMiAyNTYt
|
||||
Yml0MB4XDTAxMDEwMTAwMDAwMFoXDTQ5MTIzMTAwMDAwMFowOzENMAsGA1UEChME
|
||||
VEsyNjEqMCgGA1UEAxMhT1JJR0lOQVRPUjogR09TVCAzNC4xMC0xMiA1MTItYml0
|
||||
MIGgMBcGCCqFAwcBAQECMAsGCSqFAwcBAgECAQOBhAAEgYC0i7davCkOGGVcYqFP
|
||||
tS1fUIROzB0fYARIe0tclTRpare/qzRuVRapqzzO+K21LDpYVfDPs2Sqa13ZN+Ts
|
||||
/JUlv59qCFB2cYpFyB/0kh4+K79yvz7r8+4WE0EmZf8T3ae/J1Jo6xGunecH1/G4
|
||||
hMts9HYLnxbwJDMNVGuIHV6gzqOBhzCBhDBjBgNVHSMEXDBagBSsbA5MRGaiQpbi
|
||||
nwk7JWbzy6RTKqE8pDowODENMAsGA1UEChMEVEsyNjEnMCUGA1UEAxMeQ0EgVEsy
|
||||
NjogR09TVCAzNC4xMC0xMiAyNTYtYml0ggQBjLqBMB0GA1UdDgQWBBR+BlcJmAyt
|
||||
awioV+55AFg6ydegpDAKBggqhQMHAQEDAgNBAApeqfHQG6YvR5Pt5oDMiNFiIdey
|
||||
K5a0qf5gdBe2czLfF1A9Q8M9ya658Xl53zLzgOQXVCfYQsg4DFQBrPyHBBAxVDAj
|
||||
BgkqhkiG9w0BCRUxFgQUeVV0+dS25MICJChpmGc/8AoUwE0wLQYJKoZIhvcNAQkU
|
||||
MSAeHgBwADEAMgBGAHIAaQBlAG4AZABsAHkATgBhAG0AZTCCAdkGCSqGSIb3DQEH
|
||||
AaCCAcoEggHGMIIBwjCCAb4GCyqGSIb3DQEMCgECoIIBVzCCAVMwWQYJKoZIhvcN
|
||||
AQUNMEwwKQYJKoZIhvcNAQUMMBwECKf4N7NMwugqAgIIADAMBggqhQMHAQEEAgUA
|
||||
MB8GCSqFAwcBAQUCAjASBBAlmt2WDfaPJlsAs0mLKglzBIH1DMvEacbbWRNDVSnX
|
||||
JLWygYrKoipdOjDA/2HEnBZ34uFOLNheUqiKpCPoFpbR2GBiVYVTVK9ibiczgaca
|
||||
EQYzDXtcS0QCZOxpKWfteAlbdJLC/SqPurPYyKi0MVRUPROhbisFASDT38HDH1Dh
|
||||
0dL5f6ga4aPWLrWbbgWERFOoOPyh4DotlPF37AQOwiEjsbyyRHq3HgbWiaxQRuAh
|
||||
eqHOn4QVGY92/HFvJ7u3TcnQdLWhTe/lh1RHLNF3RnXtN9if9zC23laDZOiWZplU
|
||||
yLrUiTCbHrtn1RppPDmLFNMt9dJ7KKgCkOi7Zm5nhqPChbywX13wcfYxVDAjBgkq
|
||||
hkiG9w0BCRUxFgQUeVV0+dS25MICJChpmGc/8AoUwE0wLQYJKoZIhvcNAQkUMSAe
|
||||
HgBwADEAMgBGAHIAaQBlAG4AZABsAHkATgBhAG0AZTBeME4wCgYIKoUDBwEBAgME
|
||||
QAkBKw4ihn7pSIYTEhu0bcvTPZjI3WgVxCkUVlOsc80G69EKFEOTnObGJGSKJ51U
|
||||
KkOsXF0a7+VBZf3BcVVQh9UECIVEtO+VpuskAgIIAA==
|
||||
""")
|
||||
pfx = PFX().decod(pfx_raw)
|
||||
_, outer_safe_contents = pfx["authSafe"]["content"].defined
|
||||
|
||||
safe_contents = OctetStringSafeContents().decod(bytes(
|
||||
outer_safe_contents[0]["bagValue"]
|
||||
))
|
||||
safe_bag = safe_contents[0]
|
||||
self.assertEqual(safe_bag["bagId"], id_pkcs12_bagtypes_certBag)
|
||||
cert_bag = CertBag().decod(bytes(safe_bag["bagValue"]))
|
||||
self.assertEqual(cert_bag["certId"], id_pkcs9_certTypes_x509Certificate)
|
||||
_, cert = cert_bag["certValue"].defined
|
||||
self.assertEqual(Certificate(cert), self.cert_test)
|
||||
|
||||
safe_contents = OctetStringSafeContents().decod(bytes(
|
||||
outer_safe_contents[1]["bagValue"]
|
||||
))
|
||||
safe_bag = safe_contents[0]
|
||||
self.assertEqual(safe_bag["bagId"], id_pkcs12_bagtypes_pkcs8ShroudedKeyBag)
|
||||
shrouded_key_bag = PKCS8ShroudedKeyBag().decod(bytes(safe_bag["bagValue"]))
|
||||
_, pbes2_params = shrouded_key_bag["encryptionAlgorithm"]["parameters"].defined
|
||||
_, pbkdf2_params = pbes2_params["keyDerivationFunc"]["parameters"].defined
|
||||
_, enc_scheme_params = pbes2_params["encryptionScheme"]["parameters"].defined
|
||||
ukm = bytes(enc_scheme_params["ukm"])
|
||||
key = gost34112012_pbkdf2(
|
||||
password=self.password,
|
||||
salt=bytes(pbkdf2_params["salt"]["specified"]),
|
||||
iterations=int(pbkdf2_params["iterationCount"]),
|
||||
dklen=32,
|
||||
)
|
||||
# key = hexdec("4b7ae649ca31dd5fe3243a91a5188c03f1d7049bec8e0d241c0e1e8c39ea4c1f")
|
||||
key_enc, key_mac = kdf_tree_gostr3411_2012_256(
|
||||
key, b"kdf tree", ukm[GOST3412Kuznechik.blocksize // 2:], 2,
|
||||
)
|
||||
ciphertext = bytes(shrouded_key_bag["encryptedData"])
|
||||
plaintext = ctr_acpkm(
|
||||
GOST3412Kuznechik,
|
||||
GOST3412Kuznechik(key_enc).encrypt,
|
||||
section_size=256 * 1024,
|
||||
bs=GOST3412Kuznechik.blocksize,
|
||||
data=ciphertext,
|
||||
iv=ukm[:GOST3412Kuznechik.blocksize // 2],
|
||||
)
|
||||
mac_expected = plaintext[-GOST3412Kuznechik.blocksize:]
|
||||
plaintext = plaintext[:-GOST3412Kuznechik.blocksize]
|
||||
mac = omac(
|
||||
GOST3412Kuznechik(key_mac).encrypt,
|
||||
GOST3412Kuznechik.blocksize,
|
||||
plaintext,
|
||||
)
|
||||
self.assertSequenceEqual(mac, mac_expected)
|
||||
self.assertSequenceEqual(plaintext, self.prv_test_raw)
|
||||
|
||||
mac_data = pfx["macData"]
|
||||
mac_key = gost34112012_pbkdf2(
|
||||
password=self.password,
|
||||
salt=bytes(mac_data["macSalt"]),
|
||||
iterations=int(mac_data["iterations"]),
|
||||
dklen=96,
|
||||
)[-32:]
|
||||
# mac_key = hexdec("a81d1bc91a4a5cf1fd7320f92dda7e5b285816c3b20826a382d7ed0cbf3a9bf4")
|
||||
self.assertSequenceEqual(
|
||||
hmac_new(
|
||||
key=mac_key,
|
||||
msg=SafeContents(outer_safe_contents).encode(),
|
||||
digestmod=GOST34112012512,
|
||||
).digest(),
|
||||
bytes(mac_data["mac"]["digest"]),
|
||||
)
|
||||
self.assertTrue(gost3410.verify(
|
||||
self.ca_curve,
|
||||
self.ca_pub,
|
||||
GOST34112012256(cert["tbsCertificate"].encode()).digest()[::-1],
|
||||
bytes(cert["signatureValue"]),
|
||||
))
|
||||
|
||||
def test_encrypted_cert_and_key(self):
|
||||
pfx_raw = b64decode(b"""
|
||||
MIIFjAIBAzCCBSUGCSqGSIb3DQEHAaCCBRYEggUSMIIFDjCCA0EGCSqGSIb3DQEH
|
||||
BqCCAzIwggMuAgEAMIIDJwYJKoZIhvcNAQcBMFUGCSqGSIb3DQEFDTBIMCkGCSqG
|
||||
SIb3DQEFDDAcBAgUuSVGsSwGjQICCAAwDAYIKoUDBwEBBAIFADAbBgkqhQMHAQEF
|
||||
AQIwDgQM9Hk3dagtS48+G/x+gIICwWGPqxxN+sTrKbruRf9R5Ya9cf5AtO1frqMn
|
||||
f1eULfmZmTg/BdE51QQ+Vbnh3v1kmspr6h2+e4Wli+ndEeCWG6A6X/G22h/RAHW2
|
||||
YrVmf6cCWxW+YrqzT4h/8RQL/9haunD5LmHPLVsYrEai0OwbgXayDSwARVJQLQYq
|
||||
sLNmZK5ViN+fRiS5wszVJ3AtVq8EuPt41aQEKwPy2gmH4S6WmnQRC6W7aoqmIifF
|
||||
PJENJNn5K2M1J6zNESs6bFtYNKMArNqtvv3rioY6eAaaLy6AV6ljsekmqodHmQjv
|
||||
Y4eEioJs0xhpXhZY69PXT+ZBeHv6MSheBhwXqxAd1DqtPTafMjNK8rqKCap9TtPG
|
||||
vONvo5W9dgwegxRRQzlum8dzV4m1W9Aq4W7t8/UcxDWRz3k6ijFPlGaA9+8ZMTEO
|
||||
RHhBRvM6OY2/VNNxbgxWfGYuPxpSi3YnCZIPmBEe5lU/Xv7KjzFusGM38F8YR61k
|
||||
4/QNpKI1QUv714YKfaUQznshGGzILv1NGID62pl1+JI3vuawi2mDMrmkuM9QFU9v
|
||||
/kRP+c2uBHDuOGEUUSNhF08p7+w3vxplatGWXH9fmIsPBdk2f3wkn+rwoqrEuijM
|
||||
I/bCAylU/M0DMKhAo9j31UYSZdi4fsfRWYDJMq/8FPn96tuo+oCpbqv3NUwpZM/8
|
||||
Li4xqgTHtYw/+fRG0/P6XadNEiII/TYjenLfVHXjAHOVJsVeCu/t3EsMYHQddNCh
|
||||
rFk/Ic2PdIQOyB4/enpW0qrKegSbyZNuF1WI4zl4mI89L8dTQBUkhy45yQXZlDD8
|
||||
k1ErYdtdEsPtz/4zuSpbnmwCEIRoOuSXtGuJP+tbcWEXRKM2UBgi3qBjpn7DU18M
|
||||
tsrRM9pDdadl8mT/Vfh9+B8dZBZVxgQu70lMPEGexbUkYHuFCCnyi9J0V92StbIz
|
||||
Elxla1VebjCCAcUGCSqGSIb3DQEHAaCCAbYEggGyMIIBrjCCAaoGCyqGSIb3DQEM
|
||||
CgECoIIBQzCCAT8wVQYJKoZIhvcNAQUNMEgwKQYJKoZIhvcNAQUMMBwECP0EQk0O
|
||||
1twvAgIIADAMBggqhQMHAQEEAgUAMBsGCSqFAwcBAQUBATAOBAzwxSqgAAAAAAAA
|
||||
AAAEgeUqj9mI3RDfK5hMd0EeYws7foZK/5ANr2wUhP5qnDjAZgn76lExJ+wuvlnS
|
||||
9PChfWVugvdl/9XJgQvvr9Cu4pOh4ICXplchcy0dGk/MzItHRVC5wK2nTxwQ4kKT
|
||||
kG9xhLFzoD16dhtqX0+/dQg9G8pE5EzCBIYRXLm1Arcz9k7KVsTJuNMjFrr7EQuu
|
||||
Tr80ATSQOtsq50zpFyrpznVPGCrOdIjpymZxNdvw48bZxqTtRVDxCYATOGqz0pwH
|
||||
ClWULHD9LIajLMB2GhBKyQw6ujIlltJs0T+WNdX/AT2FLi1LFSS3+Cj9MVQwIwYJ
|
||||
KoZIhvcNAQkVMRYEFHlVdPnUtuTCAiQoaZhnP/AKFMBNMC0GCSqGSIb3DQEJFDEg
|
||||
Hh4AcAAxADIARgByAGkAZQBuAGQAbAB5AE4AYQBtAGUwXjBOMAoGCCqFAwcBAQID
|
||||
BEDp4e22JmXdnvR0xA99yQuzQuJ8pxBeOpsLm2dZQqt3Fje5zqW1uk/7VOcfV5r2
|
||||
bKm8nsLOs2rPT8hBOoeAZvOIBAjGIUHw6IjG2QICCAA=
|
||||
""")
|
||||
pfx = PFX().decod(pfx_raw)
|
||||
_, outer_safe_contents = pfx["authSafe"]["content"].defined
|
||||
|
||||
encrypted_data = EncryptedData().decod(bytes(
|
||||
outer_safe_contents[0]["bagValue"]
|
||||
))
|
||||
eci = encrypted_data["encryptedContentInfo"]
|
||||
self.assertEqual(eci["contentEncryptionAlgorithm"]["algorithm"], id_pbes2)
|
||||
pbes2_params = PBES2Params().decod(bytes(
|
||||
eci["contentEncryptionAlgorithm"]["parameters"]
|
||||
))
|
||||
_, pbkdf2_params = pbes2_params["keyDerivationFunc"]["parameters"].defined
|
||||
_, enc_scheme_params = pbes2_params["encryptionScheme"]["parameters"].defined
|
||||
ukm = bytes(enc_scheme_params["ukm"])
|
||||
key = gost34112012_pbkdf2(
|
||||
password=self.password,
|
||||
salt=bytes(pbkdf2_params["salt"]["specified"]),
|
||||
iterations=int(pbkdf2_params["iterationCount"]),
|
||||
dklen=32,
|
||||
)
|
||||
# key = hexdec("d066a96fb326ba896a2352d3f40240a4ded6e7e7bd5b4db6b5241d631c8c381c")
|
||||
key_enc, key_mac = kdf_tree_gostr3411_2012_256(
|
||||
key, b"kdf tree", ukm[GOST3412Magma.blocksize // 2:], 2,
|
||||
)
|
||||
ciphertext = bytes(eci["encryptedContent"])
|
||||
plaintext = ctr_acpkm(
|
||||
GOST3412Magma,
|
||||
GOST3412Magma(key_enc).encrypt,
|
||||
section_size=8 * 1024,
|
||||
bs=GOST3412Magma.blocksize,
|
||||
data=ciphertext,
|
||||
iv=ukm[:GOST3412Magma.blocksize // 2],
|
||||
)
|
||||
mac_expected = plaintext[-GOST3412Magma.blocksize:]
|
||||
plaintext = plaintext[:-GOST3412Magma.blocksize]
|
||||
mac = omac(
|
||||
GOST3412Magma(key_mac).encrypt,
|
||||
GOST3412Magma.blocksize,
|
||||
plaintext,
|
||||
)
|
||||
self.assertSequenceEqual(mac, mac_expected)
|
||||
|
||||
safe_contents = SafeContents().decod(plaintext)
|
||||
safe_bag = safe_contents[0]
|
||||
self.assertEqual(safe_bag["bagId"], id_pkcs12_bagtypes_certBag)
|
||||
cert_bag = CertBag().decod(bytes(safe_bag["bagValue"]))
|
||||
self.assertEqual(cert_bag["certId"], id_pkcs9_certTypes_x509Certificate)
|
||||
_, cert = cert_bag["certValue"].defined
|
||||
self.assertEqual(Certificate(cert), self.cert_test)
|
||||
|
||||
safe_contents = OctetStringSafeContents().decod(bytes(
|
||||
outer_safe_contents[1]["bagValue"]
|
||||
))
|
||||
safe_bag = safe_contents[0]
|
||||
self.assertEqual(safe_bag["bagId"], id_pkcs12_bagtypes_pkcs8ShroudedKeyBag)
|
||||
shrouded_key_bag = PKCS8ShroudedKeyBag().decod(bytes(safe_bag["bagValue"]))
|
||||
_, pbes2_params = shrouded_key_bag["encryptionAlgorithm"]["parameters"].defined
|
||||
_, pbkdf2_params = pbes2_params["keyDerivationFunc"]["parameters"].defined
|
||||
_, enc_scheme_params = pbes2_params["encryptionScheme"]["parameters"].defined
|
||||
ukm = bytes(enc_scheme_params["ukm"])
|
||||
key = gost34112012_pbkdf2(
|
||||
password=self.password,
|
||||
salt=bytes(pbkdf2_params["salt"]["specified"]),
|
||||
iterations=int(pbkdf2_params["iterationCount"]),
|
||||
dklen=32,
|
||||
)
|
||||
# key = hexdec("f840d001fd11441e0fb7ccf48f471915e5bf35275309dbe7ade9da4fe460ba7e")
|
||||
ciphertext = bytes(shrouded_key_bag["encryptedData"])
|
||||
plaintext = ctr_acpkm(
|
||||
GOST3412Magma,
|
||||
GOST3412Magma(key).encrypt,
|
||||
section_size=8 * 1024,
|
||||
bs=GOST3412Magma.blocksize,
|
||||
data=ciphertext,
|
||||
iv=ukm[:GOST3412Magma.blocksize // 2],
|
||||
)
|
||||
self.assertSequenceEqual(plaintext, self.prv_test_raw)
|
||||
|
||||
mac_data = pfx["macData"]
|
||||
mac_key = gost34112012_pbkdf2(
|
||||
password=self.password,
|
||||
salt=bytes(mac_data["macSalt"]),
|
||||
iterations=int(mac_data["iterations"]),
|
||||
dklen=96,
|
||||
)[-32:]
|
||||
# mac_key = hexdec("084f81782af1534ffd67e3c579c14cb45d7a6f659f46fdbb51a552e874e66fb2")
|
||||
self.assertSequenceEqual(
|
||||
hmac_new(
|
||||
key=mac_key,
|
||||
msg=SafeContents(outer_safe_contents).encode(),
|
||||
digestmod=GOST34112012512,
|
||||
).digest(),
|
||||
bytes(mac_data["mac"]["digest"]),
|
||||
)
|
||||
|
||||
def test_dh(self):
|
||||
curve = gost3410.CURVES["id-tc26-gost-3410-12-256-paramSetA"]
|
||||
# sender_prv_raw = hexdec("0B20810E449978C7C3B76C6FF77A16C532421139344A058EF56310B6B6F377E8")
|
||||
sender_cert = Certificate().decod(b64decode("""
|
||||
MIIB6zCCAZigAwIBAgIEAYy6gjAKBggqhQMHAQEDAjA4MQ0wCwYDVQQKEwRUSzI2
|
||||
MScwJQYDVQQDEx5DQSBUSzI2OiBHT1NUIDM0LjEwLTEyIDI1Ni1iaXQwHhcNMDEw
|
||||
MTAxMDAwMDAwWhcNNDkxMjMxMDAwMDAwWjA7MQ0wCwYDVQQKEwRUSzI2MSowKAYD
|
||||
VQQDEyFPUklHSU5BVE9SOiBHT1NUIDM0LjEwLTEyIDI1Ni1iaXQwXjAXBggqhQMH
|
||||
AQEBATALBgkqhQMHAQIBAQEDQwAEQJYpDRNiWWqDgaZje0EmLLOldQ35o5X1ZuZN
|
||||
SKequYQc/soI3OgDMWD7ThJJCk01IelCeb6MsBmG4lol+pnpVtOjgYcwgYQwYwYD
|
||||
VR0jBFwwWoAUrGwOTERmokKW4p8JOyVm88ukUyqhPKQ6MDgxDTALBgNVBAoTBFRL
|
||||
MjYxJzAlBgNVBAMTHkNBIFRLMjY6IEdPU1QgMzQuMTAtMTIgMjU2LWJpdIIEAYy6
|
||||
gTAdBgNVHQ4EFgQUPx5RgcjkifhlJm4/jQdkbm30rVQwCgYIKoUDBwEBAwIDQQA6
|
||||
8x7Vk6PvP/8xOGHhf8PuqaXAYskSyJPuBu+3Bo/PEj10devwc1J9uYWIDCGdKKPy
|
||||
bSlnQHqUPBBPM30YX1YN
|
||||
"""))
|
||||
recipient_prv_raw = hexdec("0DC8DC1FF2BC114BABC3F1CA8C51E4F58610427E197B1C2FBDBA4AE58CBFB7CE")[::-1]
|
||||
recipient_prv = gost3410.prv_unmarshal(recipient_prv_raw)
|
||||
recipient_cert = Certificate().decod(b64decode("""
|
||||
MIIB6jCCAZegAwIBAgIEAYy6gzAKBggqhQMHAQEDAjA4MQ0wCwYDVQQKEwRUSzI2
|
||||
MScwJQYDVQQDEx5DQSBUSzI2OiBHT1NUIDM0LjEwLTEyIDI1Ni1iaXQwHhcNMDEw
|
||||
MTAxMDAwMDAwWhcNNDkxMjMxMDAwMDAwWjA6MQ0wCwYDVQQKEwRUSzI2MSkwJwYD
|
||||
VQQDEyBSRUNJUElFTlQ6IEdPU1QgMzQuMTAtMTIgMjU2LWJpdDBeMBcGCCqFAwcB
|
||||
AQEBMAsGCSqFAwcBAgEBAQNDAARAvyeCGXMsYwpYe5aE0w8w3m4vpKQapGInqpnF
|
||||
lv7h08psFP0s1W80q3BR534F4TmR+o5+iU+AW6ycvWuc73JEQ6OBhzCBhDBjBgNV
|
||||
HSMEXDBagBSsbA5MRGaiQpbinwk7JWbzy6RTKqE8pDowODENMAsGA1UEChMEVEsy
|
||||
NjEnMCUGA1UEAxMeQ0EgVEsyNjogR09TVCAzNC4xMC0xMiAyNTYtYml0ggQBjLqB
|
||||
MB0GA1UdDgQWBBQ35gHPN1bx8l2eEMTbrtIg+5MU0TAKBggqhQMHAQEDAgNBABF2
|
||||
RHDaRqQuBS2yu7yGIGFgA6c/LG4GKjSOwYsRVmXJNNkQ4TB7PB8j3q7gx2koPsVB
|
||||
m90WfMWSL6SNSh3muuM=
|
||||
"""))
|
||||
self.assertTrue(gost3410.verify(
|
||||
self.ca_curve,
|
||||
self.ca_pub,
|
||||
GOST34112012256(sender_cert["tbsCertificate"].encode()).digest()[::-1],
|
||||
bytes(sender_cert["signatureValue"]),
|
||||
))
|
||||
self.assertTrue(gost3410.verify(
|
||||
self.ca_curve,
|
||||
self.ca_pub,
|
||||
GOST34112012256(recipient_cert["tbsCertificate"].encode()).digest()[::-1],
|
||||
bytes(recipient_cert["signatureValue"]),
|
||||
))
|
||||
|
||||
pfx_raw = b64decode("""
|
||||
MIIKVwIBAzCCClAGCSqGSIb3DQEHAqCCCkEwggo9AgEBMQwwCgYIKoUDBwEBAgIw
|
||||
ggcjBgkqhkiG9w0BBwGgggcUBIIHEDCCBwwwggKdBgkqhkiG9w0BBwGgggKOBIIC
|
||||
ijCCAoYwggKCBgsqhkiG9w0BDAoBA6CCAkowggJGBgoqhkiG9w0BCRYBoIICNgSC
|
||||
AjIwggIuMIIB26ADAgECAgQBjLqEMAoGCCqFAwcBAQMCMDgxDTALBgNVBAoTBFRL
|
||||
MjYxJzAlBgNVBAMTHkNBIFRLMjY6IEdPU1QgMzQuMTAtMTIgMjU2LWJpdDAeFw0w
|
||||
MTAxMDEwMDAwMDBaFw00OTEyMzEwMDAwMDBaMDsxDTALBgNVBAoTBFRLMjYxKjAo
|
||||
BgNVBAMTIU9SSUdJTkFUT1I6IEdPU1QgMzQuMTAtMTIgNTEyLWJpdDCBoDAXBggq
|
||||
hQMHAQEBAjALBgkqhQMHAQIBAgEDgYQABIGAtIu3WrwpDhhlXGKhT7UtX1CETswd
|
||||
H2AESHtLXJU0aWq3v6s0blUWqas8zvittSw6WFXwz7Nkqmtd2Tfk7PyVJb+faghQ
|
||||
dnGKRcgf9JIePiu/cr8+6/PuFhNBJmX/E92nvydSaOsRrp3nB9fxuITLbPR2C58W
|
||||
8CQzDVRriB1eoM6jgYcwgYQwYwYDVR0jBFwwWoAUrGwOTERmokKW4p8JOyVm88uk
|
||||
UyqhPKQ6MDgxDTALBgNVBAoTBFRLMjYxJzAlBgNVBAMTHkNBIFRLMjY6IEdPU1Qg
|
||||
MzQuMTAtMTIgMjU2LWJpdIIEAYy6gTAdBgNVHQ4EFgQUfgZXCZgMrWsIqFfueQBY
|
||||
OsnXoKQwCgYIKoUDBwEBAwIDQQAKXqnx0BumL0eT7eaAzIjRYiHXsiuWtKn+YHQX
|
||||
tnMy3xdQPUPDPcmuufF5ed8y84DkF1Qn2ELIOAxUAaz8hwQQMSUwIwYJKoZIhvcN
|
||||
AQkVMRYEFHlVdPnUtuTCAiQoaZhnP/AKFMBNMIIEZwYJKoZIhvcNAQcDoIIEWDCC
|
||||
BFQCAQKgggHzoIIB7zCCAeswggGYoAMCAQICBAGMuoIwCgYIKoUDBwEBAwIwODEN
|
||||
MAsGA1UEChMEVEsyNjEnMCUGA1UEAxMeQ0EgVEsyNjogR09TVCAzNC4xMC0xMiAy
|
||||
NTYtYml0MB4XDTAxMDEwMTAwMDAwMFoXDTQ5MTIzMTAwMDAwMFowOzENMAsGA1UE
|
||||
ChMEVEsyNjEqMCgGA1UEAxMhT1JJR0lOQVRPUjogR09TVCAzNC4xMC0xMiAyNTYt
|
||||
Yml0MF4wFwYIKoUDBwEBAQEwCwYJKoUDBwECAQEBA0MABECWKQ0TYllqg4GmY3tB
|
||||
JiyzpXUN+aOV9WbmTUinqrmEHP7KCNzoAzFg+04SSQpNNSHpQnm+jLAZhuJaJfqZ
|
||||
6VbTo4GHMIGEMGMGA1UdIwRcMFqAFKxsDkxEZqJCluKfCTslZvPLpFMqoTykOjA4
|
||||
MQ0wCwYDVQQKEwRUSzI2MScwJQYDVQQDEx5DQSBUSzI2OiBHT1NUIDM0LjEwLTEy
|
||||
IDI1Ni1iaXSCBAGMuoEwHQYDVR0OBBYEFD8eUYHI5In4ZSZuP40HZG5t9K1UMAoG
|
||||
CCqFAwcBAQMCA0EAOvMe1ZOj7z//MThh4X/D7qmlwGLJEsiT7gbvtwaPzxI9dHXr
|
||||
8HNSfbmFiAwhnSij8m0pZ0B6lDwQTzN9GF9WDTGB/6GB/AIBA6BCMEAwODENMAsG
|
||||
A1UEChMEVEsyNjEnMCUGA1UEAxMeQ0EgVEsyNjogR09TVCAzNC4xMC0xMiAyNTYt
|
||||
Yml0AgQBjLqCoSIEIBt4fjey+k8C1D3OaMca8wl6h3j3C6OAbrx8rmxXktsQMBcG
|
||||
CSqFAwcBAQcCATAKBggqhQMHAQEGATB2MHQwQDA4MQ0wCwYDVQQKEwRUSzI2MScw
|
||||
JQYDVQQDEx5DQSBUSzI2OiBHT1NUIDM0LjEwLTEyIDI1Ni1iaXQCBAGMuoMEMJkp
|
||||
Wae6IVfaY3mP0izRY7ifc41fATXdJ2tmTl+1vitkSE2vLCKXDLl90KfHA6gNmDCC
|
||||
AVQGCSqGSIb3DQEHATAfBgkqhQMHAQEFAgEwEgQQFhEshEBO2LkAAAAAAAAAAICC
|
||||
ASQYvLpT/8azEXJfekyGuyvE9UkVX+Ao8sfu9My/c4WAVRNMhZkCqD+BbPwBsIzN
|
||||
sXZIi9rXGAfsPz7xaO9EUFZPjNOWtF/E01oJgG+gYLFn7qAiEFcmRLptSHuanNHn
|
||||
7Yol6IHushX4UaW9hEa/L6eFQx/hoDhrNZnWTXNZtNuHuMGC9dzhHhTxfkdjZYXD
|
||||
v+M7psVj58JutE3U2d4pgxKcBPdMO4vl4+27cIKxQZFZU2zuCVJLYLqmPT5pCBkM
|
||||
mJqy7bZwHOJ9kBq/TGUf8iJGYSCNre3RTNLbcTTk7rZrbiMkFsG3borzenpouS5E
|
||||
BcCkBt8Mj0nvsMCu9ipHTuWww7LltlkXCjlNXFUi6ZI3VyHW5CDpghujQWiZxiAc
|
||||
JuGl6GwZoIIB7zCCAeswggGYoAMCAQICBAGMuoIwCgYIKoUDBwEBAwIwODENMAsG
|
||||
A1UEChMEVEsyNjEnMCUGA1UEAxMeQ0EgVEsyNjogR09TVCAzNC4xMC0xMiAyNTYt
|
||||
Yml0MB4XDTAxMDEwMTAwMDAwMFoXDTQ5MTIzMTAwMDAwMFowOzENMAsGA1UEChME
|
||||
VEsyNjEqMCgGA1UEAxMhT1JJR0lOQVRPUjogR09TVCAzNC4xMC0xMiAyNTYtYml0
|
||||
MF4wFwYIKoUDBwEBAQEwCwYJKoUDBwECAQEBA0MABECWKQ0TYllqg4GmY3tBJiyz
|
||||
pXUN+aOV9WbmTUinqrmEHP7KCNzoAzFg+04SSQpNNSHpQnm+jLAZhuJaJfqZ6VbT
|
||||
o4GHMIGEMGMGA1UdIwRcMFqAFKxsDkxEZqJCluKfCTslZvPLpFMqoTykOjA4MQ0w
|
||||
CwYDVQQKEwRUSzI2MScwJQYDVQQDEx5DQSBUSzI2OiBHT1NUIDM0LjEwLTEyIDI1
|
||||
Ni1iaXSCBAGMuoEwHQYDVR0OBBYEFD8eUYHI5In4ZSZuP40HZG5t9K1UMAoGCCqF
|
||||
AwcBAQMCA0EAOvMe1ZOj7z//MThh4X/D7qmlwGLJEsiT7gbvtwaPzxI9dHXr8HNS
|
||||
fbmFiAwhnSij8m0pZ0B6lDwQTzN9GF9WDTGCAQ4wggEKAgEBMEAwODENMAsGA1UE
|
||||
ChMEVEsyNjEnMCUGA1UEAxMeQ0EgVEsyNjogR09TVCAzNC4xMC0xMiAyNTYtYml0
|
||||
AgQBjLqCMAoGCCqFAwcBAQICoGkwGAYJKoZIhvcNAQkDMQsGCSqGSIb3DQEHATAc
|
||||
BgkqhkiG9w0BCQUxDxcNMjEwNDE0MTkyMTEyWjAvBgkqhkiG9w0BCQQxIgQg1XOA
|
||||
zNa710QuXsn5+yIf3cNTiFOQMgTiBRJBz8Tr4I0wCgYIKoUDBwEBAQEEQALINal9
|
||||
7wHXYiG+w0yzSkKOs0jRZew0S73r/cfk/sUoM3HKKIEbKruvlAdiOqX/HLFSEx/s
|
||||
kxFG6QUFH8uuoX8=
|
||||
""")
|
||||
pfx = PFX().decod(pfx_raw)
|
||||
self.assertEqual(pfx["authSafe"]["contentType"], id_signedData)
|
||||
|
||||
sd = SignedData().decod(bytes(pfx["authSafe"]["content"]))
|
||||
self.assertEqual(sd["certificates"][0]["certificate"], sender_cert)
|
||||
si = sd["signerInfos"][0]
|
||||
self.assertEqual(
|
||||
si["digestAlgorithm"]["algorithm"],
|
||||
id_tc26_gost3411_2012_256,
|
||||
)
|
||||
digest = [
|
||||
bytes(attr["attrValues"][0].defined[1]) for attr in si["signedAttrs"]
|
||||
if attr["attrType"] == id_messageDigest
|
||||
][0]
|
||||
sender_pub = gost3410.pub_unmarshal(bytes(OctetString().decod(bytes(
|
||||
sender_cert["tbsCertificate"]["subjectPublicKeyInfo"]["subjectPublicKey"]
|
||||
))))
|
||||
content = bytes(sd["encapContentInfo"]["eContent"])
|
||||
self.assertSequenceEqual(digest, GOST34112012256(content).digest())
|
||||
self.assertTrue(gost3410.verify(
|
||||
curve,
|
||||
sender_pub,
|
||||
GOST34112012256(
|
||||
SignedAttributes(si["signedAttrs"]).encode()
|
||||
).digest()[::-1],
|
||||
bytes(si["signature"]),
|
||||
))
|
||||
|
||||
outer_safe_contents = SafeContents().decod(content)
|
||||
|
||||
safe_bag = outer_safe_contents[0]
|
||||
self.assertEqual(safe_bag["bagId"], id_data)
|
||||
safe_contents = OctetStringSafeContents().decod(bytes(safe_bag["bagValue"]))
|
||||
safe_bag = safe_contents[0]
|
||||
self.assertEqual(safe_bag["bagId"], id_pkcs12_bagtypes_certBag)
|
||||
cert_bag = CertBag().decod(bytes(safe_bag["bagValue"]))
|
||||
self.assertEqual(cert_bag["certId"], id_pkcs9_certTypes_x509Certificate)
|
||||
_, cert = cert_bag["certValue"].defined
|
||||
self.assertEqual(Certificate(cert), self.cert_test)
|
||||
|
||||
safe_bag = outer_safe_contents[1]
|
||||
self.assertEqual(safe_bag["bagId"], id_envelopedData)
|
||||
ed = EnvelopedData().decod(bytes(safe_bag["bagValue"]))
|
||||
kari = ed["recipientInfos"][0]["kari"]
|
||||
ukm = bytes(kari["ukm"])
|
||||
self.assertEqual(
|
||||
kari["keyEncryptionAlgorithm"]["algorithm"],
|
||||
id_gostr3412_2015_kuznyechik_wrap_kexp15,
|
||||
)
|
||||
self.assertEqual(
|
||||
kari["keyEncryptionAlgorithm"]["parameters"].defined[1]["algorithm"],
|
||||
id_tc26_agreement_gost3410_2012_256,
|
||||
)
|
||||
kexp = bytes(kari["recipientEncryptedKeys"][0]["encryptedKey"])
|
||||
keymat = keg(curve, recipient_prv, sender_pub, ukm)
|
||||
kim, kek = keymat[:KEYSIZE], keymat[KEYSIZE:]
|
||||
cek = kimp15(
|
||||
GOST3412Kuznechik(kek).encrypt,
|
||||
GOST3412Kuznechik(kim).encrypt,
|
||||
GOST3412Kuznechik.blocksize,
|
||||
kexp,
|
||||
ukm[24:24 + GOST3412Kuznechik.blocksize // 2],
|
||||
)
|
||||
eci = ed["encryptedContentInfo"]
|
||||
self.assertEqual(
|
||||
eci["contentEncryptionAlgorithm"]["algorithm"],
|
||||
id_gostr3412_2015_kuznyechik_ctracpkm,
|
||||
)
|
||||
eci_ukm = bytes(
|
||||
eci["contentEncryptionAlgorithm"]["parameters"].defined[1]["ukm"]
|
||||
)
|
||||
content = ctr_acpkm(
|
||||
GOST3412Kuznechik,
|
||||
GOST3412Kuznechik(cek).encrypt,
|
||||
256 * 1024,
|
||||
GOST3412Kuznechik.blocksize,
|
||||
bytes(eci["encryptedContent"]),
|
||||
eci_ukm[:GOST3412Kuznechik.blocksize // 2],
|
||||
)
|
||||
|
||||
safe_contents = SafeContents().decod(content)
|
||||
safe_bag = safe_contents[0]
|
||||
self.assertEqual(safe_bag["bagId"], id_pkcs12_bagtypes_keyBag)
|
||||
KeyBag().decod(bytes(safe_bag["bagValue"]))
|
||||
self.assertSequenceEqual(bytes(safe_bag["bagValue"]), self.prv_test_raw)
|
||||
@ -1,111 +0,0 @@
|
||||
# coding: utf-8
|
||||
# PyGOST -- Pure Python GOST cryptographic functions library
|
||||
# Copyright (C) 2015-2023 Sergey Matveev <stargrave@stargrave.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, version 3 of the License.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from os import urandom
|
||||
from unittest import TestCase
|
||||
|
||||
from pygost.gost28147 import DEFAULT_SBOX
|
||||
from pygost.gost3412 import GOST3412Kuznechik
|
||||
from pygost.gost3412 import GOST3412Magma
|
||||
from pygost.utils import hexdec
|
||||
from pygost.wrap import kexp15
|
||||
from pygost.wrap import kimp15
|
||||
from pygost.wrap import unwrap_cryptopro
|
||||
from pygost.wrap import unwrap_gost
|
||||
from pygost.wrap import wrap_cryptopro
|
||||
from pygost.wrap import wrap_gost
|
||||
|
||||
|
||||
class WrapGostTest(TestCase):
|
||||
def test_symmetric(self):
|
||||
for sbox in (DEFAULT_SBOX, "id-tc26-gost-28147-param-Z"):
|
||||
for _ in range(1 << 8):
|
||||
kek = urandom(32)
|
||||
cek = urandom(32)
|
||||
ukm = urandom(8)
|
||||
wrapped = wrap_gost(ukm, kek, cek, sbox=sbox)
|
||||
unwrapped = unwrap_gost(kek, wrapped, sbox=sbox)
|
||||
self.assertSequenceEqual(unwrapped, cek)
|
||||
|
||||
def test_invalid_length(self):
|
||||
with self.assertRaises(ValueError):
|
||||
unwrap_gost(urandom(32), urandom(41))
|
||||
with self.assertRaises(ValueError):
|
||||
unwrap_gost(urandom(32), urandom(45))
|
||||
|
||||
|
||||
class WrapCryptoproTest(TestCase):
|
||||
def test_symmetric(self):
|
||||
for sbox in (DEFAULT_SBOX, "id-tc26-gost-28147-param-Z"):
|
||||
for _ in range(1 << 8):
|
||||
kek = urandom(32)
|
||||
cek = urandom(32)
|
||||
ukm = urandom(8)
|
||||
wrapped = wrap_cryptopro(ukm, kek, cek, sbox=sbox)
|
||||
unwrapped = unwrap_cryptopro(kek, wrapped, sbox=sbox)
|
||||
self.assertSequenceEqual(unwrapped, cek)
|
||||
|
||||
|
||||
class TestVectorKExp15(TestCase):
|
||||
"""Test vectors from Р 1323565.1.017-2018
|
||||
"""
|
||||
key = hexdec("8899AABBCCDDEEFF0011223344556677FEDCBA98765432100123456789ABCDEF")
|
||||
key_enc = hexdec("202122232425262728292A2B2C2D2E2F38393A3B3C3D3E3F3031323334353637")
|
||||
key_mac = hexdec("08090A0B0C0D0E0F0001020304050607101112131415161718191A1B1C1D1E1F")
|
||||
|
||||
def test_magma(self):
|
||||
iv = hexdec("67BED654")
|
||||
kexp = kexp15(
|
||||
GOST3412Magma(self.key_enc).encrypt,
|
||||
GOST3412Magma(self.key_mac).encrypt,
|
||||
GOST3412Magma.blocksize,
|
||||
self.key,
|
||||
iv,
|
||||
)
|
||||
self.assertSequenceEqual(kexp, hexdec("""
|
||||
CF D5 A1 2D 5B 81 B6 E1 E9 9C 91 6D 07 90 0C 6A
|
||||
C1 27 03 FB 3A BD ED 55 56 7B F3 74 2C 89 9C 75
|
||||
5D AF E7 B4 2E 3A 8B D9
|
||||
""".replace("\n", "").replace(" ", "")))
|
||||
self.assertSequenceEqual(kimp15(
|
||||
GOST3412Magma(self.key_enc).encrypt,
|
||||
GOST3412Magma(self.key_mac).encrypt,
|
||||
GOST3412Magma.blocksize,
|
||||
kexp,
|
||||
iv,
|
||||
), self.key)
|
||||
|
||||
def test_kuznechik(self):
|
||||
iv = hexdec("0909472DD9F26BE8")
|
||||
kexp = kexp15(
|
||||
GOST3412Kuznechik(self.key_enc).encrypt,
|
||||
GOST3412Kuznechik(self.key_mac).encrypt,
|
||||
GOST3412Kuznechik.blocksize,
|
||||
self.key,
|
||||
iv,
|
||||
)
|
||||
self.assertSequenceEqual(kexp, hexdec("""
|
||||
E3 61 84 E8 4E 8D 73 6F F3 6C C2 E5 AE 06 5D C6
|
||||
56 B2 3C 20 F5 49 B0 2F DF F8 8E 1F 3F 30 D8 C2
|
||||
9A 53 F3 CA 55 4D BA D8 0D E1 52 B9 A4 62 5B 32
|
||||
""".replace("\n", "").replace(" ", "")))
|
||||
self.assertSequenceEqual(kimp15(
|
||||
GOST3412Kuznechik(self.key_enc).encrypt,
|
||||
GOST3412Kuznechik(self.key_mac).encrypt,
|
||||
GOST3412Kuznechik.blocksize,
|
||||
kexp,
|
||||
iv,
|
||||
), self.key)
|
||||
@ -1,433 +0,0 @@
|
||||
# coding: utf-8
|
||||
# PyGOST -- Pure Python GOST cryptographic functions library
|
||||
# Copyright (C) 2015-2023 Sergey Matveev <stargrave@stargrave.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, version 3 of the License.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from base64 import b64decode
|
||||
from unittest import skipIf
|
||||
from unittest import TestCase
|
||||
|
||||
from pygost.gost3410 import CURVES
|
||||
from pygost.gost3410 import prv_unmarshal
|
||||
from pygost.gost3410 import pub_marshal
|
||||
from pygost.gost3410 import pub_unmarshal
|
||||
from pygost.gost3410 import public_key
|
||||
from pygost.gost3410 import verify
|
||||
from pygost.gost34112012256 import GOST34112012256
|
||||
from pygost.gost34112012512 import GOST34112012512
|
||||
from pygost.utils import hexdec
|
||||
|
||||
try:
|
||||
|
||||
from pyderasn import Any
|
||||
from pyderasn import BitString
|
||||
from pyderasn import Boolean
|
||||
from pyderasn import GeneralizedTime
|
||||
from pyderasn import Integer
|
||||
from pyderasn import OctetString
|
||||
from pyderasn import PrintableString
|
||||
from pyderasn import UTCTime
|
||||
|
||||
from pygost.asn1schemas.oids import id_at_commonName
|
||||
from pygost.asn1schemas.oids import id_ce_basicConstraints
|
||||
from pygost.asn1schemas.oids import id_GostR3410_2001_TestParamSet
|
||||
from pygost.asn1schemas.oids import id_tc26_gost3410_2012_256
|
||||
from pygost.asn1schemas.oids import id_tc26_gost3410_2012_256_paramSetA
|
||||
from pygost.asn1schemas.oids import id_tc26_gost3410_2012_512
|
||||
from pygost.asn1schemas.oids import id_tc26_gost3410_2012_512_paramSetTest
|
||||
from pygost.asn1schemas.oids import id_tc26_gost3411_2012_256
|
||||
from pygost.asn1schemas.oids import id_tc26_signwithdigest_gost3410_2012_256
|
||||
from pygost.asn1schemas.oids import id_tc26_signwithdigest_gost3410_2012_512
|
||||
from pygost.asn1schemas.pkcs10 import Attributes
|
||||
from pygost.asn1schemas.pkcs10 import CertificationRequest
|
||||
from pygost.asn1schemas.pkcs10 import CertificationRequestInfo
|
||||
from pygost.asn1schemas.x509 import AlgorithmIdentifier
|
||||
from pygost.asn1schemas.x509 import AttributeType
|
||||
from pygost.asn1schemas.x509 import AttributeTypeAndValue
|
||||
from pygost.asn1schemas.x509 import AttributeValue
|
||||
from pygost.asn1schemas.x509 import BasicConstraints
|
||||
from pygost.asn1schemas.x509 import Certificate
|
||||
from pygost.asn1schemas.x509 import CertificateList
|
||||
from pygost.asn1schemas.x509 import CertificateSerialNumber
|
||||
from pygost.asn1schemas.x509 import Extension
|
||||
from pygost.asn1schemas.x509 import Extensions
|
||||
from pygost.asn1schemas.x509 import GostR34102012PublicKeyParameters
|
||||
from pygost.asn1schemas.x509 import Name
|
||||
from pygost.asn1schemas.x509 import RDNSequence
|
||||
from pygost.asn1schemas.x509 import RelativeDistinguishedName
|
||||
from pygost.asn1schemas.x509 import SubjectPublicKeyInfo
|
||||
from pygost.asn1schemas.x509 import TBSCertificate
|
||||
from pygost.asn1schemas.x509 import TBSCertList
|
||||
from pygost.asn1schemas.x509 import Time
|
||||
from pygost.asn1schemas.x509 import Validity
|
||||
from pygost.asn1schemas.x509 import Version
|
||||
|
||||
except ImportError:
|
||||
pyderasn_exists = False
|
||||
else:
|
||||
pyderasn_exists = True
|
||||
|
||||
|
||||
@skipIf(not pyderasn_exists, "PyDERASN dependency is required")
|
||||
class TestCertificate(TestCase):
|
||||
"""Certificate test vectors from "Использования алгоритмов ГОСТ Р
|
||||
34.10, ГОСТ Р 34.11 в профиле сертификата и списке отзыва
|
||||
сертификатов (CRL) инфраструктуры открытых ключей X.509"
|
||||
(TK26IOK.pdf)
|
||||
"""
|
||||
|
||||
def process_cert(self, curve_name, hasher, prv_key_raw, cert_raw):
|
||||
cert, tail = Certificate().decode(cert_raw, ctx={
|
||||
"defines_by_path": (
|
||||
(
|
||||
(
|
||||
"tbsCertificate",
|
||||
"subjectPublicKeyInfo",
|
||||
"algorithm",
|
||||
"algorithm",
|
||||
),
|
||||
(
|
||||
(
|
||||
("..", "subjectPublicKey"),
|
||||
{
|
||||
id_tc26_gost3410_2012_256: OctetString(),
|
||||
id_tc26_gost3410_2012_512: OctetString(),
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
})
|
||||
self.assertSequenceEqual(tail, b"")
|
||||
curve = CURVES[curve_name]
|
||||
prv_key = prv_unmarshal(prv_key_raw)
|
||||
spk = cert["tbsCertificate"]["subjectPublicKeyInfo"]["subjectPublicKey"]
|
||||
self.assertIsNotNone(spk.defined)
|
||||
_, pub_key_raw = spk.defined
|
||||
pub_key = pub_unmarshal(bytes(pub_key_raw))
|
||||
self.assertSequenceEqual(pub_key, public_key(curve, prv_key))
|
||||
self.assertTrue(verify(
|
||||
curve,
|
||||
pub_key,
|
||||
hasher(cert["tbsCertificate"].encode()).digest()[::-1],
|
||||
bytes(cert["signatureValue"]),
|
||||
))
|
||||
|
||||
def test_256(self):
|
||||
cert_raw = b64decode("""
|
||||
MIICYjCCAg+gAwIBAgIBATAKBggqhQMHAQEDAjBWMSkwJwYJKoZIhvcNAQkBFhpH
|
||||
b3N0UjM0MTAtMjAxMkBleGFtcGxlLmNvbTEpMCcGA1UEAxMgR29zdFIzNDEwLTIw
|
||||
MTIgKDI1NiBiaXQpIGV4YW1wbGUwHhcNMTMxMTA1MTQwMjM3WhcNMzAxMTAxMTQw
|
||||
MjM3WjBWMSkwJwYJKoZIhvcNAQkBFhpHb3N0UjM0MTAtMjAxMkBleGFtcGxlLmNv
|
||||
bTEpMCcGA1UEAxMgR29zdFIzNDEwLTIwMTIgKDI1NiBiaXQpIGV4YW1wbGUwZjAf
|
||||
BggqhQMHAQEBATATBgcqhQMCAiQABggqhQMHAQECAgNDAARAut/Qw1MUq9KPqkdH
|
||||
C2xAF3K7TugHfo9n525D2s5mFZdD5pwf90/i4vF0mFmr9nfRwMYP4o0Pg1mOn5Rl
|
||||
aXNYraOBwDCBvTAdBgNVHQ4EFgQU1fIeN1HaPbw+XWUzbkJ+kHJUT0AwCwYDVR0P
|
||||
BAQDAgHGMA8GA1UdEwQIMAYBAf8CAQEwfgYDVR0BBHcwdYAU1fIeN1HaPbw+XWUz
|
||||
bkJ+kHJUT0ChWqRYMFYxKTAnBgkqhkiG9w0BCQEWGkdvc3RSMzQxMC0yMDEyQGV4
|
||||
YW1wbGUuY29tMSkwJwYDVQQDEyBHb3N0UjM0MTAtMjAxMiAoMjU2IGJpdCkgZXhh
|
||||
bXBsZYIBATAKBggqhQMHAQEDAgNBAF5bm4BbARR6hJLEoWJkOsYV3Hd7kXQQjz3C
|
||||
dqQfmHrz6TI6Xojdh/t8ckODv/587NS5/6KsM77vc6Wh90NAT2s=
|
||||
""")
|
||||
prv_key_raw = hexdec("BFCF1D623E5CDD3032A7C6EABB4A923C46E43D640FFEAAF2C3ED39A8FA399924")[::-1]
|
||||
self.process_cert(
|
||||
"id-GostR3410-2001-CryptoPro-XchA-ParamSet",
|
||||
GOST34112012256,
|
||||
prv_key_raw,
|
||||
cert_raw,
|
||||
)
|
||||
|
||||
def test_512(self):
|
||||
cert_raw = b64decode("""
|
||||
MIIC6DCCAlSgAwIBAgIBATAKBggqhQMHAQEDAzBWMSkwJwYJKoZIhvcNAQkBFhpH
|
||||
b3N0UjM0MTAtMjAxMkBleGFtcGxlLmNvbTEpMCcGA1UEAxMgR29zdFIzNDEwLTIw
|
||||
MTIgKDUxMiBiaXQpIGV4YW1wbGUwHhcNMTMxMDA0MDczNjA0WhcNMzAxMDAxMDcz
|
||||
NjA0WjBWMSkwJwYJKoZIhvcNAQkBFhpHb3N0UjM0MTAtMjAxMkBleGFtcGxlLmNv
|
||||
bTEpMCcGA1UEAxMgR29zdFIzNDEwLTIwMTIgKDUxMiBiaXQpIGV4YW1wbGUwgaow
|
||||
IQYIKoUDBwEBAQIwFQYJKoUDBwECAQICBggqhQMHAQECAwOBhAAEgYATGQ9VCiM5
|
||||
FRGCQ8MEz2F1dANqhaEuywa8CbxOnTvaGJpFQVXQwkwvLFAKh7hk542vOEtxpKtT
|
||||
CXfGf84nRhMH/Q9bZeAc2eO/yhxrsQhTBufa1Fuou2oe/jUOaG6RAtUUvRzhNTpp
|
||||
RGGl1+EIY2vzzUua9j9Ol/gAoy/LNKQIfqOBwDCBvTAdBgNVHQ4EFgQUPcbTRXJZ
|
||||
nHtjj+eBP7b5lcTMekIwCwYDVR0PBAQDAgHGMA8GA1UdEwQIMAYBAf8CAQEwfgYD
|
||||
VR0BBHcwdYAUPcbTRXJZnHtjj+eBP7b5lcTMekKhWqRYMFYxKTAnBgkqhkiG9w0B
|
||||
CQEWGkdvc3RSMzQxMC0yMDEyQGV4YW1wbGUuY29tMSkwJwYDVQQDEyBHb3N0UjM0
|
||||
MTAtMjAxMiAoNTEyIGJpdCkgZXhhbXBsZYIBATAKBggqhQMHAQEDAwOBgQBObS7o
|
||||
ppPTXzHyVR1DtPa8b57nudJzI4czhsfeX5HDntOq45t9B/qSs8dC6eGxbhHZ9zCO
|
||||
SFtxWYdmg0au8XI9Xb8vTC1qdwWID7FFjMWDNQZb6lYh/J+8F2xKylvB5nIlRZqO
|
||||
o3eUNFkNyHJwQCk2WoOlO16zwGk2tdKH4KmD5w==
|
||||
""")
|
||||
prv_key_raw = hexdec("3FC01CDCD4EC5F972EB482774C41E66DB7F380528DFE9E67992BA05AEE462435757530E641077CE587B976C8EEB48C48FD33FD175F0C7DE6A44E014E6BCB074B")[::-1]
|
||||
self.process_cert(
|
||||
"id-tc26-gost-3410-12-512-paramSetB",
|
||||
GOST34112012512,
|
||||
prv_key_raw,
|
||||
cert_raw,
|
||||
)
|
||||
|
||||
|
||||
@skipIf(not pyderasn_exists, "PyDERASN dependency is required")
|
||||
class TestRFC4491bis(TestCase):
|
||||
"""Test vectors from https://tools.ietf.org/html/draft-deremin-rfc4491-bis-02
|
||||
"""
|
||||
|
||||
def _test_vector(
|
||||
self,
|
||||
curve_name,
|
||||
hsh,
|
||||
ai_spki,
|
||||
ai_sign,
|
||||
cert_serial,
|
||||
prv_hex,
|
||||
cr_sign_hex,
|
||||
cr_b64,
|
||||
c_sign_hex,
|
||||
c_b64,
|
||||
crl_sign_hex,
|
||||
crl_b64,
|
||||
):
|
||||
prv_raw = hexdec(prv_hex)[::-1]
|
||||
prv = prv_unmarshal(prv_raw)
|
||||
curve = CURVES[curve_name]
|
||||
pub = public_key(curve, prv)
|
||||
pub_raw = pub_marshal(pub)
|
||||
subj = Name(("rdnSequence", RDNSequence([
|
||||
RelativeDistinguishedName((
|
||||
AttributeTypeAndValue((
|
||||
("type", AttributeType(id_at_commonName)),
|
||||
("value", AttributeValue(PrintableString("Example"))),
|
||||
)),
|
||||
))
|
||||
])))
|
||||
spki = SubjectPublicKeyInfo((
|
||||
("algorithm", ai_spki),
|
||||
("subjectPublicKey", BitString(OctetString(pub_raw).encode())),
|
||||
))
|
||||
|
||||
# Certification request
|
||||
cri = CertificationRequestInfo((
|
||||
("version", Integer(0)),
|
||||
("subject", subj),
|
||||
("subjectPKInfo", spki),
|
||||
("attributes", Attributes()),
|
||||
))
|
||||
sign = hexdec(cr_sign_hex)
|
||||
self.assertTrue(verify(
|
||||
curve,
|
||||
pub,
|
||||
hsh(cri.encode()).digest()[::-1],
|
||||
sign,
|
||||
))
|
||||
cr = CertificationRequest((
|
||||
("certificationRequestInfo", cri),
|
||||
("signatureAlgorithm", ai_sign),
|
||||
("signature", BitString(sign)),
|
||||
))
|
||||
self.assertSequenceEqual(cr.encode(), b64decode(cr_b64))
|
||||
|
||||
# Certificate
|
||||
tbs = TBSCertificate((
|
||||
("version", Version("v3")),
|
||||
("serialNumber", CertificateSerialNumber(cert_serial)),
|
||||
("signature", ai_sign),
|
||||
("issuer", subj),
|
||||
("validity", Validity((
|
||||
("notBefore", Time(("utcTime", UTCTime(b"010101000000Z")))),
|
||||
("notAfter", Time(("generalTime", GeneralizedTime(b"20501231000000Z")))),
|
||||
))),
|
||||
("subject", subj),
|
||||
("subjectPublicKeyInfo", spki),
|
||||
("extensions", Extensions((
|
||||
Extension((
|
||||
("extnID", id_ce_basicConstraints),
|
||||
("critical", Boolean(True)),
|
||||
("extnValue", OctetString(
|
||||
BasicConstraints((("cA", Boolean(True)),)).encode()
|
||||
)),
|
||||
)),
|
||||
))),
|
||||
))
|
||||
sign = hexdec(c_sign_hex)
|
||||
self.assertTrue(verify(
|
||||
curve,
|
||||
pub,
|
||||
hsh(tbs.encode()).digest()[::-1],
|
||||
sign,
|
||||
))
|
||||
cert = Certificate((
|
||||
("tbsCertificate", tbs),
|
||||
("signatureAlgorithm", ai_sign),
|
||||
("signatureValue", BitString(sign)),
|
||||
))
|
||||
self.assertSequenceEqual(cert.encode(), b64decode(c_b64))
|
||||
|
||||
# CRL
|
||||
tbs = TBSCertList((
|
||||
("version", Version("v2")),
|
||||
("signature", ai_sign),
|
||||
("issuer", subj),
|
||||
("thisUpdate", Time(("utcTime", UTCTime(b"140101000000Z")))),
|
||||
("nextUpdate", Time(("utcTime", UTCTime(b"140102000000Z")))),
|
||||
))
|
||||
sign = hexdec(crl_sign_hex)
|
||||
self.assertTrue(verify(
|
||||
curve,
|
||||
pub,
|
||||
hsh(tbs.encode()).digest()[::-1],
|
||||
sign,
|
||||
))
|
||||
crl = CertificateList((
|
||||
("tbsCertList", tbs),
|
||||
("signatureAlgorithm", ai_sign),
|
||||
("signatureValue", BitString(sign)),
|
||||
))
|
||||
self.assertSequenceEqual(crl.encode(), b64decode(crl_b64))
|
||||
|
||||
def test_256_test_paramset(self):
|
||||
self._test_vector(
|
||||
"id-GostR3410-2001-TestParamSet",
|
||||
GOST34112012256,
|
||||
AlgorithmIdentifier((
|
||||
("algorithm", id_tc26_gost3410_2012_256),
|
||||
("parameters", Any(
|
||||
GostR34102012PublicKeyParameters((
|
||||
("publicKeyParamSet", id_GostR3410_2001_TestParamSet),
|
||||
("digestParamSet", id_tc26_gost3411_2012_256),
|
||||
))
|
||||
)),
|
||||
)),
|
||||
AlgorithmIdentifier((
|
||||
("algorithm", id_tc26_signwithdigest_gost3410_2012_256),
|
||||
)),
|
||||
10,
|
||||
"7A929ADE789BB9BE10ED359DD39A72C11B60961F49397EEE1D19CE9891EC3B28",
|
||||
"6AAAB38E35D4AAA517940301799122D855484F579F4CBB96D63CDFDF3ACC432A41AA28D2F1AB148280CD9ED56FEDA41974053554A42767B83AD043FD39DC0493",
|
||||
"""
|
||||
MIHTMIGBAgEAMBIxEDAOBgNVBAMTB0V4YW1wbGUwZjAfBggqhQMHAQEBATATBgcq
|
||||
hQMCAiMABggqhQMHAQECAgNDAARAC9hv5djbiWaPeJtOHbqFhcVQi0XsW1nYkG3b
|
||||
cOJJK3/ad/+HGhD73ydm0pPF0WSvuzx7lzpByIXRHXDWibTxJqAAMAoGCCqFAwcB
|
||||
AQMCA0EAaqqzjjXUqqUXlAMBeZEi2FVIT1efTLuW1jzf3zrMQypBqijS8asUgoDN
|
||||
ntVv7aQZdAU1VKQnZ7g60EP9OdwEkw==
|
||||
""",
|
||||
"4D53F012FE081776507D4D9BB81F00EFDB4EEFD4AB83BAC4BACF735173CFA81C41AA28D2F1AB148280CD9ED56FEDA41974053554A42767B83AD043FD39DC0493",
|
||||
"""
|
||||
MIIBLTCB26ADAgECAgEKMAoGCCqFAwcBAQMCMBIxEDAOBgNVBAMTB0V4YW1wbGUw
|
||||
IBcNMDEwMTAxMDAwMDAwWhgPMjA1MDEyMzEwMDAwMDBaMBIxEDAOBgNVBAMTB0V4
|
||||
YW1wbGUwZjAfBggqhQMHAQEBATATBgcqhQMCAiMABggqhQMHAQECAgNDAARAC9hv
|
||||
5djbiWaPeJtOHbqFhcVQi0XsW1nYkG3bcOJJK3/ad/+HGhD73ydm0pPF0WSvuzx7
|
||||
lzpByIXRHXDWibTxJqMTMBEwDwYDVR0TAQH/BAUwAwEB/zAKBggqhQMHAQEDAgNB
|
||||
AE1T8BL+CBd2UH1Nm7gfAO/bTu/Uq4O6xLrPc1Fzz6gcQaoo0vGrFIKAzZ7Vb+2k
|
||||
GXQFNVSkJ2e4OtBD/TncBJM=
|
||||
""",
|
||||
"42BF392A14D3EBE957AF3E46CB50BF5F4221A003AD3D172753C94A9C37A31D2041AA28D2F1AB148280CD9ED56FEDA41974053554A42767B83AD043FD39DC0493",
|
||||
"""
|
||||
MIGSMEECAQEwCgYIKoUDBwEBAwIwEjEQMA4GA1UEAxMHRXhhbXBsZRcNMTQwMTAx
|
||||
MDAwMDAwWhcNMTQwMTAyMDAwMDAwWjAKBggqhQMHAQEDAgNBAEK/OSoU0+vpV68+
|
||||
RstQv19CIaADrT0XJ1PJSpw3ox0gQaoo0vGrFIKAzZ7Vb+2kGXQFNVSkJ2e4OtBD
|
||||
/TncBJM=
|
||||
""",
|
||||
)
|
||||
|
||||
def test_256a_paramset(self):
|
||||
self._test_vector(
|
||||
"id-tc26-gost-3410-2012-256-paramSetA",
|
||||
GOST34112012256,
|
||||
AlgorithmIdentifier((
|
||||
("algorithm", id_tc26_gost3410_2012_256),
|
||||
("parameters", Any(
|
||||
GostR34102012PublicKeyParameters((
|
||||
("publicKeyParamSet", id_tc26_gost3410_2012_256_paramSetA),
|
||||
))
|
||||
)),
|
||||
)),
|
||||
AlgorithmIdentifier((
|
||||
("algorithm", id_tc26_signwithdigest_gost3410_2012_256),
|
||||
)),
|
||||
10,
|
||||
"7A929ADE789BB9BE10ED359DD39A72C11B60961F49397EEE1D19CE9891EC3B28",
|
||||
"1BDC2A1317679B66232F63EA16FF7C64CCAAB9AD855FC6E18091661DB79D48121D0E1DA5BE347C6F1B5256C7AEAC200AD64AC77A6F5B3A0E097318E7AE6EE769",
|
||||
"""
|
||||
MIHKMHkCAQAwEjEQMA4GA1UEAxMHRXhhbXBsZTBeMBcGCCqFAwcBAQEBMAsGCSqF
|
||||
AwcBAgEBAQNDAARAdCeV1L7ohN3yhQ/sA+o/rxhE4B2dpgtkUJOlXibfw5l49ZbP
|
||||
TU0MbPHRiUPZRJPRa57AoW1RLS4SfMRpGmMY4qAAMAoGCCqFAwcBAQMCA0EAG9wq
|
||||
Exdnm2YjL2PqFv98ZMyqua2FX8bhgJFmHbedSBIdDh2lvjR8bxtSVseurCAK1krH
|
||||
em9bOg4Jcxjnrm7naQ==
|
||||
""",
|
||||
"140B4DA9124B09CB0D5CE928EE874273A310129492EC0E29369E3B791248578C1D0E1DA5BE347C6F1B5256C7AEAC200AD64AC77A6F5B3A0E097318E7AE6EE769",
|
||||
"""
|
||||
MIIBJTCB06ADAgECAgEKMAoGCCqFAwcBAQMCMBIxEDAOBgNVBAMTB0V4YW1wbGUw
|
||||
IBcNMDEwMTAxMDAwMDAwWhgPMjA1MDEyMzEwMDAwMDBaMBIxEDAOBgNVBAMTB0V4
|
||||
YW1wbGUwXjAXBggqhQMHAQEBATALBgkqhQMHAQIBAQEDQwAEQHQnldS+6ITd8oUP
|
||||
7APqP68YROAdnaYLZFCTpV4m38OZePWWz01NDGzx0YlD2UST0WuewKFtUS0uEnzE
|
||||
aRpjGOKjEzARMA8GA1UdEwEB/wQFMAMBAf8wCgYIKoUDBwEBAwIDQQAUC02pEksJ
|
||||
yw1c6Sjuh0JzoxASlJLsDik2njt5EkhXjB0OHaW+NHxvG1JWx66sIArWSsd6b1s6
|
||||
DglzGOeubudp
|
||||
""",
|
||||
"14BD68087C3B903C7AA28B07FEB2E7BD6FE0963F563267359F5CD8EAB45059AD1D0E1DA5BE347C6F1B5256C7AEAC200AD64AC77A6F5B3A0E097318E7AE6EE769",
|
||||
"""
|
||||
MIGSMEECAQEwCgYIKoUDBwEBAwIwEjEQMA4GA1UEAxMHRXhhbXBsZRcNMTQwMTAx
|
||||
MDAwMDAwWhcNMTQwMTAyMDAwMDAwWjAKBggqhQMHAQEDAgNBABS9aAh8O5A8eqKL
|
||||
B/6y571v4JY/VjJnNZ9c2Oq0UFmtHQ4dpb40fG8bUlbHrqwgCtZKx3pvWzoOCXMY
|
||||
565u52k=
|
||||
""",
|
||||
)
|
||||
|
||||
def test_512_test_paramset(self):
|
||||
self._test_vector(
|
||||
"id-tc26-gost-3410-2012-512-paramSetTest",
|
||||
GOST34112012512,
|
||||
AlgorithmIdentifier((
|
||||
("algorithm", id_tc26_gost3410_2012_512),
|
||||
("parameters", Any(
|
||||
GostR34102012PublicKeyParameters((
|
||||
("publicKeyParamSet", id_tc26_gost3410_2012_512_paramSetTest),
|
||||
))
|
||||
)),
|
||||
)),
|
||||
AlgorithmIdentifier((
|
||||
("algorithm", id_tc26_signwithdigest_gost3410_2012_512),
|
||||
)),
|
||||
11,
|
||||
"0BA6048AADAE241BA40936D47756D7C93091A0E8514669700EE7508E508B102072E8123B2200A0563322DAD2827E2714A2636B7BFD18AADFC62967821FA18DD4",
|
||||
"433B1D6CE40A51F1E5737EB16AA2C683829A405B9D9127E21260FC9D6AC05D87BF24E26C45278A5C2192A75BA94993ABD6074E7FF1BF03FD2F5397AFA1D945582F86FA60A081091A23DD795E1E3C689EE512A3C82EE0DCC2643C78EEA8FCACD35492558486B20F1C9EC197C90699850260C93BCBCD9C5C3317E19344E173AE36",
|
||||
"""
|
||||
MIIBTzCBvAIBADASMRAwDgYDVQQDEwdFeGFtcGxlMIGgMBcGCCqFAwcBAQECMAsG
|
||||
CSqFAwcBAgECAAOBhAAEgYDh7zDVLGEz3dmdHVxBRVz3302LTJJbvGmvFDPRVlhR
|
||||
Wt0hRoUMMlxbgcEzvmVaqMTUQOe5io1ZSHsMdpa8xV0R7L53NqnsNX/y/TmTH04R
|
||||
TLjNo1knCsfw5/9D2UGUGeph/Sq3f12fY1I9O1CgT2PioM9Rt8E63CFWDwvUDMnH
|
||||
N6AAMAoGCCqFAwcBAQMDA4GBAEM7HWzkClHx5XN+sWqixoOCmkBbnZEn4hJg/J1q
|
||||
wF2HvyTibEUnilwhkqdbqUmTq9YHTn/xvwP9L1OXr6HZRVgvhvpgoIEJGiPdeV4e
|
||||
PGie5RKjyC7g3MJkPHjuqPys01SSVYSGsg8cnsGXyQaZhQJgyTvLzZxcMxfhk0Th
|
||||
c642
|
||||
""",
|
||||
"415703D892F1A5F3F68C4353189A7EE207B80B5631EF9D49529A4D6B542C2CFA15AA2EACF11F470FDE7D954856903C35FD8F955EF300D95C77534A724A0EEE702F86FA60A081091A23DD795E1E3C689EE512A3C82EE0DCC2643C78EEA8FCACD35492558486B20F1C9EC197C90699850260C93BCBCD9C5C3317E19344E173AE36",
|
||||
"""
|
||||
MIIBqjCCARagAwIBAgIBCzAKBggqhQMHAQEDAzASMRAwDgYDVQQDEwdFeGFtcGxl
|
||||
MCAXDTAxMDEwMTAwMDAwMFoYDzIwNTAxMjMxMDAwMDAwWjASMRAwDgYDVQQDEwdF
|
||||
eGFtcGxlMIGgMBcGCCqFAwcBAQECMAsGCSqFAwcBAgECAAOBhAAEgYDh7zDVLGEz
|
||||
3dmdHVxBRVz3302LTJJbvGmvFDPRVlhRWt0hRoUMMlxbgcEzvmVaqMTUQOe5io1Z
|
||||
SHsMdpa8xV0R7L53NqnsNX/y/TmTH04RTLjNo1knCsfw5/9D2UGUGeph/Sq3f12f
|
||||
Y1I9O1CgT2PioM9Rt8E63CFWDwvUDMnHN6MTMBEwDwYDVR0TAQH/BAUwAwEB/zAK
|
||||
BggqhQMHAQEDAwOBgQBBVwPYkvGl8/aMQ1MYmn7iB7gLVjHvnUlSmk1rVCws+hWq
|
||||
LqzxH0cP3n2VSFaQPDX9j5Ve8wDZXHdTSnJKDu5wL4b6YKCBCRoj3XleHjxonuUS
|
||||
o8gu4NzCZDx47qj8rNNUklWEhrIPHJ7Bl8kGmYUCYMk7y82cXDMX4ZNE4XOuNg==
|
||||
""",
|
||||
"3A13FB7AECDB5560EEF6137CFC5DD64691732EBFB3690A1FC0C7E8A4EEEA08307D648D4DC0986C46A87B3FBE4C7AF42EA34359C795954CA39FF3ABBED9051F4D2F86FA60A081091A23DD795E1E3C689EE512A3C82EE0DCC2643C78EEA8FCACD35492558486B20F1C9EC197C90699850260C93BCBCD9C5C3317E19344E173AE36",
|
||||
"""
|
||||
MIHTMEECAQEwCgYIKoUDBwEBAwMwEjEQMA4GA1UEAxMHRXhhbXBsZRcNMTQwMTAx
|
||||
MDAwMDAwWhcNMTQwMTAyMDAwMDAwWjAKBggqhQMHAQEDAwOBgQA6E/t67NtVYO72
|
||||
E3z8XdZGkXMuv7NpCh/Ax+ik7uoIMH1kjU3AmGxGqHs/vkx69C6jQ1nHlZVMo5/z
|
||||
q77ZBR9NL4b6YKCBCRoj3XleHjxonuUSo8gu4NzCZDx47qj8rNNUklWEhrIPHJ7B
|
||||
l8kGmYUCYMk7y82cXDMX4ZNE4XOuNg==
|
||||
""",
|
||||
)
|
||||
@ -1,101 +0,0 @@
|
||||
# coding: utf-8
|
||||
# PyGOST -- Pure Python GOST cryptographic functions library
|
||||
# Copyright (C) 2015-2023 Sergey Matveev <stargrave@stargrave.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, version 3 of the License.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from codecs import getdecoder
|
||||
from codecs import getencoder
|
||||
from sys import version_info
|
||||
|
||||
|
||||
xrange = range if version_info[0] == 3 else xrange
|
||||
|
||||
|
||||
def strxor(a, b):
|
||||
"""XOR of two strings
|
||||
|
||||
This function will process only shortest length of both strings,
|
||||
ignoring remaining one.
|
||||
"""
|
||||
mlen = min(len(a), len(b))
|
||||
a, b, xor = bytearray(a), bytearray(b), bytearray(mlen)
|
||||
for i in xrange(mlen):
|
||||
xor[i] = a[i] ^ b[i]
|
||||
return bytes(xor)
|
||||
|
||||
|
||||
_hexdecoder = getdecoder("hex")
|
||||
_hexencoder = getencoder("hex")
|
||||
|
||||
|
||||
def hexdec(data):
|
||||
"""Decode hexadecimal
|
||||
"""
|
||||
return _hexdecoder(data)[0]
|
||||
|
||||
|
||||
def hexenc(data):
|
||||
"""Encode hexadecimal
|
||||
"""
|
||||
return _hexencoder(data)[0].decode("ascii")
|
||||
|
||||
|
||||
def bytes2long(raw):
|
||||
"""Deserialize big-endian bytes into long number
|
||||
|
||||
:param bytes raw: binary string
|
||||
:returns: deserialized long number
|
||||
:rtype: int
|
||||
"""
|
||||
return int(hexenc(raw), 16)
|
||||
|
||||
|
||||
def long2bytes(n, size=32):
|
||||
"""Serialize long number into big-endian bytestring
|
||||
|
||||
:param long n: long number
|
||||
:returns: serialized bytestring
|
||||
:rtype: bytes
|
||||
"""
|
||||
res = hex(int(n))[2:].rstrip("L")
|
||||
if len(res) % 2 != 0:
|
||||
res = "0" + res
|
||||
s = hexdec(res)
|
||||
if len(s) != size:
|
||||
s = (size - len(s)) * b"\x00" + s
|
||||
return s
|
||||
|
||||
|
||||
def modinvert(a, n):
|
||||
"""Modular multiplicative inverse
|
||||
|
||||
:returns: inverse number. -1 if it does not exist
|
||||
|
||||
Realization is taken from:
|
||||
https://en.wikipedia.org/wiki/Extended_Euclidean_algorithm
|
||||
"""
|
||||
if a < 0:
|
||||
# k^-1 = p - (-k)^-1 mod p
|
||||
return n - modinvert(-a, n)
|
||||
t, newt = 0, 1
|
||||
r, newr = n, a
|
||||
while newr != 0:
|
||||
quotinent = r // newr
|
||||
t, newt = newt, t - quotinent * newt
|
||||
r, newr = newr, r - quotinent * newr
|
||||
if r > 1:
|
||||
return -1
|
||||
if t < 0:
|
||||
t = t + n
|
||||
return t
|
||||
@ -1,152 +0,0 @@
|
||||
# coding: utf-8
|
||||
# PyGOST -- Pure Python GOST cryptographic functions library
|
||||
# Copyright (C) 2015-2023 Sergey Matveev <stargrave@stargrave.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, version 3 of the License.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
"""Key wrap.
|
||||
|
||||
:rfc:`4357` key wrapping (28147-89 and CryptoPro).
|
||||
"""
|
||||
|
||||
from hmac import compare_digest
|
||||
from struct import pack
|
||||
from struct import unpack
|
||||
|
||||
from pygost.gost28147 import cfb_encrypt
|
||||
from pygost.gost28147 import DEFAULT_SBOX
|
||||
from pygost.gost28147 import ecb_decrypt
|
||||
from pygost.gost28147 import ecb_encrypt
|
||||
from pygost.gost28147_mac import MAC
|
||||
from pygost.gost3413 import ctr
|
||||
from pygost.gost3413 import mac
|
||||
|
||||
|
||||
def wrap_gost(ukm, kek, cek, sbox=DEFAULT_SBOX):
|
||||
"""28147-89 key wrapping
|
||||
|
||||
:param ukm: UKM
|
||||
:type ukm: bytes, 8 bytes
|
||||
:param kek: key encryption key
|
||||
:type kek: bytes, 32 bytes
|
||||
:param cek: content encryption key
|
||||
:type cek: bytes, 32 bytes
|
||||
:returns: wrapped key
|
||||
:rtype: bytes, 44 bytes
|
||||
"""
|
||||
cek_mac = MAC(kek, data=cek, iv=ukm, sbox=sbox).digest()[:4]
|
||||
cek_enc = ecb_encrypt(kek, cek, sbox=sbox)
|
||||
return ukm + cek_enc + cek_mac
|
||||
|
||||
|
||||
def unwrap_gost(kek, data, sbox=DEFAULT_SBOX):
|
||||
"""28147-89 key unwrapping
|
||||
|
||||
:param kek: key encryption key
|
||||
:type kek: bytes, 32 bytes
|
||||
:param data: wrapped key
|
||||
:type data: bytes, 44 bytes
|
||||
:returns: unwrapped CEK
|
||||
:rtype: 32 bytes
|
||||
"""
|
||||
if len(data) != 44:
|
||||
raise ValueError("Invalid data length")
|
||||
ukm, cek_enc, cek_mac = data[:8], data[8:8 + 32], data[-4:]
|
||||
cek = ecb_decrypt(kek, cek_enc, sbox=sbox)
|
||||
if MAC(kek, data=cek, iv=ukm, sbox=sbox).digest()[:4] != cek_mac:
|
||||
raise ValueError("Invalid MAC")
|
||||
return cek
|
||||
|
||||
|
||||
def wrap_cryptopro(ukm, kek, cek, sbox=DEFAULT_SBOX):
|
||||
"""CryptoPro key wrapping
|
||||
|
||||
:param ukm: UKM
|
||||
:type ukm: bytes, 8 bytes
|
||||
:param kek: key encryption key
|
||||
:type kek: bytes, 32 bytes
|
||||
:param cek: content encryption key
|
||||
:type cek: bytes, 32 bytes
|
||||
:returns: wrapped key
|
||||
:rtype: bytes, 44 bytes
|
||||
"""
|
||||
return wrap_gost(
|
||||
ukm,
|
||||
diversify(kek, bytearray(ukm), sbox=sbox),
|
||||
cek,
|
||||
sbox=sbox,
|
||||
)
|
||||
|
||||
|
||||
def unwrap_cryptopro(kek, data, sbox=DEFAULT_SBOX):
|
||||
"""CryptoPro key unwrapping
|
||||
|
||||
:param kek: key encryption key
|
||||
:type kek: bytes, 32 bytes
|
||||
:param data: wrapped key
|
||||
:type data: bytes, 44 bytes
|
||||
:returns: unwrapped CEK
|
||||
:rtype: 32 bytes
|
||||
"""
|
||||
if len(data) < 8:
|
||||
raise ValueError("Invalid data length")
|
||||
return unwrap_gost(
|
||||
diversify(kek, bytearray(data[:8]), sbox=sbox),
|
||||
data,
|
||||
sbox=sbox,
|
||||
)
|
||||
|
||||
|
||||
def diversify(kek, ukm, sbox=DEFAULT_SBOX):
|
||||
out = kek
|
||||
for i in range(8):
|
||||
s1, s2 = 0, 0
|
||||
for j in range(8):
|
||||
k, = unpack("<i", out[j * 4:j * 4 + 4])
|
||||
if (ukm[i] >> j) & 1:
|
||||
s1 += k
|
||||
else:
|
||||
s2 += k
|
||||
iv = pack("<I", s1 % 2 ** 32) + pack("<I", s2 % 2 ** 32)
|
||||
out = cfb_encrypt(out, out, iv=iv, sbox=sbox)
|
||||
return out
|
||||
|
||||
|
||||
def kexp15(encrypter_key, encrypter_mac, bs, key, iv):
|
||||
"""KExp15 key exporting
|
||||
|
||||
:param encrypter_key: encrypting function for key encryption,
|
||||
that takes block as an input
|
||||
:param encrypter_mac: encrypting function for key authentication
|
||||
:param int bs: cipher's blocksize, bytes
|
||||
:param bytes key: key to export
|
||||
:param bytes iv: half blocksize-sized initialization vector
|
||||
"""
|
||||
key_mac = mac(encrypter_mac, bs, iv + key)
|
||||
return ctr(encrypter_key, bs, key + key_mac, iv)
|
||||
|
||||
|
||||
def kimp15(encrypter_key, encrypter_mac, bs, kexp, iv):
|
||||
"""KImp15 key importing
|
||||
|
||||
:param encrypter_key: encrypting function for key decryption,
|
||||
that takes block as an input
|
||||
:param encrypter_mac: encrypting function for key authentication
|
||||
:param int bs: cipher's blocksize, bytes
|
||||
:param bytes kexp: key to import
|
||||
:param bytes iv: half blocksize-sized initialization vector
|
||||
"""
|
||||
key_and_key_mac = ctr(encrypter_key, bs, kexp, iv)
|
||||
key, key_mac = key_and_key_mac[:-bs], key_and_key_mac[-bs:]
|
||||
if not compare_digest(mac(encrypter_mac, bs, iv + key), key_mac):
|
||||
raise ValueError("Invalid authentication tag")
|
||||
return key
|
||||
BIN
pygost-5.13/dist/pygost-5.13-py3.12.egg
vendored
BIN
pygost-5.13/dist/pygost-5.13-py3.12.egg
vendored
Binary file not shown.
@ -1,93 +0,0 @@
|
||||
Metadata-Version: 2.1
|
||||
Name: pygost
|
||||
Version: 5.13
|
||||
Summary: Pure Python GOST cryptographic functions library
|
||||
Home-page: http://www.pygost.cypherpunks.ru/
|
||||
Author: Sergey Matveev
|
||||
Author-email: stargrave@stargrave.org
|
||||
License: GPLv3
|
||||
Classifier: Development Status :: 5 - Production/Stable
|
||||
Classifier: Intended Audience :: Developers
|
||||
Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
|
||||
Classifier: Natural Language :: English
|
||||
Classifier: Operating System :: OS Independent
|
||||
Classifier: Programming Language :: Python :: 2
|
||||
Classifier: Programming Language :: Python :: 3
|
||||
Classifier: Topic :: Security :: Cryptography
|
||||
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
||||
License-File: COPYING
|
||||
License-File: AUTHORS
|
||||
|
||||
Pure Python 2.7/3.x GOST cryptographic functions library.
|
||||
|
||||
GOST is GOvernment STandard of Russian Federation (and Soviet Union).
|
||||
|
||||
* GOST 28147-89 (RFC 5830) block cipher with ECB, CNT (CTR), CFB, MAC,
|
||||
CBC (RFC 4357) modes of operation
|
||||
* various 28147-89-related S-boxes included
|
||||
* GOST R 34.11-94 hash function (RFC 5831)
|
||||
* GOST R 34.11-94 based PBKDF2 function
|
||||
* GOST R 34.11-2012 Стрибог (Streebog) hash function (RFC 6986)
|
||||
* GOST R 34.11-2012 based PBKDF2 function (Р 50.1.111-2016)
|
||||
* GOST R 34.10-2001 (RFC 5832) public key signature function
|
||||
* GOST R 34.10-2012 (RFC 7091) public key signature function
|
||||
* various 34.10 curve parameters included
|
||||
* Coordinates conversion from twisted Edwards to Weierstrass form and
|
||||
vice versa
|
||||
* VKO GOST R 34.10-2001 key agreement function (RFC 4357)
|
||||
* VKO GOST R 34.10-2012 key agreement function (RFC 7836)
|
||||
* 28147-89 and CryptoPro key wrapping (RFC 4357)
|
||||
* 28147-89 CryptoPro key meshing for CFB and CBC modes (RFC 4357)
|
||||
* RFC 4491 (using GOST algorithms with X.509) compatibility helpers
|
||||
* GOST R 34.12-2015 128-bit block cipher Кузнечик (Kuznechik) (RFC 7801)
|
||||
* GOST R 34.12-2015 64-bit block cipher Магма (Magma)
|
||||
* GOST R 34.13-2015 padding methods and block cipher modes of operation
|
||||
(ECB, CTR, OFB, CBC, CFB, MAC), ISO 10126 padding
|
||||
* MGM AEAD mode for 64 and 128 bit ciphers (RFC 9058)
|
||||
* CTR-ACPKM, OMAC-ACPKM-Master modes of operation (Р 1323565.1.017-2018)
|
||||
* KExp15/KImp15 key export/import functions (Р 1323565.1.017-2018)
|
||||
* KDF_GOSTR3411_2012_256, KDF_TREE_GOSTR3411_2012_256 (Р 50.1.113-2016)
|
||||
* KEG export key generation function (Р 1323565.1.020-2018)
|
||||
* PEP247-compatible hash/MAC functions
|
||||
|
||||
Known problems: low performance and non time-constant calculations.
|
||||
|
||||
Example 34.10-2012 keypair generation, signing and verifying:
|
||||
|
||||
>>> from pygost.gost3410 import CURVES
|
||||
>>> curve = CURVES["id-tc26-gost-3410-12-512-paramSetA"]
|
||||
>>> from os import urandom
|
||||
>>> prv_raw = urandom(64)
|
||||
>>> from pygost.gost3410 import prv_unmarshal
|
||||
>>> from pygost.gost3410 import prv_marshal
|
||||
>>> prv = prv_unmarshal(prv_raw)
|
||||
>>> prv_raw = prv_marshal(curve, prv)
|
||||
>>> from pygost.gost3410 import public_key
|
||||
>>> pub = public_key(curve, prv)
|
||||
>>> from pygost.gost3410 import pub_marshal
|
||||
>>> from pygost.utils import hexenc
|
||||
>>> print "Public key is:", hexenc(pub_marshal(pub))
|
||||
>>> from pygost import gost34112012512
|
||||
>>> data_for_signing = b"some data"
|
||||
>>> dgst = gost34112012512.new(data_for_signing).digest()
|
||||
>>> from pygost.gost3410 import sign
|
||||
>>> signature = sign(curve, prv, dgst)
|
||||
>>> from pygost.gost3410 import verify
|
||||
>>> verify(curve, pub, dgst, signature)
|
||||
True
|
||||
|
||||
Other examples can be found in docstrings and unittests.
|
||||
Example self-signed X.509 certificate creation can be found in
|
||||
pygost/asn1schemas/cert-selfsigned-example.py.
|
||||
|
||||
PyGOST is free software: see the file COPYING for copying conditions.
|
||||
|
||||
PyGOST'es home page is: http://www.pygost.cypherpunks.ru/
|
||||
You can read about GOST algorithms more: http://www.gost.cypherpunks.ru/
|
||||
|
||||
Please send questions, bug reports and patches to
|
||||
http://lists.cypherpunks.ru/gost.html mailing list.
|
||||
Announcements also go to this mailing list.
|
||||
|
||||
Development Git source code repository currently is located here:
|
||||
http://www.git.cypherpunks.ru/?p=pygost.git;a=summary
|
||||
@ -1,71 +0,0 @@
|
||||
AUTHORS
|
||||
COPYING
|
||||
FAQ
|
||||
INSTALL
|
||||
MANIFEST.in
|
||||
NEWS
|
||||
README
|
||||
THANKS
|
||||
VERSION
|
||||
setup.cfg
|
||||
setup.py
|
||||
pygost/__init__.py
|
||||
pygost/gost28147.py
|
||||
pygost/gost28147_mac.py
|
||||
pygost/gost3410.py
|
||||
pygost/gost3410_vko.py
|
||||
pygost/gost34112012.py
|
||||
pygost/gost34112012256.py
|
||||
pygost/gost34112012512.py
|
||||
pygost/gost341194.py
|
||||
pygost/gost3412.py
|
||||
pygost/gost3413.py
|
||||
pygost/iface.py
|
||||
pygost/kdf.py
|
||||
pygost/mgm.py
|
||||
pygost/pbkdf2.py
|
||||
pygost/test_cms.py
|
||||
pygost/test_gost28147.py
|
||||
pygost/test_gost28147_mac.py
|
||||
pygost/test_gost3410.py
|
||||
pygost/test_gost3410_vko.py
|
||||
pygost/test_gost34112012.py
|
||||
pygost/test_gost341194.py
|
||||
pygost/test_gost3412.py
|
||||
pygost/test_gost3413.py
|
||||
pygost/test_kdf.py
|
||||
pygost/test_mgm.py
|
||||
pygost/test_pfx.py
|
||||
pygost/test_wrap.py
|
||||
pygost/test_x509.py
|
||||
pygost/utils.py
|
||||
pygost/wrap.py
|
||||
pygost.egg-info/PKG-INFO
|
||||
pygost.egg-info/SOURCES.txt
|
||||
pygost.egg-info/dependency_links.txt
|
||||
pygost.egg-info/top_level.txt
|
||||
pygost/asn1schemas/__init__.py
|
||||
pygost/asn1schemas/cert-dane-hash.py
|
||||
pygost/asn1schemas/cert-selfsigned-example.py
|
||||
pygost/asn1schemas/cms.py
|
||||
pygost/asn1schemas/oids.py
|
||||
pygost/asn1schemas/pfx.py
|
||||
pygost/asn1schemas/pkcs10.py
|
||||
pygost/asn1schemas/prvkey.py
|
||||
pygost/asn1schemas/x509.py
|
||||
pygost/stubs/pygost/__init__.pyi
|
||||
pygost/stubs/pygost/gost28147.pyi
|
||||
pygost/stubs/pygost/gost28147_mac.pyi
|
||||
pygost/stubs/pygost/gost3410.pyi
|
||||
pygost/stubs/pygost/gost3410_vko.pyi
|
||||
pygost/stubs/pygost/gost34112012.pyi
|
||||
pygost/stubs/pygost/gost34112012256.pyi
|
||||
pygost/stubs/pygost/gost34112012512.pyi
|
||||
pygost/stubs/pygost/gost341194.pyi
|
||||
pygost/stubs/pygost/gost3412.pyi
|
||||
pygost/stubs/pygost/gost3413.pyi
|
||||
pygost/stubs/pygost/iface.pyi
|
||||
pygost/stubs/pygost/kdf.pyi
|
||||
pygost/stubs/pygost/mgm.pyi
|
||||
pygost/stubs/pygost/utils.pyi
|
||||
pygost/stubs/pygost/wrap.pyi
|
||||
@ -1 +0,0 @@
|
||||
|
||||
@ -1 +0,0 @@
|
||||
pygost
|
||||
@ -1,6 +0,0 @@
|
||||
"""Pure Python GOST cryptographic functions library.
|
||||
|
||||
PyGOST is free software: see the file COPYING for copying conditions.
|
||||
"""
|
||||
|
||||
__version__ = "5.13"
|
||||
@ -1,18 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
"""DANE's SPKI hash calculator
|
||||
"""
|
||||
|
||||
from base64 import standard_b64decode
|
||||
from hashlib import sha256
|
||||
import sys
|
||||
|
||||
from pygost.asn1schemas.x509 import Certificate
|
||||
|
||||
|
||||
lines = sys.stdin.read().split("-----")
|
||||
idx = lines.index("BEGIN CERTIFICATE")
|
||||
if idx == -1:
|
||||
raise ValueError("PEM has no CERTIFICATE")
|
||||
cert_raw = standard_b64decode(lines[idx + 1])
|
||||
cert = Certificate().decod(cert_raw)
|
||||
print(sha256(cert["tbsCertificate"]["subjectPublicKeyInfo"].encode()).hexdigest())
|
||||
@ -1,348 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Create example self-signed X.509 certificate
|
||||
"""
|
||||
|
||||
from argparse import ArgumentParser
|
||||
from base64 import standard_b64decode
|
||||
from base64 import standard_b64encode
|
||||
from datetime import datetime
|
||||
from datetime import timedelta
|
||||
from os import urandom
|
||||
from sys import exit as sys_exit
|
||||
from sys import stdout
|
||||
from textwrap import fill
|
||||
|
||||
from pyderasn import Any
|
||||
from pyderasn import BitString
|
||||
from pyderasn import Boolean
|
||||
from pyderasn import IA5String
|
||||
from pyderasn import Integer
|
||||
from pyderasn import OctetString
|
||||
from pyderasn import PrintableString
|
||||
from pyderasn import UTCTime
|
||||
|
||||
from pygost.asn1schemas.oids import id_at_commonName
|
||||
from pygost.asn1schemas.oids import id_at_countryName
|
||||
from pygost.asn1schemas.oids import id_ce_authorityKeyIdentifier
|
||||
from pygost.asn1schemas.oids import id_ce_basicConstraints
|
||||
from pygost.asn1schemas.oids import id_ce_keyUsage
|
||||
from pygost.asn1schemas.oids import id_ce_subjectAltName
|
||||
from pygost.asn1schemas.oids import id_ce_subjectKeyIdentifier
|
||||
from pygost.asn1schemas.oids import id_tc26_gost3410_2012_256
|
||||
from pygost.asn1schemas.oids import id_tc26_gost3410_2012_256_paramSetA
|
||||
from pygost.asn1schemas.oids import id_tc26_gost3410_2012_256_paramSetB
|
||||
from pygost.asn1schemas.oids import id_tc26_gost3410_2012_256_paramSetC
|
||||
from pygost.asn1schemas.oids import id_tc26_gost3410_2012_256_paramSetD
|
||||
from pygost.asn1schemas.oids import id_tc26_gost3410_2012_512
|
||||
from pygost.asn1schemas.oids import id_tc26_gost3410_2012_512_paramSetA
|
||||
from pygost.asn1schemas.oids import id_tc26_gost3410_2012_512_paramSetB
|
||||
from pygost.asn1schemas.oids import id_tc26_gost3410_2012_512_paramSetC
|
||||
from pygost.asn1schemas.oids import id_tc26_signwithdigest_gost3410_2012_256
|
||||
from pygost.asn1schemas.oids import id_tc26_signwithdigest_gost3410_2012_512
|
||||
from pygost.asn1schemas.prvkey import PrivateKey
|
||||
from pygost.asn1schemas.prvkey import PrivateKeyAlgorithmIdentifier
|
||||
from pygost.asn1schemas.prvkey import PrivateKeyInfo
|
||||
from pygost.asn1schemas.x509 import AlgorithmIdentifier
|
||||
from pygost.asn1schemas.x509 import AttributeType
|
||||
from pygost.asn1schemas.x509 import AttributeTypeAndValue
|
||||
from pygost.asn1schemas.x509 import AttributeValue
|
||||
from pygost.asn1schemas.x509 import AuthorityKeyIdentifier
|
||||
from pygost.asn1schemas.x509 import BasicConstraints
|
||||
from pygost.asn1schemas.x509 import Certificate
|
||||
from pygost.asn1schemas.x509 import CertificateSerialNumber
|
||||
from pygost.asn1schemas.x509 import Extension
|
||||
from pygost.asn1schemas.x509 import Extensions
|
||||
from pygost.asn1schemas.x509 import GeneralName
|
||||
from pygost.asn1schemas.x509 import GostR34102012PublicKeyParameters
|
||||
from pygost.asn1schemas.x509 import KeyIdentifier
|
||||
from pygost.asn1schemas.x509 import KeyUsage
|
||||
from pygost.asn1schemas.x509 import Name
|
||||
from pygost.asn1schemas.x509 import RDNSequence
|
||||
from pygost.asn1schemas.x509 import RelativeDistinguishedName
|
||||
from pygost.asn1schemas.x509 import SubjectAltName
|
||||
from pygost.asn1schemas.x509 import SubjectKeyIdentifier
|
||||
from pygost.asn1schemas.x509 import SubjectPublicKeyInfo
|
||||
from pygost.asn1schemas.x509 import TBSCertificate
|
||||
from pygost.asn1schemas.x509 import Time
|
||||
from pygost.asn1schemas.x509 import Validity
|
||||
from pygost.asn1schemas.x509 import Version
|
||||
from pygost.gost3410 import CURVES
|
||||
from pygost.gost3410 import prv_unmarshal
|
||||
from pygost.gost3410 import pub_marshal
|
||||
from pygost.gost3410 import public_key
|
||||
from pygost.gost3410 import sign
|
||||
from pygost.gost34112012256 import GOST34112012256
|
||||
from pygost.gost34112012512 import GOST34112012512
|
||||
from pygost.utils import bytes2long
|
||||
|
||||
parser = ArgumentParser(description="Self-signed X.509 certificate creator")
|
||||
parser.add_argument(
|
||||
"--ca",
|
||||
action="store_true",
|
||||
help="Enable BasicConstraints.cA",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--cn",
|
||||
required=True,
|
||||
help="Subject's CommonName",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--country",
|
||||
help="Subject's Country",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--serial",
|
||||
help="Serial number",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--ai",
|
||||
required=True,
|
||||
help="Signing algorithm: {256[ABCD],512[ABC]}",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--issue-with",
|
||||
help="Path to PEM with CA to issue the child",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--reuse-key",
|
||||
help="Path to PEM with the key to reuse",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--out-key",
|
||||
help="Path to PEM with the resulting key",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--only-key",
|
||||
action="store_true",
|
||||
help="Only generate the key",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--out-cert",
|
||||
help="Path to PEM with the resulting certificate",
|
||||
)
|
||||
args = parser.parse_args()
|
||||
AIs = {
|
||||
"256A": {
|
||||
"publicKeyParamSet": id_tc26_gost3410_2012_256_paramSetA,
|
||||
"key_algorithm": id_tc26_gost3410_2012_256,
|
||||
"prv_len": 32,
|
||||
"curve": CURVES["id-tc26-gost-3410-2012-256-paramSetA"],
|
||||
"sign_algorithm": id_tc26_signwithdigest_gost3410_2012_256,
|
||||
"hasher": GOST34112012256,
|
||||
},
|
||||
"256B": {
|
||||
"publicKeyParamSet": id_tc26_gost3410_2012_256_paramSetB,
|
||||
"key_algorithm": id_tc26_gost3410_2012_256,
|
||||
"prv_len": 32,
|
||||
"curve": CURVES["id-tc26-gost-3410-2012-256-paramSetB"],
|
||||
"sign_algorithm": id_tc26_signwithdigest_gost3410_2012_256,
|
||||
"hasher": GOST34112012256,
|
||||
},
|
||||
"256C": {
|
||||
"publicKeyParamSet": id_tc26_gost3410_2012_256_paramSetC,
|
||||
"key_algorithm": id_tc26_gost3410_2012_256,
|
||||
"prv_len": 32,
|
||||
"curve": CURVES["id-tc26-gost-3410-2012-256-paramSetC"],
|
||||
"sign_algorithm": id_tc26_signwithdigest_gost3410_2012_256,
|
||||
"hasher": GOST34112012256,
|
||||
},
|
||||
"256D": {
|
||||
"publicKeyParamSet": id_tc26_gost3410_2012_256_paramSetD,
|
||||
"key_algorithm": id_tc26_gost3410_2012_256,
|
||||
"prv_len": 32,
|
||||
"curve": CURVES["id-tc26-gost-3410-2012-256-paramSetD"],
|
||||
"sign_algorithm": id_tc26_signwithdigest_gost3410_2012_256,
|
||||
"hasher": GOST34112012256,
|
||||
},
|
||||
"512A": {
|
||||
"publicKeyParamSet": id_tc26_gost3410_2012_512_paramSetA,
|
||||
"key_algorithm": id_tc26_gost3410_2012_512,
|
||||
"prv_len": 64,
|
||||
"curve": CURVES["id-tc26-gost-3410-12-512-paramSetA"],
|
||||
"sign_algorithm": id_tc26_signwithdigest_gost3410_2012_512,
|
||||
"hasher": GOST34112012512,
|
||||
},
|
||||
"512B": {
|
||||
"publicKeyParamSet": id_tc26_gost3410_2012_512_paramSetB,
|
||||
"key_algorithm": id_tc26_gost3410_2012_512,
|
||||
"prv_len": 64,
|
||||
"curve": CURVES["id-tc26-gost-3410-12-512-paramSetB"],
|
||||
"sign_algorithm": id_tc26_signwithdigest_gost3410_2012_512,
|
||||
"hasher": GOST34112012512,
|
||||
},
|
||||
"512C": {
|
||||
"publicKeyParamSet": id_tc26_gost3410_2012_512_paramSetC,
|
||||
"key_algorithm": id_tc26_gost3410_2012_512,
|
||||
"prv_len": 64,
|
||||
"curve": CURVES["id-tc26-gost-3410-2012-512-paramSetC"],
|
||||
"sign_algorithm": id_tc26_signwithdigest_gost3410_2012_512,
|
||||
"hasher": GOST34112012512,
|
||||
},
|
||||
}
|
||||
ai = AIs[args.ai]
|
||||
|
||||
ca_prv = None
|
||||
ca_cert = None
|
||||
ca_subj = None
|
||||
ca_ai = None
|
||||
if args.issue_with is not None:
|
||||
with open(args.issue_with, "rb") as fd:
|
||||
lines = fd.read().decode("ascii").split("-----")
|
||||
idx = lines.index("BEGIN PRIVATE KEY")
|
||||
if idx == -1:
|
||||
raise ValueError("PEM has no PRIVATE KEY")
|
||||
prv_raw = standard_b64decode(lines[idx + 1])
|
||||
idx = lines.index("BEGIN CERTIFICATE")
|
||||
if idx == -1:
|
||||
raise ValueError("PEM has no CERTIFICATE")
|
||||
cert_raw = standard_b64decode(lines[idx + 1])
|
||||
pki = PrivateKeyInfo().decod(prv_raw)
|
||||
ca_prv = prv_unmarshal(bytes(OctetString().decod(bytes(pki["privateKey"]))))
|
||||
ca_cert = Certificate().decod(cert_raw)
|
||||
tbs = ca_cert["tbsCertificate"]
|
||||
ca_subj = tbs["subject"]
|
||||
curve_oid = GostR34102012PublicKeyParameters().decod(bytes(
|
||||
tbs["subjectPublicKeyInfo"]["algorithm"]["parameters"]
|
||||
))["publicKeyParamSet"]
|
||||
ca_ai = next(iter([
|
||||
params for params in AIs.values()
|
||||
if params["publicKeyParamSet"] == curve_oid
|
||||
]))
|
||||
|
||||
key_params = GostR34102012PublicKeyParameters((
|
||||
("publicKeyParamSet", ai["publicKeyParamSet"]),
|
||||
))
|
||||
|
||||
|
||||
def pem(obj):
|
||||
return fill(standard_b64encode(obj.encode()).decode("ascii"), 64)
|
||||
|
||||
|
||||
if args.reuse_key is not None:
|
||||
with open(args.reuse_key, "rb") as fd:
|
||||
lines = fd.read().decode("ascii").split("-----")
|
||||
idx = lines.index("BEGIN PRIVATE KEY")
|
||||
if idx == -1:
|
||||
raise ValueError("PEM has no PRIVATE KEY")
|
||||
prv_raw = standard_b64decode(lines[idx + 1])
|
||||
pki = PrivateKeyInfo().decod(prv_raw)
|
||||
prv = prv_unmarshal(bytes(OctetString().decod(bytes(pki["privateKey"]))))
|
||||
else:
|
||||
prv_raw = urandom(ai["prv_len"])
|
||||
out = stdout if args.out_key is None else open(args.out_key, "w")
|
||||
print("-----BEGIN PRIVATE KEY-----", file=out)
|
||||
print(pem(PrivateKeyInfo((
|
||||
("version", Integer(0)),
|
||||
("privateKeyAlgorithm", PrivateKeyAlgorithmIdentifier((
|
||||
("algorithm", ai["key_algorithm"]),
|
||||
("parameters", Any(key_params)),
|
||||
))),
|
||||
("privateKey", PrivateKey(OctetString(prv_raw).encode())),
|
||||
))), file=out)
|
||||
print("-----END PRIVATE KEY-----", file=out)
|
||||
if args.only_key:
|
||||
sys_exit()
|
||||
prv = prv_unmarshal(prv_raw)
|
||||
|
||||
curve = ai["curve"]
|
||||
pub_raw = pub_marshal(public_key(curve, prv))
|
||||
rdn = [RelativeDistinguishedName((
|
||||
AttributeTypeAndValue((
|
||||
("type", AttributeType(id_at_commonName)),
|
||||
("value", AttributeValue(PrintableString(args.cn))),
|
||||
)),
|
||||
))]
|
||||
if args.country:
|
||||
rdn.append(RelativeDistinguishedName((
|
||||
AttributeTypeAndValue((
|
||||
("type", AttributeType(id_at_countryName)),
|
||||
("value", AttributeValue(PrintableString(args.country))),
|
||||
)),
|
||||
)))
|
||||
subj = Name(("rdnSequence", RDNSequence(rdn)))
|
||||
not_before = datetime.utcnow()
|
||||
not_after = not_before + timedelta(days=365 * (10 if args.ca else 1))
|
||||
ai_sign = AlgorithmIdentifier((
|
||||
("algorithm", (ai if ca_ai is None else ca_ai)["sign_algorithm"]),
|
||||
))
|
||||
exts = [
|
||||
Extension((
|
||||
("extnID", id_ce_subjectKeyIdentifier),
|
||||
("extnValue", OctetString(
|
||||
SubjectKeyIdentifier(GOST34112012256(pub_raw).digest()[:20]).encode()
|
||||
)),
|
||||
)),
|
||||
Extension((
|
||||
("extnID", id_ce_keyUsage),
|
||||
("critical", Boolean(True)),
|
||||
("extnValue", OctetString(KeyUsage(
|
||||
("keyCertSign" if args.ca else "digitalSignature",),
|
||||
).encode())),
|
||||
)),
|
||||
]
|
||||
if args.ca:
|
||||
exts.append(Extension((
|
||||
("extnID", id_ce_basicConstraints),
|
||||
("critical", Boolean(True)),
|
||||
("extnValue", OctetString(BasicConstraints((
|
||||
("cA", Boolean(True)),
|
||||
)).encode())),
|
||||
)))
|
||||
else:
|
||||
exts.append(Extension((
|
||||
("extnID", id_ce_subjectAltName),
|
||||
("extnValue", OctetString(
|
||||
SubjectAltName((
|
||||
GeneralName(("dNSName", IA5String(args.cn))),
|
||||
)).encode()
|
||||
)),
|
||||
)))
|
||||
if ca_ai is not None:
|
||||
caKeyId = [
|
||||
bytes(SubjectKeyIdentifier().decod(bytes(ext["extnValue"])))
|
||||
for ext in ca_cert["tbsCertificate"]["extensions"]
|
||||
if ext["extnID"] == id_ce_subjectKeyIdentifier
|
||||
][0]
|
||||
exts.append(Extension((
|
||||
("extnID", id_ce_authorityKeyIdentifier),
|
||||
("extnValue", OctetString(AuthorityKeyIdentifier((
|
||||
("keyIdentifier", KeyIdentifier(caKeyId)),
|
||||
)).encode())),
|
||||
)))
|
||||
|
||||
serial = (
|
||||
bytes2long(GOST34112012256(urandom(16)).digest()[:20])
|
||||
if args.serial is None else int(args.serial)
|
||||
)
|
||||
tbs = TBSCertificate((
|
||||
("version", Version("v3")),
|
||||
("serialNumber", CertificateSerialNumber(serial)),
|
||||
("signature", ai_sign),
|
||||
("issuer", subj if ca_ai is None else ca_subj),
|
||||
("validity", Validity((
|
||||
("notBefore", Time(("utcTime", UTCTime(not_before)))),
|
||||
("notAfter", Time(("utcTime", UTCTime(not_after)))),
|
||||
))),
|
||||
("subject", subj),
|
||||
("subjectPublicKeyInfo", SubjectPublicKeyInfo((
|
||||
("algorithm", AlgorithmIdentifier((
|
||||
("algorithm", ai["key_algorithm"]),
|
||||
("parameters", Any(key_params)),
|
||||
))),
|
||||
("subjectPublicKey", BitString(OctetString(pub_raw).encode())),
|
||||
))),
|
||||
("extensions", Extensions(exts)),
|
||||
))
|
||||
cert = Certificate((
|
||||
("tbsCertificate", tbs),
|
||||
("signatureAlgorithm", ai_sign),
|
||||
("signatureValue", BitString(
|
||||
sign(curve, prv, ai["hasher"](tbs.encode()).digest()[::-1])
|
||||
if ca_ai is None else
|
||||
sign(ca_ai["curve"], ca_prv, ca_ai["hasher"](tbs.encode()).digest()[::-1])
|
||||
)),
|
||||
))
|
||||
out = stdout if args.out_cert is None else open(args.out_cert, "w")
|
||||
print("-----BEGIN CERTIFICATE-----", file=out)
|
||||
print(pem(cert), file=out)
|
||||
print("-----END CERTIFICATE-----", file=out)
|
||||
@ -1,431 +0,0 @@
|
||||
# coding: utf-8
|
||||
# PyGOST -- Pure Python GOST cryptographic functions library
|
||||
# Copyright (C) 2015-2023 Sergey Matveev <stargrave@stargrave.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, version 3 of the License.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
"""CMS related structures (**NOT COMPLETE**)
|
||||
"""
|
||||
|
||||
from pyderasn import Any
|
||||
from pyderasn import BitString
|
||||
from pyderasn import Choice
|
||||
from pyderasn import Integer
|
||||
from pyderasn import ObjectIdentifier
|
||||
from pyderasn import OctetString
|
||||
from pyderasn import Sequence
|
||||
from pyderasn import SequenceOf
|
||||
from pyderasn import SetOf
|
||||
from pyderasn import tag_ctxc
|
||||
from pyderasn import tag_ctxp
|
||||
|
||||
from pygost.asn1schemas.oids import id_cms_mac_attr
|
||||
from pygost.asn1schemas.oids import id_contentType
|
||||
from pygost.asn1schemas.oids import id_digestedData
|
||||
from pygost.asn1schemas.oids import id_encryptedData
|
||||
from pygost.asn1schemas.oids import id_envelopedData
|
||||
from pygost.asn1schemas.oids import id_Gost28147_89
|
||||
from pygost.asn1schemas.oids import id_gostr3412_2015_kuznyechik_ctracpkm
|
||||
from pygost.asn1schemas.oids import id_gostr3412_2015_kuznyechik_ctracpkm_omac
|
||||
from pygost.asn1schemas.oids import id_gostr3412_2015_kuznyechik_wrap_kexp15
|
||||
from pygost.asn1schemas.oids import id_gostr3412_2015_magma_ctracpkm
|
||||
from pygost.asn1schemas.oids import id_gostr3412_2015_magma_ctracpkm_omac
|
||||
from pygost.asn1schemas.oids import id_gostr3412_2015_magma_wrap_kexp15
|
||||
from pygost.asn1schemas.oids import id_messageDigest
|
||||
from pygost.asn1schemas.oids import id_signedData
|
||||
from pygost.asn1schemas.oids import id_tc26_gost3410_2012_256
|
||||
from pygost.asn1schemas.oids import id_tc26_gost3410_2012_512
|
||||
from pygost.asn1schemas.x509 import AlgorithmIdentifier
|
||||
from pygost.asn1schemas.x509 import Certificate
|
||||
from pygost.asn1schemas.x509 import CertificateSerialNumber
|
||||
from pygost.asn1schemas.x509 import Name
|
||||
from pygost.asn1schemas.x509 import SubjectPublicKeyInfo
|
||||
|
||||
|
||||
class CMSVersion(Integer):
|
||||
pass
|
||||
|
||||
|
||||
class ContentType(ObjectIdentifier):
|
||||
pass
|
||||
|
||||
|
||||
class IssuerAndSerialNumber(Sequence):
|
||||
schema = (
|
||||
("issuer", Name()),
|
||||
("serialNumber", CertificateSerialNumber()),
|
||||
)
|
||||
|
||||
|
||||
class KeyIdentifier(OctetString):
|
||||
pass
|
||||
|
||||
|
||||
class SubjectKeyIdentifier(KeyIdentifier):
|
||||
pass
|
||||
|
||||
|
||||
class RecipientIdentifier(Choice):
|
||||
schema = (
|
||||
("issuerAndSerialNumber", IssuerAndSerialNumber()),
|
||||
("subjectKeyIdentifier", SubjectKeyIdentifier(impl=tag_ctxp(0))),
|
||||
)
|
||||
|
||||
|
||||
class Gost2814789Key(OctetString):
|
||||
bounds = (32, 32)
|
||||
|
||||
|
||||
class Gost2814789MAC(OctetString):
|
||||
bounds = (4, 4)
|
||||
|
||||
|
||||
class Gost2814789EncryptedKey(Sequence):
|
||||
schema = (
|
||||
("encryptedKey", Gost2814789Key()),
|
||||
("maskKey", Gost2814789Key(impl=tag_ctxp(0), optional=True)),
|
||||
("macKey", Gost2814789MAC()),
|
||||
)
|
||||
|
||||
|
||||
class GostR34102001TransportParameters(Sequence):
|
||||
schema = (
|
||||
("encryptionParamSet", ObjectIdentifier()),
|
||||
("ephemeralPublicKey", SubjectPublicKeyInfo(
|
||||
impl=tag_ctxc(0),
|
||||
optional=True,
|
||||
)),
|
||||
("ukm", OctetString()),
|
||||
)
|
||||
|
||||
|
||||
class GostR3410KeyTransport(Sequence):
|
||||
schema = (
|
||||
("sessionEncryptedKey", Gost2814789EncryptedKey()),
|
||||
("transportParameters", GostR34102001TransportParameters(
|
||||
impl=tag_ctxc(0),
|
||||
optional=True,
|
||||
)),
|
||||
)
|
||||
|
||||
|
||||
class GostR3410KeyTransport2019(Sequence):
|
||||
schema = (
|
||||
("encryptedKey", OctetString()),
|
||||
("ephemeralPublicKey", SubjectPublicKeyInfo()),
|
||||
("ukm", OctetString()),
|
||||
)
|
||||
|
||||
|
||||
class GostR341012KEGParameters(Sequence):
|
||||
schema = (
|
||||
("algorithm", ObjectIdentifier()),
|
||||
)
|
||||
|
||||
|
||||
class KeyEncryptionAlgorithmIdentifier(AlgorithmIdentifier):
|
||||
schema = (
|
||||
("algorithm", ObjectIdentifier(defines=(
|
||||
(("parameters",), {
|
||||
id_gostr3412_2015_magma_wrap_kexp15: GostR341012KEGParameters(),
|
||||
id_gostr3412_2015_kuznyechik_wrap_kexp15: GostR341012KEGParameters(),
|
||||
}),
|
||||
(("..", "encryptedKey"), {
|
||||
id_tc26_gost3410_2012_256: GostR3410KeyTransport(),
|
||||
id_tc26_gost3410_2012_512: GostR3410KeyTransport(),
|
||||
id_gostr3412_2015_magma_wrap_kexp15: GostR3410KeyTransport2019(),
|
||||
id_gostr3412_2015_kuznyechik_wrap_kexp15: GostR3410KeyTransport2019(),
|
||||
}),
|
||||
(("..", "recipientEncryptedKeys", any, "encryptedKey"), {
|
||||
id_tc26_gost3410_2012_256: Gost2814789EncryptedKey(),
|
||||
id_tc26_gost3410_2012_512: Gost2814789EncryptedKey(),
|
||||
}),
|
||||
))),
|
||||
("parameters", Any(optional=True)),
|
||||
)
|
||||
|
||||
|
||||
class EncryptedKey(OctetString):
|
||||
pass
|
||||
|
||||
|
||||
class KeyTransRecipientInfo(Sequence):
|
||||
schema = (
|
||||
("version", CMSVersion()),
|
||||
("rid", RecipientIdentifier()),
|
||||
("keyEncryptionAlgorithm", KeyEncryptionAlgorithmIdentifier()),
|
||||
("encryptedKey", EncryptedKey()),
|
||||
)
|
||||
|
||||
|
||||
class OriginatorPublicKey(Sequence):
|
||||
schema = (
|
||||
("algorithm", AlgorithmIdentifier()),
|
||||
("publicKey", BitString()),
|
||||
)
|
||||
|
||||
|
||||
class OriginatorIdentifierOrKey(Choice):
|
||||
schema = (
|
||||
("issuerAndSerialNumber", IssuerAndSerialNumber()),
|
||||
("subjectKeyIdentifier", SubjectKeyIdentifier(impl=tag_ctxp(0))),
|
||||
("originatorKey", OriginatorPublicKey(impl=tag_ctxc(1))),
|
||||
)
|
||||
|
||||
|
||||
class UserKeyingMaterial(OctetString):
|
||||
pass
|
||||
|
||||
|
||||
class KeyAgreeRecipientIdentifier(Choice):
|
||||
schema = (
|
||||
("issuerAndSerialNumber", IssuerAndSerialNumber()),
|
||||
# ("rKeyId", RecipientKeyIdentifier(impl=tag_ctxc(0))),
|
||||
)
|
||||
|
||||
|
||||
class RecipientEncryptedKey(Sequence):
|
||||
schema = (
|
||||
("rid", KeyAgreeRecipientIdentifier()),
|
||||
("encryptedKey", EncryptedKey()),
|
||||
)
|
||||
|
||||
|
||||
class RecipientEncryptedKeys(SequenceOf):
|
||||
schema = RecipientEncryptedKey()
|
||||
|
||||
|
||||
class KeyAgreeRecipientInfo(Sequence):
|
||||
schema = (
|
||||
("version", CMSVersion(3)),
|
||||
("originator", OriginatorIdentifierOrKey(expl=tag_ctxc(0))),
|
||||
("ukm", UserKeyingMaterial(expl=tag_ctxc(1), optional=True)),
|
||||
("keyEncryptionAlgorithm", KeyEncryptionAlgorithmIdentifier()),
|
||||
("recipientEncryptedKeys", RecipientEncryptedKeys()),
|
||||
)
|
||||
|
||||
|
||||
class RecipientInfo(Choice):
|
||||
schema = (
|
||||
("ktri", KeyTransRecipientInfo()),
|
||||
("kari", KeyAgreeRecipientInfo(impl=tag_ctxc(1))),
|
||||
# ("kekri", KEKRecipientInfo(impl=tag_ctxc(2))),
|
||||
# ("pwri", PasswordRecipientInfo(impl=tag_ctxc(3))),
|
||||
# ("ori", OtherRecipientInfo(impl=tag_ctxc(4))),
|
||||
)
|
||||
|
||||
|
||||
class RecipientInfos(SetOf):
|
||||
schema = RecipientInfo()
|
||||
bounds = (1, float("+inf"))
|
||||
|
||||
|
||||
class Gost2814789IV(OctetString):
|
||||
bounds = (8, 8)
|
||||
|
||||
|
||||
class Gost2814789Parameters(Sequence):
|
||||
schema = (
|
||||
("iv", Gost2814789IV()),
|
||||
("encryptionParamSet", ObjectIdentifier()),
|
||||
)
|
||||
|
||||
|
||||
class Gost341215EncryptionParameters(Sequence):
|
||||
schema = (
|
||||
("ukm", OctetString()),
|
||||
)
|
||||
|
||||
|
||||
class ContentEncryptionAlgorithmIdentifier(AlgorithmIdentifier):
|
||||
schema = (
|
||||
("algorithm", ObjectIdentifier(defines=(
|
||||
(("parameters",), {
|
||||
id_Gost28147_89: Gost2814789Parameters(),
|
||||
id_gostr3412_2015_magma_ctracpkm: Gost341215EncryptionParameters(),
|
||||
id_gostr3412_2015_kuznyechik_ctracpkm: Gost341215EncryptionParameters(),
|
||||
id_gostr3412_2015_magma_ctracpkm_omac: Gost341215EncryptionParameters(),
|
||||
id_gostr3412_2015_kuznyechik_ctracpkm_omac: Gost341215EncryptionParameters(),
|
||||
}),
|
||||
))),
|
||||
("parameters", Any(optional=True)),
|
||||
)
|
||||
|
||||
|
||||
class EncryptedContent(OctetString):
|
||||
pass
|
||||
|
||||
|
||||
class EncryptedContentInfo(Sequence):
|
||||
schema = (
|
||||
("contentType", ContentType()),
|
||||
("contentEncryptionAlgorithm", ContentEncryptionAlgorithmIdentifier()),
|
||||
("encryptedContent", EncryptedContent(impl=tag_ctxp(0), optional=True)),
|
||||
)
|
||||
|
||||
|
||||
class Digest(OctetString):
|
||||
pass
|
||||
|
||||
|
||||
class AttributeValue(Any):
|
||||
pass
|
||||
|
||||
|
||||
class AttributeValues(SetOf):
|
||||
schema = AttributeValue()
|
||||
|
||||
|
||||
class EncryptedMac(OctetString):
|
||||
pass
|
||||
|
||||
|
||||
class Attribute(Sequence):
|
||||
schema = (
|
||||
("attrType", ObjectIdentifier(defines=(
|
||||
(("attrValues",), {
|
||||
id_contentType: ObjectIdentifier(),
|
||||
id_messageDigest: Digest(),
|
||||
id_cms_mac_attr: EncryptedMac(),
|
||||
},),
|
||||
))),
|
||||
("attrValues", AttributeValues()),
|
||||
)
|
||||
|
||||
|
||||
class UnprotectedAttributes(SetOf):
|
||||
schema = Attribute()
|
||||
bounds = (1, float("+inf"))
|
||||
|
||||
|
||||
class CertificateChoices(Choice):
|
||||
schema = (
|
||||
("certificate", Certificate()),
|
||||
# ("extendedCertificate", OctetString(impl=tag_ctxp(0))),
|
||||
# ("v1AttrCert", AttributeCertificateV1(impl=tag_ctxc(1))), # V1 is osbolete
|
||||
# ("v2AttrCert", AttributeCertificateV2(impl=tag_ctxc(2))),
|
||||
# ("other", OtherCertificateFormat(impl=tag_ctxc(3))),
|
||||
)
|
||||
|
||||
|
||||
class CertificateSet(SetOf):
|
||||
schema = CertificateChoices()
|
||||
|
||||
|
||||
class OriginatorInfo(Sequence):
|
||||
schema = (
|
||||
("certs", CertificateSet(impl=tag_ctxc(0), optional=True)),
|
||||
# ("crls", RevocationInfoChoices(impl=tag_ctxc(1), optional=True)),
|
||||
)
|
||||
|
||||
|
||||
class EnvelopedData(Sequence):
|
||||
schema = (
|
||||
("version", CMSVersion()),
|
||||
("originatorInfo", OriginatorInfo(impl=tag_ctxc(0), optional=True)),
|
||||
("recipientInfos", RecipientInfos()),
|
||||
("encryptedContentInfo", EncryptedContentInfo()),
|
||||
("unprotectedAttrs", UnprotectedAttributes(impl=tag_ctxc(1), optional=True)),
|
||||
)
|
||||
|
||||
|
||||
class EncapsulatedContentInfo(Sequence):
|
||||
schema = (
|
||||
("eContentType", ContentType()),
|
||||
("eContent", OctetString(expl=tag_ctxc(0), optional=True)),
|
||||
)
|
||||
|
||||
|
||||
class SignerIdentifier(Choice):
|
||||
schema = (
|
||||
("issuerAndSerialNumber", IssuerAndSerialNumber()),
|
||||
("subjectKeyIdentifier", SubjectKeyIdentifier(impl=tag_ctxp(0))),
|
||||
)
|
||||
|
||||
|
||||
class DigestAlgorithmIdentifiers(SetOf):
|
||||
schema = AlgorithmIdentifier()
|
||||
|
||||
|
||||
class DigestAlgorithmIdentifier(AlgorithmIdentifier):
|
||||
pass
|
||||
|
||||
|
||||
class SignatureAlgorithmIdentifier(AlgorithmIdentifier):
|
||||
pass
|
||||
|
||||
|
||||
class SignatureValue(OctetString):
|
||||
pass
|
||||
|
||||
|
||||
class SignedAttributes(SetOf):
|
||||
schema = Attribute()
|
||||
bounds = (1, float("+inf"))
|
||||
|
||||
|
||||
class SignerInfo(Sequence):
|
||||
schema = (
|
||||
("version", CMSVersion()),
|
||||
("sid", SignerIdentifier()),
|
||||
("digestAlgorithm", DigestAlgorithmIdentifier()),
|
||||
("signedAttrs", SignedAttributes(impl=tag_ctxc(0), optional=True)),
|
||||
("signatureAlgorithm", SignatureAlgorithmIdentifier()),
|
||||
("signature", SignatureValue()),
|
||||
# ("unsignedAttrs", UnsignedAttributes(impl=tag_ctxc(1), optional=True)),
|
||||
)
|
||||
|
||||
|
||||
class SignerInfos(SetOf):
|
||||
schema = SignerInfo()
|
||||
|
||||
|
||||
class SignedData(Sequence):
|
||||
schema = (
|
||||
("version", CMSVersion()),
|
||||
("digestAlgorithms", DigestAlgorithmIdentifiers()),
|
||||
("encapContentInfo", EncapsulatedContentInfo()),
|
||||
("certificates", CertificateSet(impl=tag_ctxc(0), optional=True)),
|
||||
# ("crls", RevocationInfoChoices(impl=tag_ctxc(1), optional=True)),
|
||||
("signerInfos", SignerInfos()),
|
||||
)
|
||||
|
||||
|
||||
class DigestedData(Sequence):
|
||||
schema = (
|
||||
("version", CMSVersion()),
|
||||
("digestAlgorithm", DigestAlgorithmIdentifier()),
|
||||
("encapContentInfo", EncapsulatedContentInfo()),
|
||||
("digest", Digest()),
|
||||
)
|
||||
|
||||
|
||||
class EncryptedData(Sequence):
|
||||
schema = (
|
||||
("version", CMSVersion()),
|
||||
("encryptedContentInfo", EncryptedContentInfo()),
|
||||
("unprotectedAttrs", UnprotectedAttributes(impl=tag_ctxc(1), optional=True)),
|
||||
)
|
||||
|
||||
|
||||
class ContentInfo(Sequence):
|
||||
schema = (
|
||||
("contentType", ContentType(defines=(
|
||||
(("content",), {
|
||||
id_digestedData: DigestedData(),
|
||||
id_encryptedData: EncryptedData(),
|
||||
id_envelopedData: EnvelopedData(),
|
||||
id_signedData: SignedData(),
|
||||
}),
|
||||
))),
|
||||
("content", Any(expl=tag_ctxc(0))),
|
||||
)
|
||||
@ -1,60 +0,0 @@
|
||||
from pyderasn import ObjectIdentifier
|
||||
|
||||
|
||||
id_at_commonName = ObjectIdentifier("2.5.4.3")
|
||||
id_at_countryName = ObjectIdentifier("2.5.4.6")
|
||||
id_at_localityName = ObjectIdentifier("2.5.4.7")
|
||||
id_at_stateOrProvinceName = ObjectIdentifier("2.5.4.8")
|
||||
id_at_organizationName = ObjectIdentifier("2.5.4.10")
|
||||
|
||||
id_pkcs7 = ObjectIdentifier("1.2.840.113549.1.7")
|
||||
id_data = id_pkcs7 + (1,)
|
||||
id_signedData = id_pkcs7 + (2,)
|
||||
id_envelopedData = id_pkcs7 + (3,)
|
||||
id_digestedData = id_pkcs7 + (5,)
|
||||
id_encryptedData = id_pkcs7 + (6,)
|
||||
|
||||
id_pkcs9 = ObjectIdentifier("1.2.840.113549.1.9")
|
||||
id_contentType = id_pkcs9 + (3,)
|
||||
id_messageDigest = id_pkcs9 + (4,)
|
||||
id_pkcs9_certTypes_x509Certificate = ObjectIdentifier("1.2.840.113549.1.9.22.1")
|
||||
id_pkcs12_bagtypes_keyBag = ObjectIdentifier("1.2.840.113549.1.12.10.1.1")
|
||||
id_pkcs12_bagtypes_pkcs8ShroudedKeyBag = ObjectIdentifier("1.2.840.113549.1.12.10.1.2")
|
||||
id_pkcs12_bagtypes_certBag = ObjectIdentifier("1.2.840.113549.1.12.10.1.3")
|
||||
|
||||
id_Gost28147_89 = ObjectIdentifier("1.2.643.2.2.21")
|
||||
id_GostR3410_2001_TestParamSet = ObjectIdentifier("1.2.643.2.2.35.0")
|
||||
id_cms_mac_attr = ObjectIdentifier("1.2.643.7.1.0.6.1.1")
|
||||
id_tc26_gost3410_2012_256 = ObjectIdentifier("1.2.643.7.1.1.1.1")
|
||||
id_tc26_gost3410_2012_512 = ObjectIdentifier("1.2.643.7.1.1.1.2")
|
||||
id_tc26_gost3411_2012_256 = ObjectIdentifier("1.2.643.7.1.1.2.2")
|
||||
id_tc26_gost3411_2012_512 = ObjectIdentifier("1.2.643.7.1.1.2.3")
|
||||
id_tc26_signwithdigest_gost3410_2012_256 = ObjectIdentifier("1.2.643.7.1.1.3.2")
|
||||
id_tc26_signwithdigest_gost3410_2012_512 = ObjectIdentifier("1.2.643.7.1.1.3.3")
|
||||
id_gostr3412_2015_magma_ctracpkm = ObjectIdentifier("1.2.643.7.1.1.5.1.1")
|
||||
id_gostr3412_2015_magma_ctracpkm_omac = ObjectIdentifier("1.2.643.7.1.1.5.1.2")
|
||||
id_gostr3412_2015_kuznyechik_ctracpkm = ObjectIdentifier("1.2.643.7.1.1.5.2.1")
|
||||
id_gostr3412_2015_kuznyechik_ctracpkm_omac = ObjectIdentifier("1.2.643.7.1.1.5.2.2")
|
||||
id_tc26_agreement_gost3410_2012_256 = ObjectIdentifier("1.2.643.7.1.1.6.1")
|
||||
id_tc26_agreement_gost3410_2012_512 = ObjectIdentifier("1.2.643.7.1.1.6.2")
|
||||
id_gostr3412_2015_magma_wrap_kexp15 = ObjectIdentifier("1.2.643.7.1.1.7.1.1")
|
||||
id_gostr3412_2015_kuznyechik_wrap_kexp15 = ObjectIdentifier("1.2.643.7.1.1.7.2.1")
|
||||
id_tc26_gost3410_2012_256_paramSetA = ObjectIdentifier("1.2.643.7.1.2.1.1.1")
|
||||
id_tc26_gost3410_2012_256_paramSetB = ObjectIdentifier("1.2.643.7.1.2.1.1.2")
|
||||
id_tc26_gost3410_2012_256_paramSetC = ObjectIdentifier("1.2.643.7.1.2.1.1.3")
|
||||
id_tc26_gost3410_2012_256_paramSetD = ObjectIdentifier("1.2.643.7.1.2.1.1.4")
|
||||
id_tc26_gost3410_2012_512_paramSetTest = ObjectIdentifier("1.2.643.7.1.2.1.2.0")
|
||||
id_tc26_gost3410_2012_512_paramSetA = ObjectIdentifier("1.2.643.7.1.2.1.2.1")
|
||||
id_tc26_gost3410_2012_512_paramSetB = ObjectIdentifier("1.2.643.7.1.2.1.2.2")
|
||||
id_tc26_gost3410_2012_512_paramSetC = ObjectIdentifier("1.2.643.7.1.2.1.2.3")
|
||||
id_tc26_gost_28147_param_Z = ObjectIdentifier("1.2.643.7.1.2.5.1.1")
|
||||
|
||||
id_pbes2 = ObjectIdentifier("1.2.840.113549.1.5.13")
|
||||
id_pbkdf2 = ObjectIdentifier("1.2.840.113549.1.5.12")
|
||||
|
||||
id_at_commonName = ObjectIdentifier("2.5.4.3")
|
||||
id_ce_basicConstraints = ObjectIdentifier("2.5.29.19")
|
||||
id_ce_subjectKeyIdentifier = ObjectIdentifier("2.5.29.14")
|
||||
id_ce_keyUsage = ObjectIdentifier("2.5.29.15")
|
||||
id_ce_subjectAltName = ObjectIdentifier("2.5.29.17")
|
||||
id_ce_authorityKeyIdentifier = ObjectIdentifier("2.5.29.35")
|
||||
@ -1,250 +0,0 @@
|
||||
# coding: utf-8
|
||||
# PyGOST -- Pure Python GOST cryptographic functions library
|
||||
# Copyright (C) 2015-2023 Sergey Matveev <stargrave@stargrave.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, version 3 of the License.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
"""PKCS #12 related structures (**NOT COMPLETE**)
|
||||
"""
|
||||
|
||||
from pyderasn import Any
|
||||
from pyderasn import Choice
|
||||
from pyderasn import Integer
|
||||
from pyderasn import ObjectIdentifier
|
||||
from pyderasn import OctetString
|
||||
from pyderasn import Sequence
|
||||
from pyderasn import SequenceOf
|
||||
from pyderasn import SetOf
|
||||
from pyderasn import tag_ctxc
|
||||
from pyderasn import tag_ctxp
|
||||
|
||||
from pygost.asn1schemas.cms import CMSVersion
|
||||
from pygost.asn1schemas.cms import ContentType
|
||||
from pygost.asn1schemas.cms import Gost2814789Parameters
|
||||
from pygost.asn1schemas.cms import Gost341215EncryptionParameters
|
||||
from pygost.asn1schemas.oids import id_data
|
||||
from pygost.asn1schemas.oids import id_encryptedData
|
||||
from pygost.asn1schemas.oids import id_Gost28147_89
|
||||
from pygost.asn1schemas.oids import id_gostr3412_2015_kuznyechik_ctracpkm
|
||||
from pygost.asn1schemas.oids import id_gostr3412_2015_kuznyechik_ctracpkm_omac
|
||||
from pygost.asn1schemas.oids import id_gostr3412_2015_magma_ctracpkm
|
||||
from pygost.asn1schemas.oids import id_gostr3412_2015_magma_ctracpkm_omac
|
||||
from pygost.asn1schemas.oids import id_pbes2
|
||||
from pygost.asn1schemas.oids import id_pbkdf2
|
||||
from pygost.asn1schemas.oids import id_pkcs9_certTypes_x509Certificate
|
||||
from pygost.asn1schemas.prvkey import PrivateKeyInfo
|
||||
from pygost.asn1schemas.x509 import AlgorithmIdentifier
|
||||
from pygost.asn1schemas.x509 import Certificate
|
||||
|
||||
|
||||
class PBKDF2Salt(Choice):
|
||||
schema = (
|
||||
("specified", OctetString()),
|
||||
# ("otherSource", PBKDF2SaltSources()),
|
||||
)
|
||||
|
||||
|
||||
id_hmacWithSHA1 = ObjectIdentifier("1.2.840.113549.2.7")
|
||||
|
||||
|
||||
class PBKDF2PRFs(AlgorithmIdentifier):
|
||||
schema = (
|
||||
("algorithm", ObjectIdentifier(default=id_hmacWithSHA1)),
|
||||
("parameters", Any(optional=True)),
|
||||
)
|
||||
|
||||
|
||||
class IterationCount(Integer):
|
||||
bounds = (1, float("+inf"))
|
||||
|
||||
|
||||
class KeyLength(Integer):
|
||||
bounds = (1, float("+inf"))
|
||||
|
||||
|
||||
class PBKDF2Params(Sequence):
|
||||
schema = (
|
||||
("salt", PBKDF2Salt()),
|
||||
("iterationCount", IterationCount(optional=True)),
|
||||
("keyLength", KeyLength(optional=True)),
|
||||
("prf", PBKDF2PRFs()),
|
||||
)
|
||||
|
||||
|
||||
class PBES2KDFs(AlgorithmIdentifier):
|
||||
schema = (
|
||||
("algorithm", ObjectIdentifier(defines=(
|
||||
(("parameters",), {id_pbkdf2: PBKDF2Params()}),
|
||||
))),
|
||||
("parameters", Any(optional=True)),
|
||||
)
|
||||
|
||||
|
||||
class PBES2Encs(AlgorithmIdentifier):
|
||||
schema = (
|
||||
("algorithm", ObjectIdentifier(defines=(
|
||||
(("parameters",), {
|
||||
id_Gost28147_89: Gost2814789Parameters(),
|
||||
id_gostr3412_2015_magma_ctracpkm: Gost341215EncryptionParameters(),
|
||||
id_gostr3412_2015_magma_ctracpkm_omac: Gost341215EncryptionParameters(),
|
||||
id_gostr3412_2015_kuznyechik_ctracpkm: Gost341215EncryptionParameters(),
|
||||
id_gostr3412_2015_kuznyechik_ctracpkm_omac: Gost341215EncryptionParameters(),
|
||||
}),
|
||||
))),
|
||||
("parameters", Any(optional=True)),
|
||||
)
|
||||
|
||||
|
||||
class PBES2Params(Sequence):
|
||||
schema = (
|
||||
("keyDerivationFunc", PBES2KDFs()),
|
||||
("encryptionScheme", PBES2Encs()),
|
||||
)
|
||||
|
||||
|
||||
class EncryptionAlgorithmIdentifier(AlgorithmIdentifier):
|
||||
schema = (
|
||||
("algorithm", ObjectIdentifier(defines=(
|
||||
(("parameters",), {id_pbes2: PBES2Params()}),
|
||||
))),
|
||||
("parameters", Any(optional=True)),
|
||||
)
|
||||
|
||||
|
||||
class ContentEncryptionAlgorithmIdentifier(EncryptionAlgorithmIdentifier):
|
||||
schema = (
|
||||
("algorithm", ObjectIdentifier(defines=(
|
||||
(("parameters",), {id_pbes2: PBES2Params()}),
|
||||
))),
|
||||
("parameters", Any(optional=True)),
|
||||
)
|
||||
|
||||
|
||||
class EncryptedContent(OctetString):
|
||||
pass
|
||||
|
||||
|
||||
class EncryptedContentInfo(Sequence):
|
||||
schema = (
|
||||
("contentType", ContentType()),
|
||||
("contentEncryptionAlgorithm", ContentEncryptionAlgorithmIdentifier()),
|
||||
("encryptedContent", EncryptedContent(impl=tag_ctxp(0), optional=True)),
|
||||
)
|
||||
|
||||
|
||||
class EncryptedData(Sequence):
|
||||
schema = (
|
||||
("version", CMSVersion()),
|
||||
("encryptedContentInfo", EncryptedContentInfo()),
|
||||
# ("unprotectedAttrs", UnprotectedAttributes(impl=tag_ctxc(1), optional=True)),
|
||||
)
|
||||
|
||||
|
||||
class PKCS12BagSet(Any):
|
||||
pass
|
||||
|
||||
|
||||
class AttrValue(SetOf):
|
||||
schema = Any()
|
||||
|
||||
|
||||
class PKCS12Attribute(Sequence):
|
||||
schema = (
|
||||
("attrId", ObjectIdentifier()),
|
||||
("attrValue", AttrValue()),
|
||||
)
|
||||
|
||||
|
||||
class PKCS12Attributes(SetOf):
|
||||
schema = PKCS12Attribute()
|
||||
|
||||
|
||||
class SafeBag(Sequence):
|
||||
schema = (
|
||||
("bagId", ObjectIdentifier(defines=(
|
||||
(("bagValue",), {id_encryptedData: EncryptedData()}),
|
||||
))),
|
||||
("bagValue", PKCS12BagSet(expl=tag_ctxc(0))),
|
||||
("bagAttributes", PKCS12Attributes(optional=True)),
|
||||
)
|
||||
|
||||
|
||||
class SafeContents(SequenceOf):
|
||||
schema = SafeBag()
|
||||
|
||||
|
||||
OctetStringSafeContents = SafeContents(expl=OctetString.tag_default)
|
||||
|
||||
|
||||
class AuthSafe(Sequence):
|
||||
schema = (
|
||||
("contentType", ContentType(defines=(
|
||||
(("content",), {id_data: OctetStringSafeContents()}),
|
||||
))),
|
||||
("content", Any(expl=tag_ctxc(0))),
|
||||
)
|
||||
|
||||
|
||||
class DigestInfo(Sequence):
|
||||
schema = (
|
||||
("digestAlgorithm", AlgorithmIdentifier()),
|
||||
("digest", OctetString()),
|
||||
)
|
||||
|
||||
|
||||
class MacData(Sequence):
|
||||
schema = (
|
||||
("mac", DigestInfo()),
|
||||
("macSalt", OctetString()),
|
||||
("iterations", Integer(default=1)),
|
||||
)
|
||||
|
||||
|
||||
class PFX(Sequence):
|
||||
schema = (
|
||||
("version", Integer(default=1)),
|
||||
("authSafe", AuthSafe()),
|
||||
("macData", MacData(optional=True)),
|
||||
)
|
||||
|
||||
|
||||
class EncryptedPrivateKeyInfo(Sequence):
|
||||
schema = (
|
||||
("encryptionAlgorithm", EncryptionAlgorithmIdentifier()),
|
||||
("encryptedData", OctetString()),
|
||||
)
|
||||
|
||||
|
||||
class PKCS8ShroudedKeyBag(EncryptedPrivateKeyInfo):
|
||||
pass
|
||||
|
||||
|
||||
OctetStringX509Certificate = Certificate(expl=OctetString.tag_default)
|
||||
|
||||
|
||||
class CertTypes(Any):
|
||||
pass
|
||||
|
||||
|
||||
class CertBag(Sequence):
|
||||
schema = (
|
||||
("certId", ObjectIdentifier(defines=(
|
||||
(("certValue",), {
|
||||
id_pkcs9_certTypes_x509Certificate: OctetStringX509Certificate(),
|
||||
}),
|
||||
))),
|
||||
("certValue", CertTypes(expl=tag_ctxc(0))),
|
||||
)
|
||||
|
||||
|
||||
class KeyBag(PrivateKeyInfo):
|
||||
pass
|
||||
@ -1,49 +0,0 @@
|
||||
# coding: utf-8
|
||||
# PyGOST -- Pure Python GOST cryptographic functions library
|
||||
# Copyright (C) 2015-2023 Sergey Matveev <stargrave@stargrave.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, version 3 of the License.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
"""PKCS #10 related structures (**NOT COMPLETE**)
|
||||
"""
|
||||
|
||||
from pyderasn import BitString
|
||||
from pyderasn import Integer
|
||||
from pyderasn import Sequence
|
||||
from pyderasn import SetOf
|
||||
from pyderasn import tag_ctxc
|
||||
|
||||
from pygost.asn1schemas.cms import Attribute
|
||||
from pygost.asn1schemas.x509 import AlgorithmIdentifier
|
||||
from pygost.asn1schemas.x509 import Name
|
||||
from pygost.asn1schemas.x509 import SubjectPublicKeyInfo
|
||||
|
||||
|
||||
class Attributes(SetOf):
|
||||
schema = Attribute()
|
||||
|
||||
|
||||
class CertificationRequestInfo(Sequence):
|
||||
schema = (
|
||||
("version", Integer(0)),
|
||||
("subject", Name()),
|
||||
("subjectPKInfo", SubjectPublicKeyInfo()),
|
||||
("attributes", Attributes(impl=tag_ctxc(0))),
|
||||
)
|
||||
|
||||
|
||||
class CertificationRequest(Sequence):
|
||||
schema = (
|
||||
("certificationRequestInfo", CertificationRequestInfo()),
|
||||
("signatureAlgorithm", AlgorithmIdentifier()),
|
||||
("signature", BitString()),
|
||||
)
|
||||
@ -1,100 +0,0 @@
|
||||
# coding: utf-8
|
||||
# PyGOST -- Pure Python GOST cryptographic functions library
|
||||
# Copyright (C) 2015-2023 Sergey Matveev <stargrave@stargrave.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, version 3 of the License.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from pyderasn import Any
|
||||
from pyderasn import BitString
|
||||
from pyderasn import Choice
|
||||
from pyderasn import Integer
|
||||
from pyderasn import Null
|
||||
from pyderasn import ObjectIdentifier
|
||||
from pyderasn import OctetString
|
||||
from pyderasn import Sequence
|
||||
from pyderasn import SetOf
|
||||
from pyderasn import tag_ctxc
|
||||
from pyderasn import tag_ctxp
|
||||
|
||||
from pygost.asn1schemas.oids import id_tc26_gost3410_2012_256
|
||||
from pygost.asn1schemas.oids import id_tc26_gost3410_2012_512
|
||||
from pygost.asn1schemas.x509 import GostR34102012PublicKeyParameters
|
||||
|
||||
|
||||
class ECParameters(Choice):
|
||||
schema = (
|
||||
("namedCurve", ObjectIdentifier()),
|
||||
("implicitCurve", Null()),
|
||||
# ("specifiedCurve", SpecifiedECDomain()),
|
||||
)
|
||||
|
||||
|
||||
ecPrivkeyVer1 = Integer(1)
|
||||
|
||||
|
||||
class ECPrivateKey(Sequence):
|
||||
schema = (
|
||||
("version", Integer(ecPrivkeyVer1)),
|
||||
("privateKey", OctetString()),
|
||||
("parameters", ECParameters(expl=tag_ctxc(0), optional=True)),
|
||||
("publicKey", BitString(expl=tag_ctxc(1), optional=True)),
|
||||
)
|
||||
|
||||
|
||||
class PrivateKeyAlgorithmIdentifier(Sequence):
|
||||
schema = (
|
||||
("algorithm", ObjectIdentifier(defines=(
|
||||
(("parameters",), {
|
||||
id_tc26_gost3410_2012_256: GostR34102012PublicKeyParameters(),
|
||||
id_tc26_gost3410_2012_512: GostR34102012PublicKeyParameters(),
|
||||
}),
|
||||
))),
|
||||
("parameters", Any(optional=True)),
|
||||
)
|
||||
|
||||
|
||||
class PrivateKey(OctetString):
|
||||
pass
|
||||
|
||||
|
||||
class AttributeValue(Any):
|
||||
pass
|
||||
|
||||
|
||||
class AttributeValues(SetOf):
|
||||
schema = AttributeValue()
|
||||
|
||||
|
||||
class Attribute(Sequence):
|
||||
schema = (
|
||||
("attrType", ObjectIdentifier()),
|
||||
("attrValues", AttributeValues()),
|
||||
)
|
||||
|
||||
|
||||
class Attributes(SetOf):
|
||||
schema = Attribute()
|
||||
|
||||
|
||||
class PublicKey(BitString):
|
||||
pass
|
||||
|
||||
|
||||
class PrivateKeyInfo(Sequence):
|
||||
schema = (
|
||||
("version", Integer(0)),
|
||||
("privateKeyAlgorithm", PrivateKeyAlgorithmIdentifier()),
|
||||
("privateKey", PrivateKey()),
|
||||
("attributes", Attributes(impl=tag_ctxc(0), optional=True)),
|
||||
("publicKey", PublicKey(impl=tag_ctxp(1), optional=True)),
|
||||
)
|
||||
@ -1,262 +0,0 @@
|
||||
# coding: utf-8
|
||||
# PyGOST -- Pure Python GOST cryptographic functions library
|
||||
# Copyright (C) 2015-2023 Sergey Matveev <stargrave@stargrave.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, version 3 of the License.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
""":rfc:`5280` related structures (**NOT COMPLETE**)
|
||||
|
||||
They are taken from `PyDERASN <http://www.pyderasn.cypherpunks.ru/`__ tests.
|
||||
"""
|
||||
|
||||
from pyderasn import Any
|
||||
from pyderasn import BitString
|
||||
from pyderasn import Boolean
|
||||
from pyderasn import Choice
|
||||
from pyderasn import GeneralizedTime
|
||||
from pyderasn import IA5String
|
||||
from pyderasn import Integer
|
||||
from pyderasn import ObjectIdentifier
|
||||
from pyderasn import OctetString
|
||||
from pyderasn import PrintableString
|
||||
from pyderasn import Sequence
|
||||
from pyderasn import SequenceOf
|
||||
from pyderasn import SetOf
|
||||
from pyderasn import tag_ctxc
|
||||
from pyderasn import tag_ctxp
|
||||
from pyderasn import TeletexString
|
||||
from pyderasn import UTCTime
|
||||
|
||||
from pygost.asn1schemas.oids import id_at_commonName
|
||||
from pygost.asn1schemas.oids import id_at_countryName
|
||||
from pygost.asn1schemas.oids import id_at_localityName
|
||||
from pygost.asn1schemas.oids import id_at_organizationName
|
||||
from pygost.asn1schemas.oids import id_at_stateOrProvinceName
|
||||
|
||||
|
||||
class Version(Integer):
|
||||
schema = (
|
||||
("v1", 0),
|
||||
("v2", 1),
|
||||
("v3", 2),
|
||||
)
|
||||
|
||||
|
||||
class CertificateSerialNumber(Integer):
|
||||
pass
|
||||
|
||||
|
||||
class AlgorithmIdentifier(Sequence):
|
||||
schema = (
|
||||
("algorithm", ObjectIdentifier()),
|
||||
("parameters", Any(optional=True)),
|
||||
)
|
||||
|
||||
|
||||
class AttributeType(ObjectIdentifier):
|
||||
pass
|
||||
|
||||
|
||||
class AttributeValue(Any):
|
||||
pass
|
||||
|
||||
|
||||
class OrganizationName(Choice):
|
||||
schema = (
|
||||
("printableString", PrintableString()),
|
||||
("teletexString", TeletexString()),
|
||||
)
|
||||
|
||||
|
||||
class AttributeTypeAndValue(Sequence):
|
||||
schema = (
|
||||
("type", AttributeType(defines=(((".", "value"), {
|
||||
id_at_countryName: PrintableString(),
|
||||
id_at_stateOrProvinceName: PrintableString(),
|
||||
id_at_localityName: PrintableString(),
|
||||
id_at_organizationName: OrganizationName(),
|
||||
id_at_commonName: PrintableString(),
|
||||
}),))),
|
||||
("value", AttributeValue()),
|
||||
)
|
||||
|
||||
|
||||
class RelativeDistinguishedName(SetOf):
|
||||
schema = AttributeTypeAndValue()
|
||||
bounds = (1, float("+inf"))
|
||||
|
||||
|
||||
class RDNSequence(SequenceOf):
|
||||
schema = RelativeDistinguishedName()
|
||||
|
||||
|
||||
class Name(Choice):
|
||||
schema = (
|
||||
("rdnSequence", RDNSequence()),
|
||||
)
|
||||
|
||||
|
||||
class Time(Choice):
|
||||
schema = (
|
||||
("utcTime", UTCTime()),
|
||||
("generalTime", GeneralizedTime()),
|
||||
)
|
||||
|
||||
|
||||
class Validity(Sequence):
|
||||
schema = (
|
||||
("notBefore", Time()),
|
||||
("notAfter", Time()),
|
||||
)
|
||||
|
||||
|
||||
class GostR34102012PublicKeyParameters(Sequence):
|
||||
schema = (
|
||||
("publicKeyParamSet", ObjectIdentifier()),
|
||||
("digestParamSet", ObjectIdentifier(optional=True)),
|
||||
)
|
||||
|
||||
|
||||
class SubjectPublicKeyInfo(Sequence):
|
||||
schema = (
|
||||
("algorithm", AlgorithmIdentifier()),
|
||||
("subjectPublicKey", BitString()),
|
||||
)
|
||||
|
||||
|
||||
class UniqueIdentifier(BitString):
|
||||
pass
|
||||
|
||||
|
||||
class KeyIdentifier(OctetString):
|
||||
pass
|
||||
|
||||
|
||||
class SubjectKeyIdentifier(KeyIdentifier):
|
||||
pass
|
||||
|
||||
|
||||
class BasicConstraints(Sequence):
|
||||
schema = (
|
||||
("cA", Boolean(default=False)),
|
||||
# ("pathLenConstraint", PathLenConstraint(optional=True)),
|
||||
)
|
||||
|
||||
|
||||
class Extension(Sequence):
|
||||
schema = (
|
||||
("extnID", ObjectIdentifier()),
|
||||
("critical", Boolean(default=False)),
|
||||
("extnValue", OctetString()),
|
||||
)
|
||||
|
||||
|
||||
class Extensions(SequenceOf):
|
||||
schema = Extension()
|
||||
bounds = (1, float("+inf"))
|
||||
|
||||
|
||||
class TBSCertificate(Sequence):
|
||||
schema = (
|
||||
("version", Version(expl=tag_ctxc(0), default="v1")),
|
||||
("serialNumber", CertificateSerialNumber()),
|
||||
("signature", AlgorithmIdentifier()),
|
||||
("issuer", Name()),
|
||||
("validity", Validity()),
|
||||
("subject", Name()),
|
||||
("subjectPublicKeyInfo", SubjectPublicKeyInfo()),
|
||||
("issuerUniqueID", UniqueIdentifier(impl=tag_ctxp(1), optional=True)),
|
||||
("subjectUniqueID", UniqueIdentifier(impl=tag_ctxp(2), optional=True)),
|
||||
("extensions", Extensions(expl=tag_ctxc(3), optional=True)),
|
||||
)
|
||||
|
||||
|
||||
class Certificate(Sequence):
|
||||
schema = (
|
||||
("tbsCertificate", TBSCertificate()),
|
||||
("signatureAlgorithm", AlgorithmIdentifier()),
|
||||
("signatureValue", BitString()),
|
||||
)
|
||||
|
||||
|
||||
class RevokedCertificates(SequenceOf):
|
||||
# schema = RevokedCertificate()
|
||||
schema = OctetString() # dummy
|
||||
|
||||
|
||||
class TBSCertList(Sequence):
|
||||
schema = (
|
||||
("version", Version(optional=True)),
|
||||
("signature", AlgorithmIdentifier()),
|
||||
("issuer", Name()),
|
||||
("thisUpdate", Time()),
|
||||
("nextUpdate", Time(optional=True)),
|
||||
("revokedCertificates", RevokedCertificates(optional=True)),
|
||||
("crlExtensions", Extensions(expl=tag_ctxc(0), optional=True)),
|
||||
)
|
||||
|
||||
|
||||
class CertificateList(Sequence):
|
||||
schema = (
|
||||
("tbsCertList", TBSCertList()),
|
||||
("signatureAlgorithm", AlgorithmIdentifier()),
|
||||
("signatureValue", BitString()),
|
||||
)
|
||||
|
||||
|
||||
class GeneralName(Choice):
|
||||
schema = (
|
||||
# ("otherName", AnotherName(impl=tag_ctxc(0))),
|
||||
# ("rfc822Name", IA5String(impl=tag_ctxp(1))),
|
||||
("dNSName", IA5String(impl=tag_ctxp(2))),
|
||||
# ("x400Address", ORAddress(impl=tag_ctxp(3))),
|
||||
# ("x400Address", OctetString(impl=tag_ctxp(3))),
|
||||
# ("directoryName", Name(expl=tag_ctxc(4))),
|
||||
# ("ediPartyName", EDIPartyName(impl=tag_ctxc(5))),
|
||||
# ("uniformResourceIdentifier", IA5String(impl=tag_ctxp(6))),
|
||||
# ("iPAddress", OctetString(impl=tag_ctxp(7))),
|
||||
# ("registeredID", ObjectIdentifier(impl=tag_ctxp(8))),
|
||||
)
|
||||
|
||||
|
||||
class GeneralNames(SequenceOf):
|
||||
schema = GeneralName()
|
||||
bounds = (1, float("+inf"))
|
||||
|
||||
|
||||
class SubjectAltName(GeneralNames):
|
||||
pass
|
||||
|
||||
|
||||
class AuthorityKeyIdentifier(Sequence):
|
||||
schema = (
|
||||
("keyIdentifier", KeyIdentifier(impl=tag_ctxp(0), optional=True)),
|
||||
# ("authorityCertIssuer", GeneralNames(impl=tag_ctxc(1), optional=True)),
|
||||
# (
|
||||
# "authorityCertSerialNumber",
|
||||
# CertificateSerialNumber(impl=tag_ctxp(2), optional=True),
|
||||
# ),
|
||||
)
|
||||
|
||||
|
||||
class KeyUsage(BitString):
|
||||
schema = (
|
||||
("digitalSignature", 0),
|
||||
("nonRepudiation", 1),
|
||||
("keyEncipherment", 2),
|
||||
("dataEncipherment", 3),
|
||||
("keyAgreement", 4),
|
||||
("keyCertSign", 5),
|
||||
("cRLSign", 6),
|
||||
("encipherOnly", 7),
|
||||
("decipherOnly", 8),
|
||||
)
|
||||
@ -1,457 +0,0 @@
|
||||
# coding: utf-8
|
||||
# PyGOST -- Pure Python GOST cryptographic functions library
|
||||
# Copyright (C) 2015-2023 Sergey Matveev <stargrave@stargrave.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, version 3 of the License.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
"""GOST 28147-89 block cipher
|
||||
|
||||
This is implementation of :rfc:`5830` ECB, CNT, CFB and :rfc:`4357`
|
||||
CBC modes of operation. N1, N2, K names are taken according to
|
||||
specification's terminology. CNT and CFB modes can work with arbitrary
|
||||
data lengths.
|
||||
"""
|
||||
|
||||
from functools import partial
|
||||
|
||||
from pygost.gost3413 import pad2
|
||||
from pygost.gost3413 import pad_size
|
||||
from pygost.gost3413 import unpad2
|
||||
from pygost.utils import hexdec
|
||||
from pygost.utils import strxor
|
||||
from pygost.utils import xrange
|
||||
|
||||
|
||||
KEYSIZE = 32
|
||||
BLOCKSIZE = 8
|
||||
C1 = 0x01010104
|
||||
C2 = 0x01010101
|
||||
|
||||
# Sequence of K_i S-box applying for encryption and decryption
|
||||
SEQ_ENCRYPT = (
|
||||
0, 1, 2, 3, 4, 5, 6, 7,
|
||||
0, 1, 2, 3, 4, 5, 6, 7,
|
||||
0, 1, 2, 3, 4, 5, 6, 7,
|
||||
7, 6, 5, 4, 3, 2, 1, 0,
|
||||
)
|
||||
SEQ_DECRYPT = (
|
||||
0, 1, 2, 3, 4, 5, 6, 7,
|
||||
7, 6, 5, 4, 3, 2, 1, 0,
|
||||
7, 6, 5, 4, 3, 2, 1, 0,
|
||||
7, 6, 5, 4, 3, 2, 1, 0,
|
||||
)
|
||||
|
||||
# S-box parameters
|
||||
DEFAULT_SBOX = "id-Gost28147-89-CryptoPro-A-ParamSet"
|
||||
SBOXES = {
|
||||
"id-Gost28147-89-TestParamSet": (
|
||||
(4, 2, 15, 5, 9, 1, 0, 8, 14, 3, 11, 12, 13, 7, 10, 6),
|
||||
(12, 9, 15, 14, 8, 1, 3, 10, 2, 7, 4, 13, 6, 0, 11, 5),
|
||||
(13, 8, 14, 12, 7, 3, 9, 10, 1, 5, 2, 4, 6, 15, 0, 11),
|
||||
(14, 9, 11, 2, 5, 15, 7, 1, 0, 13, 12, 6, 10, 4, 3, 8),
|
||||
(3, 14, 5, 9, 6, 8, 0, 13, 10, 11, 7, 12, 2, 1, 15, 4),
|
||||
(8, 15, 6, 11, 1, 9, 12, 5, 13, 3, 7, 10, 0, 14, 2, 4),
|
||||
(9, 11, 12, 0, 3, 6, 7, 5, 4, 8, 14, 15, 1, 10, 2, 13),
|
||||
(12, 6, 5, 2, 11, 0, 9, 13, 3, 14, 7, 10, 15, 4, 1, 8),
|
||||
),
|
||||
"id-Gost28147-89-CryptoPro-A-ParamSet": (
|
||||
(9, 6, 3, 2, 8, 11, 1, 7, 10, 4, 14, 15, 12, 0, 13, 5),
|
||||
(3, 7, 14, 9, 8, 10, 15, 0, 5, 2, 6, 12, 11, 4, 13, 1),
|
||||
(14, 4, 6, 2, 11, 3, 13, 8, 12, 15, 5, 10, 0, 7, 1, 9),
|
||||
(14, 7, 10, 12, 13, 1, 3, 9, 0, 2, 11, 4, 15, 8, 5, 6),
|
||||
(11, 5, 1, 9, 8, 13, 15, 0, 14, 4, 2, 3, 12, 7, 10, 6),
|
||||
(3, 10, 13, 12, 1, 2, 0, 11, 7, 5, 9, 4, 8, 15, 14, 6),
|
||||
(1, 13, 2, 9, 7, 10, 6, 0, 8, 12, 4, 5, 15, 3, 11, 14),
|
||||
(11, 10, 15, 5, 0, 12, 14, 8, 6, 2, 3, 9, 1, 7, 13, 4),
|
||||
),
|
||||
"id-Gost28147-89-CryptoPro-B-ParamSet": (
|
||||
(8, 4, 11, 1, 3, 5, 0, 9, 2, 14, 10, 12, 13, 6, 7, 15),
|
||||
(0, 1, 2, 10, 4, 13, 5, 12, 9, 7, 3, 15, 11, 8, 6, 14),
|
||||
(14, 12, 0, 10, 9, 2, 13, 11, 7, 5, 8, 15, 3, 6, 1, 4),
|
||||
(7, 5, 0, 13, 11, 6, 1, 2, 3, 10, 12, 15, 4, 14, 9, 8),
|
||||
(2, 7, 12, 15, 9, 5, 10, 11, 1, 4, 0, 13, 6, 8, 14, 3),
|
||||
(8, 3, 2, 6, 4, 13, 14, 11, 12, 1, 7, 15, 10, 0, 9, 5),
|
||||
(5, 2, 10, 11, 9, 1, 12, 3, 7, 4, 13, 0, 6, 15, 8, 14),
|
||||
(0, 4, 11, 14, 8, 3, 7, 1, 10, 2, 9, 6, 15, 13, 5, 12),
|
||||
),
|
||||
"id-Gost28147-89-CryptoPro-C-ParamSet": (
|
||||
(1, 11, 12, 2, 9, 13, 0, 15, 4, 5, 8, 14, 10, 7, 6, 3),
|
||||
(0, 1, 7, 13, 11, 4, 5, 2, 8, 14, 15, 12, 9, 10, 6, 3),
|
||||
(8, 2, 5, 0, 4, 9, 15, 10, 3, 7, 12, 13, 6, 14, 1, 11),
|
||||
(3, 6, 0, 1, 5, 13, 10, 8, 11, 2, 9, 7, 14, 15, 12, 4),
|
||||
(8, 13, 11, 0, 4, 5, 1, 2, 9, 3, 12, 14, 6, 15, 10, 7),
|
||||
(12, 9, 11, 1, 8, 14, 2, 4, 7, 3, 6, 5, 10, 0, 15, 13),
|
||||
(10, 9, 6, 8, 13, 14, 2, 0, 15, 3, 5, 11, 4, 1, 12, 7),
|
||||
(7, 4, 0, 5, 10, 2, 15, 14, 12, 6, 1, 11, 13, 9, 3, 8),
|
||||
),
|
||||
"id-Gost28147-89-CryptoPro-D-ParamSet": (
|
||||
(15, 12, 2, 10, 6, 4, 5, 0, 7, 9, 14, 13, 1, 11, 8, 3),
|
||||
(11, 6, 3, 4, 12, 15, 14, 2, 7, 13, 8, 0, 5, 10, 9, 1),
|
||||
(1, 12, 11, 0, 15, 14, 6, 5, 10, 13, 4, 8, 9, 3, 7, 2),
|
||||
(1, 5, 14, 12, 10, 7, 0, 13, 6, 2, 11, 4, 9, 3, 15, 8),
|
||||
(0, 12, 8, 9, 13, 2, 10, 11, 7, 3, 6, 5, 4, 14, 15, 1),
|
||||
(8, 0, 15, 3, 2, 5, 14, 11, 1, 10, 4, 7, 12, 9, 13, 6),
|
||||
(3, 0, 6, 15, 1, 14, 9, 2, 13, 8, 12, 4, 11, 10, 5, 7),
|
||||
(1, 10, 6, 8, 15, 11, 0, 4, 12, 3, 5, 9, 7, 13, 2, 14),
|
||||
),
|
||||
"id-tc26-gost-28147-param-Z": (
|
||||
(12, 4, 6, 2, 10, 5, 11, 9, 14, 8, 13, 7, 0, 3, 15, 1),
|
||||
(6, 8, 2, 3, 9, 10, 5, 12, 1, 14, 4, 7, 11, 13, 0, 15),
|
||||
(11, 3, 5, 8, 2, 15, 10, 13, 14, 1, 7, 4, 12, 9, 6, 0),
|
||||
(12, 8, 2, 1, 13, 4, 15, 6, 7, 0, 10, 5, 3, 14, 9, 11),
|
||||
(7, 15, 5, 10, 8, 1, 6, 13, 0, 9, 3, 14, 11, 4, 2, 12),
|
||||
(5, 13, 15, 6, 9, 2, 12, 10, 11, 7, 8, 1, 4, 3, 14, 0),
|
||||
(8, 14, 2, 5, 6, 9, 1, 12, 15, 4, 11, 0, 13, 10, 3, 7),
|
||||
(1, 7, 14, 13, 0, 5, 8, 3, 4, 15, 10, 6, 9, 12, 11, 2),
|
||||
),
|
||||
"id-GostR3411-94-TestParamSet": (
|
||||
(4, 10, 9, 2, 13, 8, 0, 14, 6, 11, 1, 12, 7, 15, 5, 3),
|
||||
(14, 11, 4, 12, 6, 13, 15, 10, 2, 3, 8, 1, 0, 7, 5, 9),
|
||||
(5, 8, 1, 13, 10, 3, 4, 2, 14, 15, 12, 7, 6, 0, 9, 11),
|
||||
(7, 13, 10, 1, 0, 8, 9, 15, 14, 4, 6, 12, 11, 2, 5, 3),
|
||||
(6, 12, 7, 1, 5, 15, 13, 8, 4, 10, 9, 14, 0, 3, 11, 2),
|
||||
(4, 11, 10, 0, 7, 2, 1, 13, 3, 6, 8, 5, 9, 12, 15, 14),
|
||||
(13, 11, 4, 1, 3, 15, 5, 9, 0, 10, 14, 7, 6, 8, 2, 12),
|
||||
(1, 15, 13, 0, 5, 7, 10, 4, 9, 2, 3, 14, 6, 11, 8, 12),
|
||||
),
|
||||
"id-GostR3411-94-CryptoProParamSet": (
|
||||
(10, 4, 5, 6, 8, 1, 3, 7, 13, 12, 14, 0, 9, 2, 11, 15),
|
||||
(5, 15, 4, 0, 2, 13, 11, 9, 1, 7, 6, 3, 12, 14, 10, 8),
|
||||
(7, 15, 12, 14, 9, 4, 1, 0, 3, 11, 5, 2, 6, 10, 8, 13),
|
||||
(4, 10, 7, 12, 0, 15, 2, 8, 14, 1, 6, 5, 13, 11, 9, 3),
|
||||
(7, 6, 4, 11, 9, 12, 2, 10, 1, 8, 0, 14, 15, 13, 3, 5),
|
||||
(7, 6, 2, 4, 13, 9, 15, 0, 10, 1, 5, 11, 8, 14, 12, 3),
|
||||
(13, 14, 4, 1, 7, 0, 5, 10, 3, 12, 8, 15, 6, 2, 9, 11),
|
||||
(1, 3, 10, 9, 5, 11, 4, 15, 8, 6, 7, 14, 13, 0, 2, 12),
|
||||
),
|
||||
"EACParamSet": (
|
||||
(11, 4, 8, 10, 9, 7, 0, 3, 1, 6, 2, 15, 14, 5, 12, 13),
|
||||
(1, 7, 14, 9, 11, 3, 15, 12, 0, 5, 4, 6, 13, 10, 8, 2),
|
||||
(7, 3, 1, 9, 2, 4, 13, 15, 8, 10, 12, 6, 5, 0, 11, 14),
|
||||
(10, 5, 15, 7, 14, 11, 3, 9, 2, 8, 1, 12, 0, 4, 6, 13),
|
||||
(0, 14, 6, 11, 9, 3, 8, 4, 12, 15, 10, 5, 13, 7, 1, 2),
|
||||
(9, 2, 11, 12, 0, 4, 5, 6, 3, 15, 13, 8, 1, 7, 14, 10),
|
||||
(4, 0, 14, 1, 5, 11, 8, 3, 12, 2, 9, 7, 6, 10, 13, 15),
|
||||
(7, 14, 12, 13, 9, 4, 8, 15, 10, 2, 6, 0, 3, 11, 5, 1),
|
||||
),
|
||||
}
|
||||
SBOXES["AppliedCryptography"] = SBOXES["id-GostR3411-94-TestParamSet"]
|
||||
|
||||
|
||||
def _K(s, _in):
|
||||
"""S-box substitution
|
||||
|
||||
:param s: S-box
|
||||
:param _in: 32-bit word
|
||||
:returns: substituted 32-bit word
|
||||
"""
|
||||
return (
|
||||
(s[0][(_in >> 0) & 0x0F] << 0) +
|
||||
(s[1][(_in >> 4) & 0x0F] << 4) +
|
||||
(s[2][(_in >> 8) & 0x0F] << 8) +
|
||||
(s[3][(_in >> 12) & 0x0F] << 12) +
|
||||
(s[4][(_in >> 16) & 0x0F] << 16) +
|
||||
(s[5][(_in >> 20) & 0x0F] << 20) +
|
||||
(s[6][(_in >> 24) & 0x0F] << 24) +
|
||||
(s[7][(_in >> 28) & 0x0F] << 28)
|
||||
)
|
||||
|
||||
|
||||
def block2ns(data):
|
||||
"""Convert block to N1 and N2 integers
|
||||
"""
|
||||
data = bytearray(data)
|
||||
return (
|
||||
data[0] | data[1] << 8 | data[2] << 16 | data[3] << 24,
|
||||
data[4] | data[5] << 8 | data[6] << 16 | data[7] << 24,
|
||||
)
|
||||
|
||||
|
||||
def ns2block(ns):
|
||||
"""Convert N1 and N2 integers to 8-byte block
|
||||
"""
|
||||
n1, n2 = ns
|
||||
return bytes(bytearray((
|
||||
(n2 >> 0) & 0xFF, (n2 >> 8) & 0xFF, (n2 >> 16) & 0xFF, (n2 >> 24) & 0xFF,
|
||||
(n1 >> 0) & 0xFF, (n1 >> 8) & 0xFF, (n1 >> 16) & 0xFF, (n1 >> 24) & 0xFF,
|
||||
)))
|
||||
|
||||
|
||||
def _shift11(x):
|
||||
"""11-bit cyclic shift
|
||||
"""
|
||||
return ((x << 11) & (2 ** 32 - 1)) | ((x >> (32 - 11)) & (2 ** 32 - 1))
|
||||
|
||||
|
||||
def validate_key(key):
|
||||
if len(key) != KEYSIZE:
|
||||
raise ValueError("Invalid key size")
|
||||
|
||||
|
||||
def validate_iv(iv):
|
||||
if len(iv) != BLOCKSIZE:
|
||||
raise ValueError("Invalid IV size")
|
||||
|
||||
|
||||
def validate_sbox(sbox):
|
||||
if sbox not in SBOXES:
|
||||
raise ValueError("Unknown sbox supplied")
|
||||
|
||||
|
||||
def xcrypt(seq, sbox, key, ns):
|
||||
"""Perform full-round single-block operation
|
||||
|
||||
:param seq: sequence of K_i S-box applying (either encrypt or decrypt)
|
||||
:param sbox: S-box parameters to use
|
||||
:type sbox: str, SBOXES'es key
|
||||
:param bytes key: 256-bit encryption key
|
||||
:param ns: N1 and N2 integers
|
||||
:type ns: (int, int)
|
||||
:returns: resulting N1 and N2
|
||||
:rtype: (int, int)
|
||||
"""
|
||||
s = SBOXES[sbox]
|
||||
w = bytearray(key)
|
||||
x = [
|
||||
w[0 + i * 4] |
|
||||
w[1 + i * 4] << 8 |
|
||||
w[2 + i * 4] << 16 |
|
||||
w[3 + i * 4] << 24 for i in range(8)
|
||||
]
|
||||
n1, n2 = ns
|
||||
for i in seq:
|
||||
n1, n2 = _shift11(_K(s, (n1 + x[i]) % (2 ** 32))) ^ n2, n1
|
||||
return n1, n2
|
||||
|
||||
|
||||
def encrypt(sbox, key, ns):
|
||||
"""Encrypt single block
|
||||
"""
|
||||
return xcrypt(SEQ_ENCRYPT, sbox, key, ns)
|
||||
|
||||
|
||||
def decrypt(sbox, key, ns):
|
||||
"""Decrypt single block
|
||||
"""
|
||||
return xcrypt(SEQ_DECRYPT, sbox, key, ns)
|
||||
|
||||
|
||||
def ecb(key, data, action, sbox=DEFAULT_SBOX):
|
||||
"""ECB mode of operation
|
||||
|
||||
:param bytes key: encryption key
|
||||
:param data: plaintext
|
||||
:type data: bytes, multiple of BLOCKSIZE
|
||||
:param func action: "encrypt"/"decrypt"
|
||||
:param sbox: S-box parameters to use
|
||||
:type sbox: str, SBOXES'es key
|
||||
:returns: ciphertext
|
||||
:rtype: bytes
|
||||
"""
|
||||
validate_key(key)
|
||||
validate_sbox(sbox)
|
||||
if not data or len(data) % BLOCKSIZE != 0:
|
||||
raise ValueError("Data is not blocksize aligned")
|
||||
result = []
|
||||
for i in xrange(0, len(data), BLOCKSIZE):
|
||||
result.append(ns2block(action(
|
||||
sbox, key, block2ns(data[i:i + BLOCKSIZE])
|
||||
)))
|
||||
return b"".join(result)
|
||||
|
||||
|
||||
ecb_encrypt = partial(ecb, action=encrypt)
|
||||
ecb_decrypt = partial(ecb, action=decrypt)
|
||||
|
||||
|
||||
def cbc_encrypt(key, data, iv=8 * b"\x00", pad=True, sbox=DEFAULT_SBOX, mesh=False):
|
||||
"""CBC encryption mode of operation
|
||||
|
||||
:param bytes key: encryption key
|
||||
:param bytes data: plaintext
|
||||
:param iv: initialization vector
|
||||
:type iv: bytes, BLOCKSIZE length
|
||||
:type bool pad: perform ISO/IEC 7816-4 padding
|
||||
:param sbox: S-box parameters to use
|
||||
:type sbox: str, SBOXES'es key
|
||||
:param bool mesh: enable key meshing
|
||||
:returns: ciphertext
|
||||
:rtype: bytes
|
||||
|
||||
34.13-2015 padding method 2 is used.
|
||||
"""
|
||||
validate_key(key)
|
||||
validate_iv(iv)
|
||||
validate_sbox(sbox)
|
||||
if not data:
|
||||
raise ValueError("No data supplied")
|
||||
if pad:
|
||||
data = pad2(data, BLOCKSIZE)
|
||||
if len(data) % BLOCKSIZE != 0:
|
||||
raise ValueError("Data is not blocksize aligned")
|
||||
ciphertext = [iv]
|
||||
for i in xrange(0, len(data), BLOCKSIZE):
|
||||
if mesh and i >= MESH_MAX_DATA and i % MESH_MAX_DATA == 0:
|
||||
key, _ = meshing(key, iv, sbox=sbox)
|
||||
ciphertext.append(ns2block(encrypt(sbox, key, block2ns(
|
||||
strxor(ciphertext[-1], data[i:i + BLOCKSIZE])
|
||||
))))
|
||||
return b"".join(ciphertext)
|
||||
|
||||
|
||||
def cbc_decrypt(key, data, pad=True, sbox=DEFAULT_SBOX, mesh=False):
|
||||
"""CBC decryption mode of operation
|
||||
|
||||
:param bytes key: encryption key
|
||||
:param bytes data: ciphertext
|
||||
:type bool pad: perform ISO/IEC 7816-4 unpadding after decryption
|
||||
:param sbox: S-box parameters to use
|
||||
:type sbox: str, SBOXES'es key
|
||||
:param bool mesh: enable key meshing
|
||||
:returns: plaintext
|
||||
:rtype: bytes
|
||||
"""
|
||||
validate_key(key)
|
||||
validate_sbox(sbox)
|
||||
if not data or len(data) % BLOCKSIZE != 0:
|
||||
raise ValueError("Data is not blocksize aligned")
|
||||
if len(data) < 2 * BLOCKSIZE:
|
||||
raise ValueError("There is no either data, or IV in ciphertext")
|
||||
iv = data[:BLOCKSIZE]
|
||||
plaintext = []
|
||||
for i in xrange(BLOCKSIZE, len(data), BLOCKSIZE):
|
||||
if (
|
||||
mesh and
|
||||
(i - BLOCKSIZE) >= MESH_MAX_DATA and
|
||||
(i - BLOCKSIZE) % MESH_MAX_DATA == 0
|
||||
):
|
||||
key, _ = meshing(key, iv, sbox=sbox)
|
||||
plaintext.append(strxor(
|
||||
ns2block(decrypt(sbox, key, block2ns(data[i:i + BLOCKSIZE]))),
|
||||
data[i - BLOCKSIZE:i],
|
||||
))
|
||||
if pad:
|
||||
plaintext[-1] = unpad2(plaintext[-1], BLOCKSIZE)
|
||||
return b"".join(plaintext)
|
||||
|
||||
|
||||
def cnt(key, data, iv=8 * b"\x00", sbox=DEFAULT_SBOX):
|
||||
"""Counter mode of operation
|
||||
|
||||
:param bytes key: encryption key
|
||||
:param bytes data: plaintext
|
||||
:param iv: initialization vector
|
||||
:type iv: bytes, BLOCKSIZE length
|
||||
:param sbox: S-box parameters to use
|
||||
:type sbox: str, SBOXES'es key
|
||||
:returns: ciphertext
|
||||
:rtype: bytes
|
||||
|
||||
For decryption you use the same function again.
|
||||
"""
|
||||
validate_key(key)
|
||||
validate_iv(iv)
|
||||
validate_sbox(sbox)
|
||||
if not data:
|
||||
raise ValueError("No data supplied")
|
||||
n2, n1 = encrypt(sbox, key, block2ns(iv))
|
||||
gamma = []
|
||||
for _ in xrange(0, len(data) + pad_size(len(data), BLOCKSIZE), BLOCKSIZE):
|
||||
n1 = (n1 + C2) % (2 ** 32)
|
||||
n2 = (n2 + C1) % (2 ** 32 - 1)
|
||||
gamma.append(ns2block(encrypt(sbox, key, (n1, n2))))
|
||||
return strxor(b"".join(gamma), data)
|
||||
|
||||
|
||||
MESH_CONST = hexdec("6900722264C904238D3ADB9646E92AC418FEAC9400ED0712C086DCC2EF4CA92B")
|
||||
MESH_MAX_DATA = 1024
|
||||
|
||||
|
||||
def meshing(key, iv, sbox=DEFAULT_SBOX):
|
||||
""":rfc:`4357` key meshing
|
||||
"""
|
||||
key = ecb_decrypt(key, MESH_CONST, sbox=sbox)
|
||||
iv = ecb_encrypt(key, iv, sbox=sbox)
|
||||
return key, iv
|
||||
|
||||
|
||||
def cfb_encrypt(key, data, iv=8 * b"\x00", sbox=DEFAULT_SBOX, mesh=False):
|
||||
"""CFB encryption mode of operation
|
||||
|
||||
:param bytes key: encryption key
|
||||
:param bytes data: plaintext
|
||||
:param iv: initialization vector
|
||||
:type iv: bytes, BLOCKSIZE length
|
||||
:param sbox: S-box parameters to use
|
||||
:type sbox: str, SBOXES'es key
|
||||
:param bool mesh: enable key meshing
|
||||
:returns: ciphertext
|
||||
:rtype: bytes
|
||||
"""
|
||||
validate_key(key)
|
||||
validate_iv(iv)
|
||||
validate_sbox(sbox)
|
||||
if not data:
|
||||
raise ValueError("No data supplied")
|
||||
ciphertext = [iv]
|
||||
for i in xrange(0, len(data) + pad_size(len(data), BLOCKSIZE), BLOCKSIZE):
|
||||
if mesh and i >= MESH_MAX_DATA and i % MESH_MAX_DATA == 0:
|
||||
key, iv = meshing(key, ciphertext[-1], sbox=sbox)
|
||||
ciphertext.append(strxor(
|
||||
data[i:i + BLOCKSIZE],
|
||||
ns2block(encrypt(sbox, key, block2ns(iv))),
|
||||
))
|
||||
continue
|
||||
ciphertext.append(strxor(
|
||||
data[i:i + BLOCKSIZE],
|
||||
ns2block(encrypt(sbox, key, block2ns(ciphertext[-1]))),
|
||||
))
|
||||
return b"".join(ciphertext[1:])
|
||||
|
||||
|
||||
def cfb_decrypt(key, data, iv=8 * b"\x00", sbox=DEFAULT_SBOX, mesh=False):
|
||||
"""CFB decryption mode of operation
|
||||
|
||||
:param bytes key: encryption key
|
||||
:param bytes data: plaintext
|
||||
:param iv: initialization vector
|
||||
:type iv: bytes, BLOCKSIZE length
|
||||
:param sbox: S-box parameters to use
|
||||
:type sbox: str, SBOXES'es key
|
||||
:param bool mesh: enable key meshing
|
||||
:returns: ciphertext
|
||||
:rtype: bytes
|
||||
"""
|
||||
validate_key(key)
|
||||
validate_iv(iv)
|
||||
validate_sbox(sbox)
|
||||
if not data:
|
||||
raise ValueError("No data supplied")
|
||||
plaintext = []
|
||||
data = iv + data
|
||||
for i in xrange(BLOCKSIZE, len(data) + pad_size(len(data), BLOCKSIZE), BLOCKSIZE):
|
||||
if (
|
||||
mesh and
|
||||
(i - BLOCKSIZE) >= MESH_MAX_DATA and
|
||||
(i - BLOCKSIZE) % MESH_MAX_DATA == 0
|
||||
):
|
||||
key, iv = meshing(key, data[i - BLOCKSIZE:i], sbox=sbox)
|
||||
plaintext.append(strxor(
|
||||
data[i:i + BLOCKSIZE],
|
||||
ns2block(encrypt(sbox, key, block2ns(iv))),
|
||||
))
|
||||
continue
|
||||
plaintext.append(strxor(
|
||||
data[i:i + BLOCKSIZE],
|
||||
ns2block(encrypt(sbox, key, block2ns(data[i - BLOCKSIZE:i]))),
|
||||
))
|
||||
return b"".join(plaintext)
|
||||
@ -1,99 +0,0 @@
|
||||
# coding: utf-8
|
||||
# PyGOST -- Pure Python GOST cryptographic functions library
|
||||
# Copyright (C) 2015-2023 Sergey Matveev <stargrave@stargrave.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, version 3 of the License.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
"""GOST 28147-89 MAC
|
||||
"""
|
||||
|
||||
from copy import copy
|
||||
|
||||
from pygost.gost28147 import block2ns
|
||||
from pygost.gost28147 import BLOCKSIZE
|
||||
from pygost.gost28147 import DEFAULT_SBOX
|
||||
from pygost.gost28147 import ns2block
|
||||
from pygost.gost28147 import validate_iv
|
||||
from pygost.gost28147 import validate_key
|
||||
from pygost.gost28147 import validate_sbox
|
||||
from pygost.gost28147 import xcrypt
|
||||
from pygost.gost3413 import pad1
|
||||
from pygost.iface import PEP247
|
||||
from pygost.utils import strxor
|
||||
from pygost.utils import xrange
|
||||
|
||||
digest_size = 8
|
||||
SEQ_MAC = (
|
||||
0, 1, 2, 3, 4, 5, 6, 7,
|
||||
0, 1, 2, 3, 4, 5, 6, 7,
|
||||
)
|
||||
|
||||
|
||||
class MAC(PEP247):
|
||||
"""GOST 28147-89 MAC mode of operation
|
||||
|
||||
>>> m = MAC(key=key)
|
||||
>>> m.update("some data")
|
||||
>>> m.update("another data")
|
||||
>>> m.hexdigest()[:8]
|
||||
'a687a08b'
|
||||
"""
|
||||
digest_size = digest_size
|
||||
|
||||
def __init__(self, key, data=b"", iv=8 * b"\x00", sbox=DEFAULT_SBOX):
|
||||
"""
|
||||
:param key: authentication key
|
||||
:type key: bytes, 32 bytes
|
||||
:param iv: initialization vector
|
||||
:type iv: bytes, BLOCKSIZE length
|
||||
:param sbox: S-box parameters to use
|
||||
:type sbox: str, SBOXES'es key
|
||||
"""
|
||||
validate_key(key)
|
||||
validate_iv(iv)
|
||||
validate_sbox(sbox)
|
||||
self.key = key
|
||||
self.data = data
|
||||
self.iv = iv
|
||||
self.sbox = sbox
|
||||
|
||||
def copy(self):
|
||||
return MAC(self.key, copy(self.data), self.iv, self.sbox)
|
||||
|
||||
def update(self, data):
|
||||
"""Append data that has to be authenticated
|
||||
"""
|
||||
self.data += data
|
||||
|
||||
def digest(self):
|
||||
"""Get MAC tag of supplied data
|
||||
|
||||
You have to provide at least single byte of data.
|
||||
If you want to produce tag length of 3 bytes, then
|
||||
``digest()[:3]``.
|
||||
"""
|
||||
if not self.data:
|
||||
raise ValueError("No data processed")
|
||||
data = pad1(self.data, BLOCKSIZE)
|
||||
prev = block2ns(self.iv)[::-1]
|
||||
for i in xrange(0, len(data), BLOCKSIZE):
|
||||
prev = xcrypt(
|
||||
SEQ_MAC, self.sbox, self.key, block2ns(strxor(
|
||||
data[i:i + BLOCKSIZE],
|
||||
ns2block(prev),
|
||||
)),
|
||||
)[::-1]
|
||||
return ns2block(prev)
|
||||
|
||||
|
||||
def new(key, data=b"", iv=8 * b"\x00", sbox=DEFAULT_SBOX):
|
||||
return MAC(key, data, iv, sbox)
|
||||
@ -1,412 +0,0 @@
|
||||
# coding: utf-8
|
||||
# PyGOST -- Pure Python GOST cryptographic functions library
|
||||
# Copyright (C) 2015-2023 Sergey Matveev <stargrave@stargrave.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, version 3 of the License.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
"""GOST R 34.10 public-key signature function.
|
||||
|
||||
This is implementation of GOST R 34.10-2001 (:rfc:`5832`), GOST R
|
||||
34.10-2012 (:rfc:`7091`). The difference between 2001 and 2012 is the
|
||||
key, digest and signature lengths.
|
||||
"""
|
||||
|
||||
from os import urandom
|
||||
|
||||
from pygost.utils import bytes2long
|
||||
from pygost.utils import hexdec
|
||||
from pygost.utils import long2bytes
|
||||
from pygost.utils import modinvert
|
||||
|
||||
|
||||
def point_size(point):
|
||||
"""Determine is it either 256 or 512 bit point
|
||||
"""
|
||||
return (512 // 8) if point.bit_length() > 256 else (256 // 8)
|
||||
|
||||
|
||||
class GOST3410Curve(object):
|
||||
"""GOST 34.10 validated curve
|
||||
|
||||
>>> curve = CURVES["id-GostR3410-2001-TestParamSet"]
|
||||
>>> prv = prv_unmarshal(urandom(32))
|
||||
>>> signature = sign(curve, prv, GOST341194(data).digest())
|
||||
>>> pub = public_key(curve, prv)
|
||||
>>> verify(curve, pub, GOST341194(data).digest(), signature)
|
||||
True
|
||||
|
||||
:param long p: characteristic of the underlying prime field
|
||||
:param long q: elliptic curve subgroup order
|
||||
:param long a, b: coefficients of the equation of the elliptic curve in
|
||||
the canonical form
|
||||
:param long x, y: the coordinate of the point P (generator of the
|
||||
subgroup of order q) of the elliptic curve in
|
||||
the canonical form
|
||||
:param long e, d: coefficients of the equation of the elliptic curve in
|
||||
the twisted Edwards form
|
||||
:param str name: human-readable curve name
|
||||
"""
|
||||
|
||||
def __init__(self, p, q, a, b, x, y, cofactor=1, e=None, d=None, name=None):
|
||||
self.p = p
|
||||
self.q = q
|
||||
self.a = a
|
||||
self.b = b
|
||||
self.x = x
|
||||
self.y = y
|
||||
self.cofactor = cofactor
|
||||
self.e = e
|
||||
self.d = d
|
||||
if not self.contains((x, y)):
|
||||
raise ValueError("Invalid parameters")
|
||||
self._st = None
|
||||
self.name = name
|
||||
|
||||
@property
|
||||
def point_size(self):
|
||||
return point_size(self.p)
|
||||
|
||||
def __repr__(self):
|
||||
return "<%s: %s>" % (self.__class__.__name__, self.name)
|
||||
|
||||
def pos(self, v):
|
||||
"""Make positive number
|
||||
"""
|
||||
if v < 0:
|
||||
return v + self.p
|
||||
return v
|
||||
|
||||
def contains(self, point):
|
||||
"""Is point on the curve?
|
||||
|
||||
:type point: (long, long)
|
||||
"""
|
||||
x, y = point
|
||||
r1 = y * y % self.p
|
||||
r2 = ((x * x + self.a) * x + self.b) % self.p
|
||||
return r1 == self.pos(r2)
|
||||
|
||||
def _add(self, p1x, p1y, p2x, p2y):
|
||||
if p1x == p2x and p1y == p2y:
|
||||
# double
|
||||
t = ((3 * p1x * p1x + self.a) * modinvert(2 * p1y, self.p)) % self.p
|
||||
else:
|
||||
tx = self.pos(p2x - p1x) % self.p
|
||||
ty = self.pos(p2y - p1y) % self.p
|
||||
t = (ty * modinvert(tx, self.p)) % self.p
|
||||
tx = self.pos(t * t - p1x - p2x) % self.p
|
||||
ty = self.pos(t * (p1x - tx) - p1y) % self.p
|
||||
return tx, ty
|
||||
|
||||
def exp(self, degree, x=None, y=None):
|
||||
x = x or self.x
|
||||
y = y or self.y
|
||||
tx = x
|
||||
ty = y
|
||||
if degree == 0:
|
||||
raise ValueError("Bad degree value")
|
||||
degree -= 1
|
||||
while degree != 0:
|
||||
if degree & 1 == 1:
|
||||
tx, ty = self._add(tx, ty, x, y)
|
||||
degree = degree >> 1
|
||||
x, y = self._add(x, y, x, y)
|
||||
return tx, ty
|
||||
|
||||
def st(self):
|
||||
"""Compute s/t parameters for twisted Edwards curve points conversion
|
||||
"""
|
||||
if self.e is None or self.d is None:
|
||||
raise ValueError("Non twisted Edwards curve")
|
||||
if self._st is not None:
|
||||
return self._st
|
||||
self._st = (
|
||||
self.pos(self.e - self.d) * modinvert(4, self.p) % self.p,
|
||||
(self.e + self.d) * modinvert(6, self.p) % self.p,
|
||||
)
|
||||
return self._st
|
||||
|
||||
|
||||
CURVES = {
|
||||
"GostR3410_2001_ParamSet_cc": GOST3410Curve(
|
||||
p=bytes2long(hexdec("C0000000000000000000000000000000000000000000000000000000000003C7")),
|
||||
q=bytes2long(hexdec("5fffffffffffffffffffffffffffffff606117a2f4bde428b7458a54b6e87b85")),
|
||||
a=bytes2long(hexdec("C0000000000000000000000000000000000000000000000000000000000003c4")),
|
||||
b=bytes2long(hexdec("2d06B4265ebc749ff7d0f1f1f88232e81632e9088fd44b7787d5e407e955080c")),
|
||||
x=bytes2long(hexdec("0000000000000000000000000000000000000000000000000000000000000002")),
|
||||
y=bytes2long(hexdec("a20e034bf8813ef5c18d01105e726a17eb248b264ae9706f440bedc8ccb6b22c")),
|
||||
),
|
||||
"id-GostR3410-2001-TestParamSet": GOST3410Curve(
|
||||
p=bytes2long(hexdec("8000000000000000000000000000000000000000000000000000000000000431")),
|
||||
q=bytes2long(hexdec("8000000000000000000000000000000150FE8A1892976154C59CFC193ACCF5B3")),
|
||||
a=bytes2long(hexdec("0000000000000000000000000000000000000000000000000000000000000007")),
|
||||
b=bytes2long(hexdec("5FBFF498AA938CE739B8E022FBAFEF40563F6E6A3472FC2A514C0CE9DAE23B7E")),
|
||||
x=bytes2long(hexdec("0000000000000000000000000000000000000000000000000000000000000002")),
|
||||
y=bytes2long(hexdec("08E2A8A0E65147D4BD6316030E16D19C85C97F0A9CA267122B96ABBCEA7E8FC8")),
|
||||
),
|
||||
"id-tc26-gost-3410-12-256-paramSetA": GOST3410Curve(
|
||||
p=bytes2long(hexdec("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD97")),
|
||||
q=bytes2long(hexdec("400000000000000000000000000000000FD8CDDFC87B6635C115AF556C360C67")),
|
||||
a=bytes2long(hexdec("C2173F1513981673AF4892C23035A27CE25E2013BF95AA33B22C656F277E7335")),
|
||||
b=bytes2long(hexdec("295F9BAE7428ED9CCC20E7C359A9D41A22FCCD9108E17BF7BA9337A6F8AE9513")),
|
||||
x=bytes2long(hexdec("91E38443A5E82C0D880923425712B2BB658B9196932E02C78B2582FE742DAA28")),
|
||||
y=bytes2long(hexdec("32879423AB1A0375895786C4BB46E9565FDE0B5344766740AF268ADB32322E5C")),
|
||||
cofactor=4,
|
||||
e=0x01,
|
||||
d=bytes2long(hexdec("0605F6B7C183FA81578BC39CFAD518132B9DF62897009AF7E522C32D6DC7BFFB")),
|
||||
),
|
||||
"id-tc26-gost-3410-12-256-paramSetB": GOST3410Curve(
|
||||
p=bytes2long(hexdec("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD97")),
|
||||
q=bytes2long(hexdec("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6C611070995AD10045841B09B761B893")),
|
||||
a=bytes2long(hexdec("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD94")),
|
||||
b=bytes2long(hexdec("00000000000000000000000000000000000000000000000000000000000000a6")),
|
||||
x=bytes2long(hexdec("0000000000000000000000000000000000000000000000000000000000000001")),
|
||||
y=bytes2long(hexdec("8D91E471E0989CDA27DF505A453F2B7635294F2DDF23E3B122ACC99C9E9F1E14")),
|
||||
),
|
||||
"id-tc26-gost-3410-12-256-paramSetC": GOST3410Curve(
|
||||
p=bytes2long(hexdec("8000000000000000000000000000000000000000000000000000000000000C99")),
|
||||
q=bytes2long(hexdec("800000000000000000000000000000015F700CFFF1A624E5E497161BCC8A198F")),
|
||||
a=bytes2long(hexdec("8000000000000000000000000000000000000000000000000000000000000C96")),
|
||||
b=bytes2long(hexdec("3E1AF419A269A5F866A7D3C25C3DF80AE979259373FF2B182F49D4CE7E1BBC8B")),
|
||||
x=bytes2long(hexdec("0000000000000000000000000000000000000000000000000000000000000001")),
|
||||
y=bytes2long(hexdec("3FA8124359F96680B83D1C3EB2C070E5C545C9858D03ECFB744BF8D717717EFC")),
|
||||
),
|
||||
"id-tc26-gost-3410-12-256-paramSetD": GOST3410Curve(
|
||||
p=bytes2long(hexdec("9B9F605F5A858107AB1EC85E6B41C8AACF846E86789051D37998F7B9022D759B")),
|
||||
q=bytes2long(hexdec("9B9F605F5A858107AB1EC85E6B41C8AA582CA3511EDDFB74F02F3A6598980BB9")),
|
||||
a=bytes2long(hexdec("9B9F605F5A858107AB1EC85E6B41C8AACF846E86789051D37998F7B9022D7598")),
|
||||
b=bytes2long(hexdec("000000000000000000000000000000000000000000000000000000000000805a")),
|
||||
x=bytes2long(hexdec("0000000000000000000000000000000000000000000000000000000000000000")),
|
||||
y=bytes2long(hexdec("41ECE55743711A8C3CBF3783CD08C0EE4D4DC440D4641A8F366E550DFDB3BB67")),
|
||||
),
|
||||
"id-tc26-gost-3410-12-512-paramSetTest": GOST3410Curve(
|
||||
p=bytes2long(hexdec("4531ACD1FE0023C7550D267B6B2FEE80922B14B2FFB90F04D4EB7C09B5D2D15DF1D852741AF4704A0458047E80E4546D35B8336FAC224DD81664BBF528BE6373")),
|
||||
q=bytes2long(hexdec("4531ACD1FE0023C7550D267B6B2FEE80922B14B2FFB90F04D4EB7C09B5D2D15DA82F2D7ECB1DBAC719905C5EECC423F1D86E25EDBE23C595D644AAF187E6E6DF")),
|
||||
a=7,
|
||||
b=bytes2long(hexdec("1CFF0806A31116DA29D8CFA54E57EB748BC5F377E49400FDD788B649ECA1AC4361834013B2AD7322480A89CA58E0CF74BC9E540C2ADD6897FAD0A3084F302ADC")),
|
||||
x=bytes2long(hexdec("24D19CC64572EE30F396BF6EBBFD7A6C5213B3B3D7057CC825F91093A68CD762FD60611262CD838DC6B60AA7EEE804E28BC849977FAC33B4B530F1B120248A9A")),
|
||||
y=bytes2long(hexdec("2BB312A43BD2CE6E0D020613C857ACDDCFBF061E91E5F2C3F32447C259F39B2C83AB156D77F1496BF7EB3351E1EE4E43DC1A18B91B24640B6DBB92CB1ADD371E")),
|
||||
),
|
||||
"id-tc26-gost-3410-12-512-paramSetA": GOST3410Curve(
|
||||
p=bytes2long(hexdec("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDC7")),
|
||||
q=bytes2long(hexdec("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF27E69532F48D89116FF22B8D4E0560609B4B38ABFAD2B85DCACDB1411F10B275")),
|
||||
a=bytes2long(hexdec("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDC4")),
|
||||
b=bytes2long(hexdec("E8C2505DEDFC86DDC1BD0B2B6667F1DA34B82574761CB0E879BD081CFD0B6265EE3CB090F30D27614CB4574010DA90DD862EF9D4EBEE4761503190785A71C760")),
|
||||
x=bytes2long(hexdec("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003")),
|
||||
y=bytes2long(hexdec("7503CFE87A836AE3A61B8816E25450E6CE5E1C93ACF1ABC1778064FDCBEFA921DF1626BE4FD036E93D75E6A50E3A41E98028FE5FC235F5B889A589CB5215F2A4")),
|
||||
),
|
||||
"id-tc26-gost-3410-12-512-paramSetB": GOST3410Curve(
|
||||
p=bytes2long(hexdec("8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006F")),
|
||||
q=bytes2long(hexdec("800000000000000000000000000000000000000000000000000000000000000149A1EC142565A545ACFDB77BD9D40CFA8B996712101BEA0EC6346C54374F25BD")),
|
||||
a=bytes2long(hexdec("8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006C")),
|
||||
b=bytes2long(hexdec("687D1B459DC841457E3E06CF6F5E2517B97C7D614AF138BCBF85DC806C4B289F3E965D2DB1416D217F8B276FAD1AB69C50F78BEE1FA3106EFB8CCBC7C5140116")),
|
||||
x=bytes2long(hexdec("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002")),
|
||||
y=bytes2long(hexdec("1A8F7EDA389B094C2C071E3647A8940F3C123B697578C213BE6DD9E6C8EC7335DCB228FD1EDF4A39152CBCAAF8C0398828041055F94CEEEC7E21340780FE41BD")),
|
||||
),
|
||||
"id-tc26-gost-3410-12-512-paramSetC": GOST3410Curve(
|
||||
p=bytes2long(hexdec("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDC7")),
|
||||
q=bytes2long(hexdec("3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC98CDBA46506AB004C33A9FF5147502CC8EDA9E7A769A12694623CEF47F023ED")),
|
||||
a=bytes2long(hexdec("DC9203E514A721875485A529D2C722FB187BC8980EB866644DE41C68E143064546E861C0E2C9EDD92ADE71F46FCF50FF2AD97F951FDA9F2A2EB6546F39689BD3")),
|
||||
b=bytes2long(hexdec("B4C4EE28CEBC6C2C8AC12952CF37F16AC7EFB6A9F69F4B57FFDA2E4F0DE5ADE038CBC2FFF719D2C18DE0284B8BFEF3B52B8CC7A5F5BF0A3C8D2319A5312557E1")),
|
||||
x=bytes2long(hexdec("E2E31EDFC23DE7BDEBE241CE593EF5DE2295B7A9CBAEF021D385F7074CEA043AA27272A7AE602BF2A7B9033DB9ED3610C6FB85487EAE97AAC5BC7928C1950148")),
|
||||
y=bytes2long(hexdec("F5CE40D95B5EB899ABBCCFF5911CB8577939804D6527378B8C108C3D2090FF9BE18E2D33E3021ED2EF32D85822423B6304F726AA854BAE07D0396E9A9ADDC40F")),
|
||||
cofactor=4,
|
||||
e=0x01,
|
||||
d=bytes2long(hexdec("9E4F5D8C017D8D9F13A5CF3CDF5BFE4DAB402D54198E31EBDE28A0621050439CA6B39E0A515C06B304E2CE43E79E369E91A0CFC2BC2A22B4CA302DBB33EE7550")),
|
||||
),
|
||||
}
|
||||
CURVES["id-GostR3410-2001-CryptoPro-A-ParamSet"] = CURVES["id-tc26-gost-3410-12-256-paramSetB"]
|
||||
CURVES["id-GostR3410-2001-CryptoPro-B-ParamSet"] = CURVES["id-tc26-gost-3410-12-256-paramSetC"]
|
||||
CURVES["id-GostR3410-2001-CryptoPro-C-ParamSet"] = CURVES["id-tc26-gost-3410-12-256-paramSetD"]
|
||||
CURVES["id-GostR3410-2001-CryptoPro-XchA-ParamSet"] = CURVES["id-GostR3410-2001-CryptoPro-A-ParamSet"]
|
||||
CURVES["id-GostR3410-2001-CryptoPro-XchB-ParamSet"] = CURVES["id-GostR3410-2001-CryptoPro-C-ParamSet"]
|
||||
CURVES["id-tc26-gost-3410-2012-256-paramSetA"] = CURVES["id-tc26-gost-3410-12-256-paramSetA"]
|
||||
CURVES["id-tc26-gost-3410-2012-256-paramSetB"] = CURVES["id-tc26-gost-3410-12-256-paramSetB"]
|
||||
CURVES["id-tc26-gost-3410-2012-256-paramSetC"] = CURVES["id-tc26-gost-3410-12-256-paramSetC"]
|
||||
CURVES["id-tc26-gost-3410-2012-256-paramSetD"] = CURVES["id-tc26-gost-3410-12-256-paramSetD"]
|
||||
CURVES["id-tc26-gost-3410-2012-512-paramSetTest"] = CURVES["id-tc26-gost-3410-12-512-paramSetTest"]
|
||||
CURVES["id-tc26-gost-3410-2012-512-paramSetA"] = CURVES["id-tc26-gost-3410-12-512-paramSetA"]
|
||||
CURVES["id-tc26-gost-3410-2012-512-paramSetB"] = CURVES["id-tc26-gost-3410-12-512-paramSetB"]
|
||||
CURVES["id-tc26-gost-3410-2012-512-paramSetC"] = CURVES["id-tc26-gost-3410-12-512-paramSetC"]
|
||||
for _name, _curve in CURVES.items():
|
||||
_curve.name = _name
|
||||
DEFAULT_CURVE = CURVES["id-tc26-gost-3410-12-256-paramSetB"]
|
||||
|
||||
|
||||
def public_key(curve, prv, mask=None):
|
||||
"""Generate public key from the private one
|
||||
|
||||
:param GOST3410Curve curve: curve to use
|
||||
:param long prv: private key
|
||||
:returns: public key's parts, X and Y
|
||||
:rtype: (long, long)
|
||||
"""
|
||||
pub = curve.exp(prv)
|
||||
if mask is not None:
|
||||
pub = curve.exp(mask, pub[0], pub[1])
|
||||
return pub
|
||||
|
||||
|
||||
def sign(curve, prv, digest, rand=None, mask=None):
|
||||
"""Calculate signature for provided digest
|
||||
|
||||
:param GOST3410Curve curve: curve to use
|
||||
:param long prv: private key
|
||||
:param digest: digest for signing
|
||||
:type digest: bytes, 32 or 64 bytes
|
||||
:param rand: optional predefined random data used for k/r generation
|
||||
:type rand: bytes, 32 or 64 bytes
|
||||
:returns: signature, BE(S) || BE(R)
|
||||
:rtype: bytes, 64 or 128 bytes
|
||||
"""
|
||||
size = curve.point_size
|
||||
q = curve.q
|
||||
e = bytes2long(digest) % q
|
||||
if e == 0:
|
||||
e = 1
|
||||
while True:
|
||||
if rand is None:
|
||||
rand = urandom(size)
|
||||
elif len(rand) != size:
|
||||
raise ValueError("rand length != %d" % size)
|
||||
k = bytes2long(rand) % q
|
||||
if k == 0:
|
||||
continue
|
||||
r, y = curve.exp(k)
|
||||
if mask is not None:
|
||||
r, y = curve.exp(mask, x=r, y=y)
|
||||
r %= q
|
||||
if r == 0:
|
||||
continue
|
||||
d = prv * r
|
||||
k *= e
|
||||
s = d + k
|
||||
if mask is not None:
|
||||
s *= mask
|
||||
s %= q
|
||||
if s == 0:
|
||||
continue
|
||||
break
|
||||
return long2bytes(s, size) + long2bytes(r, size)
|
||||
|
||||
|
||||
def verify(curve, pub, digest, signature):
|
||||
"""Verify provided digest with the signature
|
||||
|
||||
:param GOST3410Curve curve: curve to use
|
||||
:type pub: (long, long)
|
||||
:param digest: digest needed to check
|
||||
:type digest: bytes, 32 or 64 bytes
|
||||
:param signature: signature to verify with
|
||||
:type signature: bytes, 64 or 128 bytes
|
||||
:rtype: bool
|
||||
"""
|
||||
size = curve.point_size
|
||||
if len(signature) != size * 2:
|
||||
raise ValueError("Invalid signature length")
|
||||
q = curve.q
|
||||
p = curve.p
|
||||
s = bytes2long(signature[:size])
|
||||
r = bytes2long(signature[size:])
|
||||
if r <= 0 or r >= q or s <= 0 or s >= q:
|
||||
return False
|
||||
e = bytes2long(digest) % curve.q
|
||||
if e == 0:
|
||||
e = 1
|
||||
v = modinvert(e, q)
|
||||
z1 = s * v % q
|
||||
z2 = q - r * v % q
|
||||
p1x, p1y = curve.exp(z1)
|
||||
q1x, q1y = curve.exp(z2, pub[0], pub[1])
|
||||
lm = q1x - p1x
|
||||
if lm < 0:
|
||||
lm += p
|
||||
lm = modinvert(lm, p)
|
||||
z1 = q1y - p1y
|
||||
lm = lm * z1 % p
|
||||
lm = lm * lm % p
|
||||
lm = lm - p1x - q1x
|
||||
lm = lm % p
|
||||
if lm < 0:
|
||||
lm += p
|
||||
lm %= q
|
||||
# This is not constant time comparison!
|
||||
return lm == r
|
||||
|
||||
|
||||
def prv_unmarshal(prv):
|
||||
"""Unmarshal little-endian private key
|
||||
|
||||
:param bytes prv: serialized private key
|
||||
:rtype: long
|
||||
|
||||
It is advisable to use :py:func:`pygost.gost3410.prv_marshal` to
|
||||
assure that key i in curve's Q field for better compatibility with
|
||||
some implementations.
|
||||
"""
|
||||
return bytes2long(prv[::-1])
|
||||
|
||||
|
||||
def prv_marshal(curve, prv):
|
||||
"""Marshal little-endian private key
|
||||
|
||||
:param GOST3410Curve curve: curve to use
|
||||
:param long prv: serialized private key
|
||||
:rtype: bytes
|
||||
|
||||
Key is in curve's Q field.
|
||||
"""
|
||||
return long2bytes(prv % curve.q, point_size(prv))[::-1]
|
||||
|
||||
|
||||
def pub_marshal(pub):
|
||||
"""Marshal public key
|
||||
|
||||
:type pub: (long, long)
|
||||
:rtype: bytes
|
||||
:returns: LE(X) || LE(Y)
|
||||
"""
|
||||
size = point_size(pub[0])
|
||||
return (long2bytes(pub[1], size) + long2bytes(pub[0], size))[::-1]
|
||||
|
||||
|
||||
def pub_unmarshal(pub):
|
||||
"""Unmarshal public key
|
||||
|
||||
:param pub: LE(X) || LE(Y)
|
||||
:type pub: bytes
|
||||
:rtype: (long, long)
|
||||
"""
|
||||
size = len(pub) // 2
|
||||
pub = pub[::-1]
|
||||
return (bytes2long(pub[size:]), bytes2long(pub[:size]))
|
||||
|
||||
|
||||
def uv2xy(curve, u, v):
|
||||
"""Convert twisted Edwards curve U,V coordinates to Weierstrass X,Y
|
||||
"""
|
||||
s, t = curve.st()
|
||||
k1 = (s * (1 + v)) % curve.p
|
||||
k2 = curve.pos(1 - v)
|
||||
x = t + k1 * modinvert(k2, curve.p)
|
||||
y = k1 * modinvert(u * k2, curve.p)
|
||||
return x % curve.p, y % curve.p
|
||||
|
||||
|
||||
def xy2uv(curve, x, y):
|
||||
"""Convert Weierstrass X,Y coordinates to twisted Edwards curve U,V
|
||||
"""
|
||||
s, t = curve.st()
|
||||
xmt = curve.pos(x - t)
|
||||
u = xmt * modinvert(y, curve.p)
|
||||
v = curve.pos(xmt - s) * modinvert(xmt + s, curve.p)
|
||||
return u % curve.p, v % curve.p
|
||||
@ -1,97 +0,0 @@
|
||||
# coding: utf-8
|
||||
# PyGOST -- Pure Python GOST cryptographic functions library
|
||||
# Copyright (C) 2015-2023 Sergey Matveev <stargrave@stargrave.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, version 3 of the License.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
"""Key agreement functions, VKO GOST R 34.10-2001/2012
|
||||
"""
|
||||
|
||||
from pygost.gost3410 import pub_marshal
|
||||
from pygost.gost34112012256 import GOST34112012256
|
||||
from pygost.gost34112012512 import GOST34112012512
|
||||
from pygost.gost341194 import GOST341194
|
||||
from pygost.utils import bytes2long
|
||||
|
||||
|
||||
def ukm_unmarshal(ukm):
|
||||
"""Unmarshal UKM value
|
||||
|
||||
:type ukm: little-endian bytes
|
||||
:rtype: long
|
||||
"""
|
||||
return bytes2long(ukm[::-1])
|
||||
|
||||
|
||||
def kek(curve, prv, pub, ukm, mask=None):
|
||||
if not curve.contains(pub):
|
||||
raise ValueError("pub is not on the curve")
|
||||
key = curve.exp(prv, pub[0], pub[1])
|
||||
key = curve.exp(curve.cofactor * ukm, key[0], key[1])
|
||||
if mask is not None:
|
||||
key = curve.exp(mask, key[0], key[1])
|
||||
return pub_marshal(key)
|
||||
|
||||
|
||||
def kek_34102001(curve, prv, pub, ukm):
|
||||
"""Key agreement (34.10-2001, 34.11-94)
|
||||
|
||||
:param GOST3410Curve curve: curve to use
|
||||
:param long prv: private key
|
||||
:param pub: public key
|
||||
:type pub: (long, long)
|
||||
:param long ukm: user keying material, VKO-factor
|
||||
:returns: Key Encryption Key (shared key)
|
||||
:rtype: bytes, 32 bytes
|
||||
|
||||
Shared Key Encryption Key computation is based on
|
||||
:rfc:`4357` VKO GOST R 34.10-2001 with little-endian
|
||||
hash output.
|
||||
"""
|
||||
return GOST341194(
|
||||
kek(curve, prv, pub, ukm),
|
||||
sbox="id-GostR3411-94-CryptoProParamSet",
|
||||
).digest()
|
||||
|
||||
|
||||
def kek_34102012256(curve, prv, pub, ukm=1):
|
||||
"""Key agreement (34.10-2012, 34.11-2012 256 bit)
|
||||
|
||||
:param GOST3410Curve curve: curve to use
|
||||
:param long prv: private key
|
||||
:param pub: public key
|
||||
:type pub: (long, long)
|
||||
:param long ukm: user keying material, VKO-factor
|
||||
:returns: Key Encryption Key (shared key)
|
||||
:rtype: bytes, 32 bytes
|
||||
|
||||
Shared Key Encryption Key computation is based on
|
||||
:rfc:`7836` VKO GOST R 34.10-2012.
|
||||
"""
|
||||
return GOST34112012256(kek(curve, prv, pub, ukm)).digest()
|
||||
|
||||
|
||||
def kek_34102012512(curve, prv, pub, ukm=1):
|
||||
"""Key agreement (34.10-2012, 34.11-2012 512 bit)
|
||||
|
||||
:param GOST3410Curve curve: curve to use
|
||||
:param long prv: private key
|
||||
:param pub: public key
|
||||
:type pub: (long, long)
|
||||
:param long ukm: user keying material, VKO-factor
|
||||
:returns: Key Encryption Key (shared key)
|
||||
:rtype: bytes, 32 bytes
|
||||
|
||||
Shared Key Encryption Key computation is based on
|
||||
:rfc:`7836` VKO GOST R 34.10-2012.
|
||||
"""
|
||||
return GOST34112012512(kek(curve, prv, pub, ukm)).digest()
|
||||
@ -1,299 +0,0 @@
|
||||
# coding: utf-8
|
||||
# PyGOST -- Pure Python GOST cryptographic functions library
|
||||
# Copyright (C) 2015-2023 Sergey Matveev <stargrave@stargrave.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, version 3 of the License.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
"""GOST R 34.11-2012 (Streebog) hash function common files
|
||||
|
||||
This is implementation of :rfc:`6986`. Most function and variable names are
|
||||
taken according to specification's terminology.
|
||||
"""
|
||||
|
||||
from copy import copy
|
||||
from struct import pack
|
||||
from struct import unpack
|
||||
|
||||
from pygost.iface import PEP247
|
||||
from pygost.utils import hexdec
|
||||
from pygost.utils import strxor
|
||||
from pygost.utils import xrange
|
||||
|
||||
|
||||
BLOCKSIZE = 64
|
||||
Pi = bytearray((
|
||||
252, 238, 221, 17, 207, 110, 49, 22, 251, 196, 250,
|
||||
218, 35, 197, 4, 77, 233, 119, 240, 219, 147, 46,
|
||||
153, 186, 23, 54, 241, 187, 20, 205, 95, 193, 249,
|
||||
24, 101, 90, 226, 92, 239, 33, 129, 28, 60, 66,
|
||||
139, 1, 142, 79, 5, 132, 2, 174, 227, 106, 143,
|
||||
160, 6, 11, 237, 152, 127, 212, 211, 31, 235, 52,
|
||||
44, 81, 234, 200, 72, 171, 242, 42, 104, 162, 253,
|
||||
58, 206, 204, 181, 112, 14, 86, 8, 12, 118, 18,
|
||||
191, 114, 19, 71, 156, 183, 93, 135, 21, 161, 150,
|
||||
41, 16, 123, 154, 199, 243, 145, 120, 111, 157, 158,
|
||||
178, 177, 50, 117, 25, 61, 255, 53, 138, 126, 109,
|
||||
84, 198, 128, 195, 189, 13, 87, 223, 245, 36, 169,
|
||||
62, 168, 67, 201, 215, 121, 214, 246, 124, 34, 185,
|
||||
3, 224, 15, 236, 222, 122, 148, 176, 188, 220, 232,
|
||||
40, 80, 78, 51, 10, 74, 167, 151, 96, 115, 30,
|
||||
0, 98, 68, 26, 184, 56, 130, 100, 159, 38, 65,
|
||||
173, 69, 70, 146, 39, 94, 85, 47, 140, 163, 165,
|
||||
125, 105, 213, 149, 59, 7, 88, 179, 64, 134, 172,
|
||||
29, 247, 48, 55, 107, 228, 136, 217, 231, 137, 225,
|
||||
27, 131, 73, 76, 63, 248, 254, 141, 83, 170, 144,
|
||||
202, 216, 133, 97, 32, 113, 103, 164, 45, 43, 9,
|
||||
91, 203, 155, 37, 208, 190, 229, 108, 82, 89, 166,
|
||||
116, 210, 230, 244, 180, 192, 209, 102, 175, 194, 57,
|
||||
75, 99, 182,
|
||||
))
|
||||
|
||||
A = [unpack(">Q", hexdec(s))[0] for s in (
|
||||
"8e20faa72ba0b470", "47107ddd9b505a38", "ad08b0e0c3282d1c", "d8045870ef14980e",
|
||||
"6c022c38f90a4c07", "3601161cf205268d", "1b8e0b0e798c13c8", "83478b07b2468764",
|
||||
"a011d380818e8f40", "5086e740ce47c920", "2843fd2067adea10", "14aff010bdd87508",
|
||||
"0ad97808d06cb404", "05e23c0468365a02", "8c711e02341b2d01", "46b60f011a83988e",
|
||||
"90dab52a387ae76f", "486dd4151c3dfdb9", "24b86a840e90f0d2", "125c354207487869",
|
||||
"092e94218d243cba", "8a174a9ec8121e5d", "4585254f64090fa0", "accc9ca9328a8950",
|
||||
"9d4df05d5f661451", "c0a878a0a1330aa6", "60543c50de970553", "302a1e286fc58ca7",
|
||||
"18150f14b9ec46dd", "0c84890ad27623e0", "0642ca05693b9f70", "0321658cba93c138",
|
||||
"86275df09ce8aaa8", "439da0784e745554", "afc0503c273aa42a", "d960281e9d1d5215",
|
||||
"e230140fc0802984", "71180a8960409a42", "b60c05ca30204d21", "5b068c651810a89e",
|
||||
"456c34887a3805b9", "ac361a443d1c8cd2", "561b0d22900e4669", "2b838811480723ba",
|
||||
"9bcf4486248d9f5d", "c3e9224312c8c1a0", "effa11af0964ee50", "f97d86d98a327728",
|
||||
"e4fa2054a80b329c", "727d102a548b194e", "39b008152acb8227", "9258048415eb419d",
|
||||
"492c024284fbaec0", "aa16012142f35760", "550b8e9e21f7a530", "a48b474f9ef5dc18",
|
||||
"70a6a56e2440598e", "3853dc371220a247", "1ca76e95091051ad", "0edd37c48a08a6d8",
|
||||
"07e095624504536c", "8d70c431ac02a736", "c83862965601dd1b", "641c314b2b8ee083",
|
||||
)]
|
||||
|
||||
Tau = (
|
||||
0, 8, 16, 24, 32, 40, 48, 56,
|
||||
1, 9, 17, 25, 33, 41, 49, 57,
|
||||
2, 10, 18, 26, 34, 42, 50, 58,
|
||||
3, 11, 19, 27, 35, 43, 51, 59,
|
||||
4, 12, 20, 28, 36, 44, 52, 60,
|
||||
5, 13, 21, 29, 37, 45, 53, 61,
|
||||
6, 14, 22, 30, 38, 46, 54, 62,
|
||||
7, 15, 23, 31, 39, 47, 55, 63,
|
||||
)
|
||||
|
||||
C = [hexdec("".join(s))[::-1] for s in (
|
||||
(
|
||||
"b1085bda1ecadae9ebcb2f81c0657c1f",
|
||||
"2f6a76432e45d016714eb88d7585c4fc",
|
||||
"4b7ce09192676901a2422a08a460d315",
|
||||
"05767436cc744d23dd806559f2a64507",
|
||||
),
|
||||
(
|
||||
"6fa3b58aa99d2f1a4fe39d460f70b5d7",
|
||||
"f3feea720a232b9861d55e0f16b50131",
|
||||
"9ab5176b12d699585cb561c2db0aa7ca",
|
||||
"55dda21bd7cbcd56e679047021b19bb7",
|
||||
),
|
||||
(
|
||||
"f574dcac2bce2fc70a39fc286a3d8435",
|
||||
"06f15e5f529c1f8bf2ea7514b1297b7b",
|
||||
"d3e20fe490359eb1c1c93a376062db09",
|
||||
"c2b6f443867adb31991e96f50aba0ab2",
|
||||
),
|
||||
(
|
||||
"ef1fdfb3e81566d2f948e1a05d71e4dd",
|
||||
"488e857e335c3c7d9d721cad685e353f",
|
||||
"a9d72c82ed03d675d8b71333935203be",
|
||||
"3453eaa193e837f1220cbebc84e3d12e",
|
||||
),
|
||||
(
|
||||
"4bea6bacad4747999a3f410c6ca92363",
|
||||
"7f151c1f1686104a359e35d7800fffbd",
|
||||
"bfcd1747253af5a3dfff00b723271a16",
|
||||
"7a56a27ea9ea63f5601758fd7c6cfe57",
|
||||
),
|
||||
(
|
||||
"ae4faeae1d3ad3d96fa4c33b7a3039c0",
|
||||
"2d66c4f95142a46c187f9ab49af08ec6",
|
||||
"cffaa6b71c9ab7b40af21f66c2bec6b6",
|
||||
"bf71c57236904f35fa68407a46647d6e",
|
||||
),
|
||||
(
|
||||
"f4c70e16eeaac5ec51ac86febf240954",
|
||||
"399ec6c7e6bf87c9d3473e33197a93c9",
|
||||
"0992abc52d822c3706476983284a0504",
|
||||
"3517454ca23c4af38886564d3a14d493",
|
||||
),
|
||||
(
|
||||
"9b1f5b424d93c9a703e7aa020c6e4141",
|
||||
"4eb7f8719c36de1e89b4443b4ddbc49a",
|
||||
"f4892bcb929b069069d18d2bd1a5c42f",
|
||||
"36acc2355951a8d9a47f0dd4bf02e71e",
|
||||
),
|
||||
(
|
||||
"378f5a541631229b944c9ad8ec165fde",
|
||||
"3a7d3a1b258942243cd955b7e00d0984",
|
||||
"800a440bdbb2ceb17b2b8a9aa6079c54",
|
||||
"0e38dc92cb1f2a607261445183235adb",
|
||||
),
|
||||
(
|
||||
"abbedea680056f52382ae548b2e4f3f3",
|
||||
"8941e71cff8a78db1fffe18a1b336103",
|
||||
"9fe76702af69334b7a1e6c303b7652f4",
|
||||
"3698fad1153bb6c374b4c7fb98459ced",
|
||||
),
|
||||
(
|
||||
"7bcd9ed0efc889fb3002c6cd635afe94",
|
||||
"d8fa6bbbebab07612001802114846679",
|
||||
"8a1d71efea48b9caefbacd1d7d476e98",
|
||||
"dea2594ac06fd85d6bcaa4cd81f32d1b",
|
||||
),
|
||||
(
|
||||
"378ee767f11631bad21380b00449b17a",
|
||||
"cda43c32bcdf1d77f82012d430219f9b",
|
||||
"5d80ef9d1891cc86e71da4aa88e12852",
|
||||
"faf417d5d9b21b9948bc924af11bd720",
|
||||
),
|
||||
)]
|
||||
|
||||
|
||||
def _lcache():
|
||||
cache = []
|
||||
for byteN in xrange(8):
|
||||
cache.append([0 for _ in xrange(256)])
|
||||
for byteN in xrange(8):
|
||||
for byteVal in xrange(256):
|
||||
res64 = 0
|
||||
val = byteVal
|
||||
for bitN in xrange(8):
|
||||
if val & 0x80 > 0:
|
||||
res64 ^= A[(7 - byteN) * 8 + bitN]
|
||||
val <<= 1
|
||||
cache[byteN][byteVal] = res64
|
||||
return cache
|
||||
|
||||
|
||||
# Trade memory for CPU for part of L() calculations
|
||||
LCache = _lcache()
|
||||
|
||||
|
||||
def add512bit(a, b):
|
||||
a = int.from_bytes(a, "little")
|
||||
b = int.from_bytes(b, "little")
|
||||
r = (a + b) % (1 << 512)
|
||||
return r.to_bytes(512 // 8, "little")
|
||||
|
||||
|
||||
def g(n, hsh, msg):
|
||||
res = E(LPS(strxor(hsh[:8], pack("<Q", n)) + hsh[8:]), msg)
|
||||
return strxor(strxor(res, hsh), msg)
|
||||
|
||||
|
||||
def E(k, msg):
|
||||
for i in range(12):
|
||||
msg = LPS(strxor(k, msg))
|
||||
k = LPS(strxor(k, C[i]))
|
||||
return strxor(k, msg)
|
||||
|
||||
|
||||
def LPS(data):
|
||||
return L(PS(bytearray(data)))
|
||||
|
||||
|
||||
def PS(data):
|
||||
res = bytearray(BLOCKSIZE)
|
||||
for i in range(BLOCKSIZE):
|
||||
res[Tau[i]] = Pi[data[i]]
|
||||
return res
|
||||
|
||||
|
||||
def L(data):
|
||||
res = []
|
||||
for i in range(8):
|
||||
res64 = 0
|
||||
for j in range(8):
|
||||
res64 ^= LCache[j][data[8 * i + j]]
|
||||
res.append(pack("<Q", res64))
|
||||
return b"".join(res)
|
||||
|
||||
|
||||
class GOST34112012(PEP247):
|
||||
"""GOST 34.11-2012 big-endian hash
|
||||
|
||||
>>> m = GOST34112012(digest_size=32)
|
||||
>>> m.update("foo")
|
||||
>>> m.update("bar")
|
||||
>>> m.hexdigest()
|
||||
'e3c9fd89226d93b489a9fe27d686806e24a514e3787bca053c698ec4616ceb78'
|
||||
"""
|
||||
block_size = BLOCKSIZE
|
||||
|
||||
def __init__(self, data=b"", digest_size=64):
|
||||
"""
|
||||
:param digest_size: hash digest size to compute
|
||||
:type digest_size: 32 or 64 bytes
|
||||
"""
|
||||
self._digest_size = digest_size
|
||||
self.hsh = BLOCKSIZE * (b"\x01" if digest_size == 32 else b"\x00")
|
||||
self.chk = bytearray(BLOCKSIZE * b"\x00")
|
||||
self.n = 0
|
||||
self.buf = b""
|
||||
self.update(data)
|
||||
|
||||
def copy(self):
|
||||
obj = GOST34112012()
|
||||
obj._digest_size = self._digest_size
|
||||
obj.hsh = self.hsh
|
||||
obj.chk = copy(self.chk)
|
||||
obj.n = self.n
|
||||
obj.buf = self.buf
|
||||
return obj
|
||||
|
||||
@property
|
||||
def digest_size(self):
|
||||
return self._digest_size
|
||||
|
||||
def _update_block(self, block):
|
||||
self.hsh = g(self.n, self.hsh, block)
|
||||
self.chk = add512bit(self.chk, block)
|
||||
self.n += 512
|
||||
|
||||
def update(self, data):
|
||||
"""Update state with the new data
|
||||
"""
|
||||
if len(self.buf) > 0:
|
||||
chunk_len = BLOCKSIZE - len(self.buf)
|
||||
self.buf += data[:chunk_len]
|
||||
data = data[chunk_len:]
|
||||
if len(self.buf) == BLOCKSIZE:
|
||||
self._update_block(self.buf)
|
||||
self.buf = b""
|
||||
while len(data) >= BLOCKSIZE:
|
||||
self._update_block(data[:BLOCKSIZE])
|
||||
data = data[BLOCKSIZE:]
|
||||
self.buf += data
|
||||
|
||||
def digest(self):
|
||||
"""Get hash of the provided data
|
||||
"""
|
||||
data = self.buf
|
||||
|
||||
# Padding
|
||||
padblock_size = len(data) * 8
|
||||
data += b"\x01"
|
||||
padlen = BLOCKSIZE - len(data)
|
||||
if padlen != BLOCKSIZE:
|
||||
data += b"\x00" * padlen
|
||||
|
||||
hsh = g(self.n, self.hsh, data)
|
||||
n = self.n + padblock_size
|
||||
chk = add512bit(self.chk, data)
|
||||
hsh = g(0, hsh, pack("<Q", n) + 56 * b"\x00")
|
||||
hsh = g(0, hsh, chk)
|
||||
return hsh[-self._digest_size:]
|
||||
@ -1,16 +0,0 @@
|
||||
"""GOST R 34.11-2012 (Streebog) 256-bit hash function
|
||||
|
||||
This is implementation of :rfc:`6986`. Most function and variable names are
|
||||
taken according to specification's terminology.
|
||||
"""
|
||||
|
||||
from pygost.gost34112012 import GOST34112012
|
||||
|
||||
|
||||
class GOST34112012256(GOST34112012):
|
||||
def __init__(self, data=b""):
|
||||
super(GOST34112012256, self).__init__(data, digest_size=32)
|
||||
|
||||
|
||||
def new(data=b""):
|
||||
return GOST34112012256(data)
|
||||
@ -1,21 +0,0 @@
|
||||
"""GOST R 34.11-2012 (Streebog) 512-bit hash function
|
||||
|
||||
This is implementation of :rfc:`6986`. Most function and variable names are
|
||||
taken according to specification's terminology.
|
||||
"""
|
||||
|
||||
from pygost.gost34112012 import GOST34112012
|
||||
from pygost.pbkdf2 import pbkdf2 as pbkdf2_base
|
||||
|
||||
|
||||
class GOST34112012512(GOST34112012):
|
||||
def __init__(self, data=b""):
|
||||
super(GOST34112012512, self).__init__(data, digest_size=64)
|
||||
|
||||
|
||||
def new(data=b""):
|
||||
return GOST34112012512(data)
|
||||
|
||||
|
||||
def pbkdf2(password, salt, iterations, dklen):
|
||||
return pbkdf2_base(GOST34112012512, password, salt, iterations, dklen)
|
||||
@ -1,192 +0,0 @@
|
||||
# coding: utf-8
|
||||
# PyGOST -- Pure Python GOST cryptographic functions library
|
||||
# Copyright (C) 2015-2023 Sergey Matveev <stargrave@stargrave.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, version 3 of the License.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
"""GOST R 34.11-94 hash function
|
||||
|
||||
This is implementation of :rfc:`5831`. Most function and variable names are
|
||||
taken according to specification's terminology.
|
||||
"""
|
||||
|
||||
from copy import copy
|
||||
from functools import partial
|
||||
from struct import pack
|
||||
|
||||
from pygost.gost28147 import block2ns
|
||||
from pygost.gost28147 import encrypt
|
||||
from pygost.gost28147 import ns2block
|
||||
from pygost.gost28147 import validate_sbox
|
||||
from pygost.iface import PEP247
|
||||
from pygost.pbkdf2 import pbkdf2 as pbkdf2_base
|
||||
from pygost.utils import hexdec
|
||||
from pygost.utils import hexenc
|
||||
from pygost.utils import strxor
|
||||
from pygost.utils import xrange
|
||||
|
||||
|
||||
DEFAULT_SBOX = "id-GostR3411-94-CryptoProParamSet"
|
||||
BLOCKSIZE = 32
|
||||
C2 = 32 * b"\x00"
|
||||
C3 = hexdec(b"ff00ffff000000ffff0000ff00ffff0000ff00ff00ff00ffff00ff00ff00ff00")
|
||||
C4 = 32 * b"\x00"
|
||||
digest_size = 32
|
||||
|
||||
|
||||
def A(x):
|
||||
x4, x3, x2, x1 = x[0:8], x[8:16], x[16:24], x[24:32]
|
||||
return b"".join((strxor(x1, x2), x4, x3, x2))
|
||||
|
||||
|
||||
def P(x):
|
||||
return bytearray((
|
||||
x[0], x[8], x[16], x[24], x[1], x[9], x[17], x[25], x[2],
|
||||
x[10], x[18], x[26], x[3], x[11], x[19], x[27], x[4], x[12],
|
||||
x[20], x[28], x[5], x[13], x[21], x[29], x[6], x[14], x[22],
|
||||
x[30], x[7], x[15], x[23], x[31],
|
||||
))
|
||||
|
||||
|
||||
def _chi(Y):
|
||||
"""Chi function
|
||||
|
||||
This is some kind of LFSR.
|
||||
"""
|
||||
(y16, y15, y14, y13, y12, y11, y10, y9, y8, y7, y6, y5, y4, y3, y2, y1) = (
|
||||
Y[0:2], Y[2:4], Y[4:6], Y[6:8], Y[8:10], Y[10:12], Y[12:14],
|
||||
Y[14:16], Y[16:18], Y[18:20], Y[20:22], Y[22:24], Y[24:26],
|
||||
Y[26:28], Y[28:30], Y[30:32],
|
||||
)
|
||||
by1, by2, by3, by4, by13, by16, byx = (
|
||||
bytearray(y1), bytearray(y2), bytearray(y3), bytearray(y4),
|
||||
bytearray(y13), bytearray(y16), bytearray(2),
|
||||
)
|
||||
byx[0] = by1[0] ^ by2[0] ^ by3[0] ^ by4[0] ^ by13[0] ^ by16[0]
|
||||
byx[1] = by1[1] ^ by2[1] ^ by3[1] ^ by4[1] ^ by13[1] ^ by16[1]
|
||||
return b"".join((
|
||||
bytes(byx), y16, y15, y14, y13, y12, y11, y10, y9, y8, y7, y6, y5, y4, y3, y2
|
||||
))
|
||||
|
||||
|
||||
def _step(hin, m, sbox):
|
||||
"""Step function
|
||||
|
||||
H_out = f(H_in, m)
|
||||
"""
|
||||
# Generate keys
|
||||
u = hin
|
||||
v = m
|
||||
w = strxor(hin, m)
|
||||
k1 = P(w)
|
||||
|
||||
u = strxor(A(u), C2)
|
||||
v = A(A(v))
|
||||
w = strxor(u, v)
|
||||
k2 = P(w)
|
||||
|
||||
u = strxor(A(u), C3)
|
||||
v = A(A(v))
|
||||
w = strxor(u, v)
|
||||
k3 = P(w)
|
||||
|
||||
u = strxor(A(u), C4)
|
||||
v = A(A(v))
|
||||
w = strxor(u, v)
|
||||
k4 = P(w)
|
||||
|
||||
# Encipher
|
||||
h4, h3, h2, h1 = hin[0:8], hin[8:16], hin[16:24], hin[24:32]
|
||||
s1 = ns2block(encrypt(sbox, k1[::-1], block2ns(h1[::-1])))[::-1]
|
||||
s2 = ns2block(encrypt(sbox, k2[::-1], block2ns(h2[::-1])))[::-1]
|
||||
s3 = ns2block(encrypt(sbox, k3[::-1], block2ns(h3[::-1])))[::-1]
|
||||
s4 = ns2block(encrypt(sbox, k4[::-1], block2ns(h4[::-1])))[::-1]
|
||||
s = b"".join((s4, s3, s2, s1))
|
||||
|
||||
# Permute
|
||||
# H_out = chi^61(H_in XOR chi(m XOR chi^12(S)))
|
||||
x = s
|
||||
for _ in xrange(12):
|
||||
x = _chi(x)
|
||||
x = strxor(x, m)
|
||||
x = _chi(x)
|
||||
x = strxor(hin, x)
|
||||
for _ in xrange(61):
|
||||
x = _chi(x)
|
||||
return x
|
||||
|
||||
|
||||
class GOST341194(PEP247):
|
||||
"""GOST 34.11-94 big-endian hash
|
||||
|
||||
>>> m = GOST341194()
|
||||
>>> m.update("foo")
|
||||
>>> m.update("bar")
|
||||
>>> m.hexdigest()
|
||||
'3bd8a3a35917871dfa0d49f9e73e7c57eea028dc061133eb560849ea20c133af'
|
||||
>>> GOST341194("foobar").hexdigest()
|
||||
'3bd8a3a35917871dfa0d49f9e73e7c57eea028dc061133eb560849ea20c133af'
|
||||
"""
|
||||
block_size = BLOCKSIZE
|
||||
digest_size = digest_size
|
||||
|
||||
def __init__(self, data=b"", sbox=DEFAULT_SBOX):
|
||||
"""
|
||||
:param bytes data: provide initial data
|
||||
:param bytes sbox: S-box to use
|
||||
"""
|
||||
validate_sbox(sbox)
|
||||
self.data = data
|
||||
self.sbox = sbox
|
||||
|
||||
def copy(self):
|
||||
return GOST341194(copy(self.data), self.sbox)
|
||||
|
||||
def update(self, data):
|
||||
"""Append data that has to be hashed
|
||||
"""
|
||||
self.data += data
|
||||
|
||||
def digest(self):
|
||||
"""Get hash of the provided data
|
||||
"""
|
||||
_len = 0
|
||||
checksum = 0
|
||||
h = 32 * b"\x00"
|
||||
m = self.data
|
||||
for i in xrange(0, len(m), BLOCKSIZE):
|
||||
part = m[i:i + BLOCKSIZE][::-1]
|
||||
_len += len(part) * 8
|
||||
checksum = (checksum + int(hexenc(part), 16)) % (2 ** 256)
|
||||
if len(part) < BLOCKSIZE:
|
||||
part = b"\x00" * (BLOCKSIZE - len(part)) + part
|
||||
h = _step(h, part, self.sbox)
|
||||
h = _step(h, 24 * b"\x00" + pack(">Q", _len), self.sbox)
|
||||
|
||||
checksum = hex(checksum)[2:].rstrip("L")
|
||||
if len(checksum) % 2 != 0:
|
||||
checksum = "0" + checksum
|
||||
checksum = hexdec(checksum)
|
||||
checksum = b"\x00" * (BLOCKSIZE - len(checksum)) + checksum
|
||||
h = _step(h, checksum, self.sbox)
|
||||
return h[::-1]
|
||||
|
||||
|
||||
def new(data=b"", sbox=DEFAULT_SBOX):
|
||||
return GOST341194(data, sbox)
|
||||
|
||||
|
||||
PBKDF2_HASHER = partial(GOST341194, sbox="id-GostR3411-94-CryptoProParamSet")
|
||||
|
||||
|
||||
def pbkdf2(password, salt, iterations, dklen):
|
||||
return pbkdf2_base(PBKDF2_HASHER, password, salt, iterations, dklen)
|
||||
@ -1,186 +0,0 @@
|
||||
# coding: utf-8
|
||||
# PyGOST -- Pure Python GOST cryptographic functions library
|
||||
# Copyright (C) 2015-2023 Sergey Matveev <stargrave@stargrave.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, version 3 of the License.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
"""GOST 34.12-2015 64 and 128 bit block ciphers (:rfc:`7801`)
|
||||
|
||||
Several precalculations are performed during this module importing.
|
||||
"""
|
||||
|
||||
from pygost.gost28147 import block2ns as gost28147_block2ns
|
||||
from pygost.gost28147 import decrypt as gost28147_decrypt
|
||||
from pygost.gost28147 import encrypt as gost28147_encrypt
|
||||
from pygost.gost28147 import ns2block as gost28147_ns2block
|
||||
from pygost.utils import strxor
|
||||
from pygost.utils import xrange
|
||||
|
||||
|
||||
KEYSIZE = 32
|
||||
|
||||
LC = bytearray((
|
||||
148, 32, 133, 16, 194, 192, 1, 251, 1, 192, 194, 16, 133, 32, 148, 1,
|
||||
))
|
||||
PI = bytearray((
|
||||
252, 238, 221, 17, 207, 110, 49, 22, 251, 196, 250, 218, 35, 197, 4, 77,
|
||||
233, 119, 240, 219, 147, 46, 153, 186, 23, 54, 241, 187, 20, 205, 95, 193,
|
||||
249, 24, 101, 90, 226, 92, 239, 33, 129, 28, 60, 66, 139, 1, 142, 79, 5,
|
||||
132, 2, 174, 227, 106, 143, 160, 6, 11, 237, 152, 127, 212, 211, 31, 235,
|
||||
52, 44, 81, 234, 200, 72, 171, 242, 42, 104, 162, 253, 58, 206, 204, 181,
|
||||
112, 14, 86, 8, 12, 118, 18, 191, 114, 19, 71, 156, 183, 93, 135, 21, 161,
|
||||
150, 41, 16, 123, 154, 199, 243, 145, 120, 111, 157, 158, 178, 177, 50, 117,
|
||||
25, 61, 255, 53, 138, 126, 109, 84, 198, 128, 195, 189, 13, 87, 223, 245,
|
||||
36, 169, 62, 168, 67, 201, 215, 121, 214, 246, 124, 34, 185, 3, 224, 15,
|
||||
236, 222, 122, 148, 176, 188, 220, 232, 40, 80, 78, 51, 10, 74, 167, 151,
|
||||
96, 115, 30, 0, 98, 68, 26, 184, 56, 130, 100, 159, 38, 65, 173, 69, 70,
|
||||
146, 39, 94, 85, 47, 140, 163, 165, 125, 105, 213, 149, 59, 7, 88, 179, 64,
|
||||
134, 172, 29, 247, 48, 55, 107, 228, 136, 217, 231, 137, 225, 27, 131, 73,
|
||||
76, 63, 248, 254, 141, 83, 170, 144, 202, 216, 133, 97, 32, 113, 103, 164,
|
||||
45, 43, 9, 91, 203, 155, 37, 208, 190, 229, 108, 82, 89, 166, 116, 210, 230,
|
||||
244, 180, 192, 209, 102, 175, 194, 57, 75, 99, 182,
|
||||
))
|
||||
|
||||
########################################################################
|
||||
# Precalculate inverted PI value as a performance optimization.
|
||||
# Actually it can be computed only once and saved on the disk.
|
||||
########################################################################
|
||||
PIinv = bytearray(256)
|
||||
for x in xrange(256):
|
||||
PIinv[PI[x]] = x
|
||||
|
||||
|
||||
def gf(a, b):
|
||||
c = 0
|
||||
while b:
|
||||
if b & 1:
|
||||
c ^= a
|
||||
if a & 0x80:
|
||||
a = (a << 1) ^ 0x1C3
|
||||
else:
|
||||
a <<= 1
|
||||
b >>= 1
|
||||
return c
|
||||
|
||||
########################################################################
|
||||
# Precalculate all possible gf(byte, byte) values as a performance
|
||||
# optimization.
|
||||
# Actually it can be computed only once and saved on the disk.
|
||||
########################################################################
|
||||
|
||||
|
||||
GF = [bytearray(256) for _ in xrange(256)]
|
||||
|
||||
for x in xrange(256):
|
||||
for y in xrange(256):
|
||||
GF[x][y] = gf(x, y)
|
||||
|
||||
|
||||
def L(blk, rounds=16):
|
||||
for _ in range(rounds):
|
||||
t = blk[15]
|
||||
for i in range(14, -1, -1):
|
||||
blk[i + 1] = blk[i]
|
||||
t ^= GF[blk[i]][LC[i]]
|
||||
blk[0] = t
|
||||
return blk
|
||||
|
||||
|
||||
def Linv(blk):
|
||||
for _ in range(16):
|
||||
t = blk[0]
|
||||
for i in range(15):
|
||||
blk[i] = blk[i + 1]
|
||||
t ^= GF[blk[i]][LC[i]]
|
||||
blk[15] = t
|
||||
return blk
|
||||
|
||||
########################################################################
|
||||
# Precalculate values of the C -- it does not depend on key.
|
||||
# Actually it can be computed only once and saved on the disk.
|
||||
########################################################################
|
||||
|
||||
|
||||
C = []
|
||||
|
||||
for x in range(1, 33):
|
||||
y = bytearray(16)
|
||||
y[15] = x
|
||||
C.append(L(y))
|
||||
|
||||
|
||||
def lp(blk):
|
||||
return L([PI[v] for v in blk])
|
||||
|
||||
|
||||
class GOST3412Kuznechik(object):
|
||||
"""GOST 34.12-2015 128-bit block cipher Кузнечик (Kuznechik)
|
||||
"""
|
||||
blocksize = 16
|
||||
|
||||
def __init__(self, key):
|
||||
"""
|
||||
:param key: encryption/decryption key
|
||||
:type key: bytes, 32 bytes
|
||||
|
||||
Key scheduling (roundkeys precomputation) is performed here.
|
||||
"""
|
||||
kr0 = bytearray(key[:16])
|
||||
kr1 = bytearray(key[16:])
|
||||
self.ks = [kr0, kr1]
|
||||
for i in range(4):
|
||||
for j in range(8):
|
||||
k = lp(bytearray(strxor(C[8 * i + j], kr0)))
|
||||
kr0, kr1 = [strxor(k, kr1), kr0]
|
||||
self.ks.append(kr0)
|
||||
self.ks.append(kr1)
|
||||
|
||||
def encrypt(self, blk):
|
||||
blk = bytearray(blk)
|
||||
for i in range(9):
|
||||
blk = lp(bytearray(strxor(self.ks[i], blk)))
|
||||
return bytes(strxor(self.ks[9], blk))
|
||||
|
||||
def decrypt(self, blk):
|
||||
blk = bytearray(blk)
|
||||
for i in range(9, 0, -1):
|
||||
blk = [PIinv[v] for v in Linv(bytearray(strxor(self.ks[i], blk)))]
|
||||
return bytes(strxor(self.ks[0], blk))
|
||||
|
||||
|
||||
class GOST3412Magma(object):
|
||||
"""GOST 34.12-2015 64-bit block cipher Магма (Magma)
|
||||
"""
|
||||
blocksize = 8
|
||||
|
||||
def __init__(self, key):
|
||||
"""
|
||||
:param key: encryption/decryption key
|
||||
:type key: bytes, 32 bytes
|
||||
"""
|
||||
# Backward compatibility key preparation for 28147-89 key schedule
|
||||
self.key = b"".join(key[i * 4:i * 4 + 4][::-1] for i in range(8))
|
||||
self.sbox = "id-tc26-gost-28147-param-Z"
|
||||
|
||||
def encrypt(self, blk):
|
||||
return gost28147_ns2block(gost28147_encrypt(
|
||||
self.sbox,
|
||||
self.key,
|
||||
gost28147_block2ns(blk[::-1]),
|
||||
))[::-1]
|
||||
|
||||
def decrypt(self, blk):
|
||||
return gost28147_ns2block(gost28147_decrypt(
|
||||
self.sbox,
|
||||
self.key,
|
||||
gost28147_block2ns(blk[::-1]),
|
||||
))[::-1]
|
||||
@ -1,392 +0,0 @@
|
||||
# coding: utf-8
|
||||
# PyGOST -- Pure Python GOST cryptographic functions library
|
||||
# Copyright (C) 2015-2023 Sergey Matveev <stargrave@stargrave.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, version 3 of the License.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
"""GOST R 34.13-2015: Modes of operation for block ciphers
|
||||
|
||||
This module currently includes only padding methods.
|
||||
"""
|
||||
|
||||
from os import urandom
|
||||
|
||||
from pygost.utils import bytes2long
|
||||
from pygost.utils import long2bytes
|
||||
from pygost.utils import strxor
|
||||
from pygost.utils import xrange
|
||||
|
||||
|
||||
KEYSIZE = 32
|
||||
|
||||
|
||||
def pad_size(data_size, blocksize):
|
||||
"""Calculate required pad size to full up blocksize
|
||||
"""
|
||||
if data_size < blocksize:
|
||||
return blocksize - data_size
|
||||
if data_size % blocksize == 0:
|
||||
return 0
|
||||
return blocksize - data_size % blocksize
|
||||
|
||||
|
||||
def pad1(data, blocksize):
|
||||
"""Padding method 1
|
||||
|
||||
Just fill up with zeros if necessary.
|
||||
"""
|
||||
return data + b"\x00" * pad_size(len(data), blocksize)
|
||||
|
||||
|
||||
def pad2(data, blocksize):
|
||||
"""Padding method 2 (also known as ISO/IEC 7816-4)
|
||||
|
||||
Add one bit and then fill up with zeros.
|
||||
"""
|
||||
return data + b"\x80" + b"\x00" * pad_size(len(data) + 1, blocksize)
|
||||
|
||||
|
||||
def unpad2(data, blocksize):
|
||||
"""Unpad method 2
|
||||
"""
|
||||
last_block = bytearray(data[-blocksize:])
|
||||
pad_index = last_block.rfind(b"\x80")
|
||||
if pad_index == -1:
|
||||
raise ValueError("Invalid padding")
|
||||
for c in last_block[pad_index + 1:]:
|
||||
if c != 0:
|
||||
raise ValueError("Invalid padding")
|
||||
return data[:-(blocksize - pad_index)]
|
||||
|
||||
|
||||
def pad3(data, blocksize):
|
||||
"""Padding method 3
|
||||
"""
|
||||
if pad_size(len(data), blocksize) == 0:
|
||||
return data
|
||||
return pad2(data, blocksize)
|
||||
|
||||
|
||||
def ecb_encrypt(encrypter, bs, pt):
|
||||
"""ECB encryption mode of operation
|
||||
|
||||
:param encrypter: encrypting function, that takes block as an input
|
||||
:param int bs: cipher's blocksize, bytes
|
||||
:param bytes pt: already padded plaintext
|
||||
"""
|
||||
if not pt or len(pt) % bs != 0:
|
||||
raise ValueError("Plaintext is not blocksize aligned")
|
||||
ct = []
|
||||
for i in xrange(0, len(pt), bs):
|
||||
ct.append(encrypter(pt[i:i + bs]))
|
||||
return b"".join(ct)
|
||||
|
||||
|
||||
def ecb_decrypt(decrypter, bs, ct):
|
||||
"""ECB decryption mode of operation
|
||||
|
||||
:param decrypter: Decrypting function, that takes block as an input
|
||||
:param int bs: cipher's blocksize, bytes
|
||||
:param bytes ct: ciphertext
|
||||
"""
|
||||
if not ct or len(ct) % bs != 0:
|
||||
raise ValueError("Ciphertext is not blocksize aligned")
|
||||
pt = []
|
||||
for i in xrange(0, len(ct), bs):
|
||||
pt.append(decrypter(ct[i:i + bs]))
|
||||
return b"".join(pt)
|
||||
|
||||
|
||||
def acpkm(encrypter, bs):
|
||||
"""Perform ACPKM key derivation
|
||||
|
||||
:param encrypter: encrypting function, that takes block as an input
|
||||
:param int bs: cipher's blocksize, bytes
|
||||
"""
|
||||
return b"".join([
|
||||
encrypter(bytes(bytearray(range(d, d + bs))))
|
||||
for d in range(0x80, 0x80 + bs * (KEYSIZE // bs), bs)
|
||||
])
|
||||
|
||||
|
||||
def ctr(encrypter, bs, data, iv, _acpkm=None):
|
||||
"""Counter mode of operation
|
||||
|
||||
:param encrypter: encrypting function, that takes block as an input
|
||||
:param int bs: cipher's blocksize, bytes
|
||||
:param bytes data: plaintext/ciphertext
|
||||
:param bytes iv: half blocksize-sized initialization vector
|
||||
|
||||
For decryption you use the same function again.
|
||||
"""
|
||||
if len(iv) != bs // 2:
|
||||
raise ValueError("Invalid IV size")
|
||||
if len(data) > bs * (1 << (8 * (bs // 2 - 1))):
|
||||
raise ValueError("Too big data")
|
||||
stream = []
|
||||
ctr_value = 0
|
||||
ctr_max_value = 1 << (8 * (bs // 2))
|
||||
if _acpkm is not None:
|
||||
acpkm_algo_class, acpkm_section_size_in_bs = _acpkm
|
||||
acpkm_section_size_in_bs //= bs
|
||||
for _ in xrange(0, len(data) + pad_size(len(data), bs), bs):
|
||||
if (
|
||||
_acpkm is not None and
|
||||
ctr_value != 0 and
|
||||
ctr_value % acpkm_section_size_in_bs == 0
|
||||
):
|
||||
encrypter = acpkm_algo_class(acpkm(encrypter, bs)).encrypt
|
||||
stream.append(encrypter(iv + long2bytes(ctr_value, bs // 2)))
|
||||
ctr_value = (ctr_value + 1) % ctr_max_value
|
||||
return strxor(b"".join(stream), data)
|
||||
|
||||
|
||||
def ctr_acpkm(algo_class, encrypter, section_size, bs, data, iv):
|
||||
"""CTR-ACPKM mode of operation
|
||||
|
||||
:param algo_class: pygost.gost3412's algorithm class
|
||||
:param encrypter: encrypting function, that takes block as an input
|
||||
:param int section_size: ACPKM'es section size (N), in bytes
|
||||
:param int bs: cipher's blocksize, bytes
|
||||
:param bytes data: plaintext/ciphertext
|
||||
:param bytes iv: half blocksize-sized initialization vector
|
||||
|
||||
For decryption you use the same function again.
|
||||
"""
|
||||
if section_size % bs != 0:
|
||||
raise ValueError("section_size must be multiple of bs")
|
||||
return ctr(encrypter, bs, data, iv, _acpkm=(algo_class, section_size))
|
||||
|
||||
|
||||
def ofb(encrypter, bs, data, iv):
|
||||
"""OFB mode of operation
|
||||
|
||||
:param encrypter: encrypting function, that takes block as an input
|
||||
:param int bs: cipher's blocksize, bytes
|
||||
:param bytes data: plaintext/ciphertext
|
||||
:param bytes iv: blocksize-sized initialization vector
|
||||
|
||||
For decryption you use the same function again.
|
||||
"""
|
||||
if len(iv) < bs or len(iv) % bs != 0:
|
||||
raise ValueError("Invalid IV size")
|
||||
r = [iv[i:i + bs] for i in range(0, len(iv), bs)]
|
||||
result = []
|
||||
for i in xrange(0, len(data) + pad_size(len(data), bs), bs):
|
||||
r = r[1:] + [encrypter(r[0])]
|
||||
result.append(strxor(r[-1], data[i:i + bs]))
|
||||
return b"".join(result)
|
||||
|
||||
|
||||
def cbc_encrypt(encrypter, bs, pt, iv):
|
||||
"""CBC encryption mode of operation
|
||||
|
||||
:param encrypter: encrypting function, that takes block as an input
|
||||
:param int bs: cipher's blocksize, bytes
|
||||
:param bytes pt: already padded plaintext
|
||||
:param bytes iv: blocksize-sized initialization vector
|
||||
"""
|
||||
if not pt or len(pt) % bs != 0:
|
||||
raise ValueError("Plaintext is not blocksize aligned")
|
||||
if len(iv) < bs or len(iv) % bs != 0:
|
||||
raise ValueError("Invalid IV size")
|
||||
r = [iv[i:i + bs] for i in range(0, len(iv), bs)]
|
||||
ct = []
|
||||
for i in xrange(0, len(pt), bs):
|
||||
ct.append(encrypter(strxor(r[0], pt[i:i + bs])))
|
||||
r = r[1:] + [ct[-1]]
|
||||
return b"".join(ct)
|
||||
|
||||
|
||||
def cbc_decrypt(decrypter, bs, ct, iv):
|
||||
"""CBC decryption mode of operation
|
||||
|
||||
:param decrypter: Decrypting function, that takes block as an input
|
||||
:param int bs: cipher's blocksize, bytes
|
||||
:param bytes ct: ciphertext
|
||||
:param bytes iv: blocksize-sized initialization vector
|
||||
"""
|
||||
if not ct or len(ct) % bs != 0:
|
||||
raise ValueError("Ciphertext is not blocksize aligned")
|
||||
if len(iv) < bs or len(iv) % bs != 0:
|
||||
raise ValueError("Invalid IV size")
|
||||
r = [iv[i:i + bs] for i in range(0, len(iv), bs)]
|
||||
pt = []
|
||||
for i in xrange(0, len(ct), bs):
|
||||
blk = ct[i:i + bs]
|
||||
pt.append(strxor(r[0], decrypter(blk)))
|
||||
r = r[1:] + [blk]
|
||||
return b"".join(pt)
|
||||
|
||||
|
||||
def cfb_encrypt(encrypter, bs, pt, iv):
|
||||
"""CFB encryption mode of operation
|
||||
|
||||
:param encrypter: encrypting function, that takes block as an input
|
||||
:param int bs: cipher's blocksize, bytes
|
||||
:param bytes pt: plaintext
|
||||
:param bytes iv: blocksize-sized initialization vector
|
||||
"""
|
||||
if len(iv) < bs or len(iv) % bs != 0:
|
||||
raise ValueError("Invalid IV size")
|
||||
r = [iv[i:i + bs] for i in range(0, len(iv), bs)]
|
||||
ct = []
|
||||
for i in xrange(0, len(pt) + pad_size(len(pt), bs), bs):
|
||||
ct.append(strxor(encrypter(r[0]), pt[i:i + bs]))
|
||||
r = r[1:] + [ct[-1]]
|
||||
return b"".join(ct)
|
||||
|
||||
|
||||
def cfb_decrypt(encrypter, bs, ct, iv):
|
||||
"""CFB decryption mode of operation
|
||||
|
||||
:param encrypter: encrypting function, that takes block as an input
|
||||
:param int bs: cipher's blocksize, bytes
|
||||
:param bytes ct: ciphertext
|
||||
:param bytes iv: blocksize-sized initialization vector
|
||||
"""
|
||||
if len(iv) < bs or len(iv) % bs != 0:
|
||||
raise ValueError("Invalid IV size")
|
||||
r = [iv[i:i + bs] for i in range(0, len(iv), bs)]
|
||||
pt = []
|
||||
for i in xrange(0, len(ct) + pad_size(len(ct), bs), bs):
|
||||
blk = ct[i:i + bs]
|
||||
pt.append(strxor(encrypter(r[0]), blk))
|
||||
r = r[1:] + [blk]
|
||||
return b"".join(pt)
|
||||
|
||||
|
||||
def _mac_shift(bs, data, xor_lsb=0):
|
||||
num = (bytes2long(data) << 1) ^ xor_lsb
|
||||
return long2bytes(num, bs)[-bs:]
|
||||
|
||||
|
||||
Rb64 = 0b11011
|
||||
Rb128 = 0b10000111
|
||||
|
||||
|
||||
def _mac_ks(encrypter, bs):
|
||||
Rb = Rb128 if bs == 16 else Rb64
|
||||
_l = encrypter(bs * b"\x00")
|
||||
k1 = _mac_shift(bs, _l, Rb) if bytearray(_l)[0] & 0x80 > 0 else _mac_shift(bs, _l)
|
||||
k2 = _mac_shift(bs, k1, Rb) if bytearray(k1)[0] & 0x80 > 0 else _mac_shift(bs, k1)
|
||||
return k1, k2
|
||||
|
||||
|
||||
def mac(encrypter, bs, data):
|
||||
"""MAC (known here as CMAC, OMAC1) mode of operation
|
||||
|
||||
:param encrypter: encrypting function, that takes block as an input
|
||||
:param int bs: cipher's blocksize, bytes
|
||||
:param bytes data: data to authenticate
|
||||
|
||||
Implementation is based on PyCrypto's CMAC one, that is in public domain.
|
||||
"""
|
||||
k1, k2 = _mac_ks(encrypter, bs)
|
||||
if len(data) % bs == 0:
|
||||
tail_offset = len(data) - bs
|
||||
else:
|
||||
tail_offset = len(data) - (len(data) % bs)
|
||||
prev = bs * b"\x00"
|
||||
for i in xrange(0, tail_offset, bs):
|
||||
prev = encrypter(strxor(data[i:i + bs], prev))
|
||||
tail = data[tail_offset:]
|
||||
return encrypter(strxor(
|
||||
strxor(pad3(tail, bs), prev),
|
||||
k1 if len(tail) == bs else k2,
|
||||
))
|
||||
|
||||
|
||||
def acpkm_master(algo_class, encrypter, key_section_size, bs, keymat_len):
|
||||
"""ACPKM-Master key derivation
|
||||
|
||||
:param algo_class: pygost.gost3412's algorithm class
|
||||
:param encrypter: encrypting function, that takes block as an input
|
||||
:param int key_section_size: ACPKM'es key section size (T*), in bytes
|
||||
:param int bs: cipher's blocksize, bytes
|
||||
:param int keymat_len: length of key material to produce
|
||||
"""
|
||||
return ctr_acpkm(
|
||||
algo_class,
|
||||
encrypter,
|
||||
key_section_size,
|
||||
bs,
|
||||
data=b"\x00" * keymat_len,
|
||||
iv=b"\xFF" * (bs // 2),
|
||||
)
|
||||
|
||||
|
||||
def mac_acpkm_master(algo_class, encrypter, key_section_size, section_size, bs, data):
|
||||
"""OMAC-ACPKM-Master
|
||||
|
||||
:param algo_class: pygost.gost3412's algorithm class
|
||||
:param encrypter: encrypting function, that takes block as an input
|
||||
:param int key_section_size: ACPKM'es key section size (T*), in bytes
|
||||
:param int section_size: ACPKM'es section size (N), in bytes
|
||||
:param int bs: cipher's blocksize, bytes
|
||||
:param bytes data: data to authenticate
|
||||
"""
|
||||
if len(data) % bs == 0:
|
||||
tail_offset = len(data) - bs
|
||||
else:
|
||||
tail_offset = len(data) - (len(data) % bs)
|
||||
prev = bs * b"\x00"
|
||||
sections = len(data) // section_size
|
||||
if len(data) % section_size != 0:
|
||||
sections += 1
|
||||
keymats = acpkm_master(
|
||||
algo_class,
|
||||
encrypter,
|
||||
key_section_size,
|
||||
bs,
|
||||
(KEYSIZE + bs) * sections,
|
||||
)
|
||||
for i in xrange(0, tail_offset, bs):
|
||||
if i % section_size == 0:
|
||||
keymat, keymats = keymats[:KEYSIZE + bs], keymats[KEYSIZE + bs:]
|
||||
key, k1 = keymat[:KEYSIZE], keymat[KEYSIZE:]
|
||||
encrypter = algo_class(key).encrypt
|
||||
prev = encrypter(strxor(data[i:i + bs], prev))
|
||||
tail = data[tail_offset:]
|
||||
if len(tail) == bs:
|
||||
key, k1 = keymats[:KEYSIZE], keymats[KEYSIZE:]
|
||||
encrypter = algo_class(key).encrypt
|
||||
k2 = long2bytes(bytes2long(k1) << 1, size=bs)
|
||||
if bytearray(k1)[0] & 0x80 != 0:
|
||||
k2 = strxor(k2, long2bytes(Rb128 if bs == 16 else Rb64, size=bs))
|
||||
return encrypter(strxor(
|
||||
strxor(pad3(tail, bs), prev),
|
||||
k1 if len(tail) == bs else k2,
|
||||
))
|
||||
|
||||
|
||||
def pad_iso10126(data, blocksize):
|
||||
"""ISO 10126 padding
|
||||
|
||||
Does not exist in 34.13, but added for convenience.
|
||||
It uses urandom call for getting the randomness.
|
||||
"""
|
||||
pad_len = blocksize - len(data) % blocksize
|
||||
if pad_len == 0:
|
||||
pad_len = blocksize
|
||||
return b"".join((data, urandom(pad_len - 1), bytes((pad_len,))))
|
||||
|
||||
|
||||
def unpad_iso10126(data, blocksize):
|
||||
"""Unpad :py:func:`pygost.gost3413.pad_iso10126`
|
||||
"""
|
||||
if len(data) % blocksize != 0:
|
||||
raise ValueError("Data length is not multiple of blocksize")
|
||||
pad_len = bytearray(data)[-1]
|
||||
if pad_len > blocksize:
|
||||
raise ValueError("Padding length is bigger than blocksize")
|
||||
return data[:-pad_len]
|
||||
@ -1,50 +0,0 @@
|
||||
from abc import ABCMeta
|
||||
from abc import abstractmethod
|
||||
|
||||
from pygost.utils import hexenc
|
||||
|
||||
|
||||
# This function is taken from six package as is
|
||||
def add_metaclass(metaclass):
|
||||
"""Class decorator for creating a class with a metaclass."""
|
||||
def wrapper(cls):
|
||||
orig_vars = cls.__dict__.copy()
|
||||
slots = orig_vars.get("__slots__")
|
||||
if slots is not None:
|
||||
if isinstance(slots, str):
|
||||
slots = [slots]
|
||||
for slots_var in slots:
|
||||
orig_vars.pop(slots_var)
|
||||
orig_vars.pop("__dict__", None)
|
||||
orig_vars.pop("__weakref__", None)
|
||||
return metaclass(cls.__name__, cls.__bases__, orig_vars)
|
||||
return wrapper
|
||||
|
||||
|
||||
@add_metaclass(ABCMeta)
|
||||
class PEP247(object):
|
||||
@property
|
||||
@abstractmethod
|
||||
def digest_size(self):
|
||||
"""The size of the digest produced by the hashing objects.
|
||||
"""
|
||||
|
||||
@abstractmethod
|
||||
def copy(self):
|
||||
"""Return a separate copy of this hashing object.
|
||||
"""
|
||||
|
||||
@abstractmethod
|
||||
def update(self, data):
|
||||
"""Hash data into the current state of the hashing object.
|
||||
"""
|
||||
|
||||
@abstractmethod
|
||||
def digest(self):
|
||||
"""Return the hash value as a string containing 8-bit data.
|
||||
"""
|
||||
|
||||
def hexdigest(self):
|
||||
"""Return the hash value as a string containing hexadecimal digits.
|
||||
"""
|
||||
return hexenc(self.digest())
|
||||
@ -1,81 +0,0 @@
|
||||
# coding: utf-8
|
||||
# PyGOST -- Pure Python GOST cryptographic functions library
|
||||
# Copyright (C) 2015-2023 Sergey Matveev <stargrave@stargrave.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, version 3 of the License.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
"""Key derivation functions, Р 50.1.113-2016, Р 1323565.1.020-2018
|
||||
"""
|
||||
|
||||
import hmac
|
||||
|
||||
from pygost.gost3410_vko import kek_34102012256
|
||||
from pygost.gost3410_vko import kek_34102012512
|
||||
from pygost.gost34112012256 import GOST34112012256
|
||||
from pygost.utils import bytes2long
|
||||
from pygost.utils import long2bytes
|
||||
|
||||
|
||||
def kdf_gostr3411_2012_256(key, label, seed):
|
||||
"""KDF_GOSTR3411_2012_256
|
||||
|
||||
:param bytes key: initial key
|
||||
:param bytes label: label
|
||||
:param bytes seed: seed
|
||||
:returns: 32 bytes
|
||||
"""
|
||||
return hmac.new(
|
||||
key=key,
|
||||
msg=b"".join((b"\x01", label, b"\x00", seed, b"\x01\x00")),
|
||||
digestmod=GOST34112012256,
|
||||
).digest()
|
||||
|
||||
|
||||
def kdf_tree_gostr3411_2012_256(key, label, seed, keys, i_len=1):
|
||||
"""KDF_TREE_GOSTR3411_2012_256
|
||||
|
||||
:param bytes key: initial key
|
||||
:param bytes label: label
|
||||
:param bytes seed: seed
|
||||
:param int keys: number of generated keys
|
||||
:param int i_len: length of iterations value (called "R")
|
||||
:returns: list of 256-bit keys
|
||||
"""
|
||||
keymat = []
|
||||
_len = long2bytes(keys * 32 * 8, size=1)
|
||||
for i in range(keys):
|
||||
keymat.append(hmac.new(
|
||||
key=key,
|
||||
msg=b"".join((long2bytes(i + 1, size=i_len), label, b"\x00", seed, _len)),
|
||||
digestmod=GOST34112012256,
|
||||
).digest())
|
||||
return keymat
|
||||
|
||||
|
||||
def keg(curve, prv, pub, h):
|
||||
"""Export key generation (Р 1323565.1.020-2018)
|
||||
|
||||
:param GOST3410Curve curve: curve to use
|
||||
:param long prv: private key
|
||||
:param pub: public key
|
||||
:type pub: (long, long)
|
||||
:param bytes h: "h"-value, 32 bytes
|
||||
"""
|
||||
if len(h) != 32:
|
||||
raise ValueError("h must be 32 bytes long")
|
||||
ukm = bytes2long(h[:16])
|
||||
if ukm == 0:
|
||||
ukm = 1
|
||||
if curve.point_size == 64:
|
||||
return kek_34102012512(curve, prv, pub, ukm)
|
||||
k_exp = kek_34102012256(curve, prv, pub, ukm)
|
||||
return b"".join(kdf_tree_gostr3411_2012_256(k_exp, b"kdf tree", h[16:24], 2))
|
||||
@ -1,168 +0,0 @@
|
||||
# coding: utf-8
|
||||
# PyGOST -- Pure Python GOST cryptographic functions library
|
||||
# Copyright (C) 2015-2023 Sergey Matveev <stargrave@stargrave.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, version 3 of the License.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
"""Multilinear Galois Mode (MGM) block cipher mode.
|
||||
"""
|
||||
|
||||
from hmac import compare_digest
|
||||
|
||||
from pygost.gost3413 import pad1
|
||||
from pygost.utils import bytes2long
|
||||
from pygost.utils import long2bytes
|
||||
from pygost.utils import strxor
|
||||
|
||||
|
||||
def _incr(data, bs):
|
||||
return long2bytes(bytes2long(data) + 1, size=bs // 2)
|
||||
|
||||
|
||||
def incr_r(data, bs):
|
||||
return data[:bs // 2] + _incr(data[bs // 2:], bs)
|
||||
|
||||
|
||||
def incr_l(data, bs):
|
||||
return _incr(data[:bs // 2], bs) + data[bs // 2:]
|
||||
|
||||
|
||||
def nonce_prepare(nonce):
|
||||
"""Prepare nonce for MGM usage
|
||||
|
||||
It just clears MSB.
|
||||
"""
|
||||
n = bytearray(nonce)
|
||||
n[0] &= 0x7F
|
||||
return bytes(n)
|
||||
|
||||
|
||||
class MGM(object):
|
||||
# Implementation is fully based on go.cypherpunks.ru/gogost/mgm
|
||||
def __init__(self, encrypter, bs, tag_size=None):
|
||||
"""Multilinear Galois Mode (MGM) block cipher mode
|
||||
|
||||
:param encrypter: encrypting function, that takes block as an input
|
||||
:param int bs: cipher's blocksize
|
||||
:param int tag_size: authentication tag size
|
||||
(defaults to blocksize if not specified)
|
||||
"""
|
||||
if bs not in (8, 16):
|
||||
raise ValueError("Only 64/128-bit blocksizes allowed")
|
||||
self.tag_size = bs if tag_size is None else tag_size
|
||||
if self.tag_size < 4 or self.tag_size > bs:
|
||||
raise ValueError("Invalid tag_size")
|
||||
self.encrypter = encrypter
|
||||
self.bs = bs
|
||||
self.max_size = (1 << (bs * 8 // 2)) - 1
|
||||
self.r = 0x1B if bs == 8 else 0x87
|
||||
|
||||
def _validate_nonce(self, nonce):
|
||||
if len(nonce) != self.bs:
|
||||
raise ValueError("nonce length must be equal to cipher's blocksize")
|
||||
if bytearray(nonce)[0] & 0x80 > 0:
|
||||
raise ValueError("nonce must not have higher bit set")
|
||||
|
||||
def _validate_sizes(self, plaintext, additional_data):
|
||||
if len(plaintext) == 0 and len(additional_data) == 0:
|
||||
raise ValueError("At least one of plaintext or additional_data required")
|
||||
if len(plaintext) + len(additional_data) > self.max_size:
|
||||
raise ValueError("plaintext+additional_data are too big")
|
||||
|
||||
def _mul(self, x, y):
|
||||
x = bytes2long(x)
|
||||
y = bytes2long(y)
|
||||
z = 0
|
||||
max_bit = 1 << (self.bs * 8 - 1)
|
||||
while y > 0:
|
||||
if y & 1 == 1:
|
||||
z ^= x
|
||||
if x & max_bit > 0:
|
||||
x = ((x ^ max_bit) << 1) ^ self.r
|
||||
else:
|
||||
x <<= 1
|
||||
y >>= 1
|
||||
return long2bytes(z, size=self.bs)
|
||||
|
||||
def _crypt(self, icn, data):
|
||||
icn[0] &= 0x7F
|
||||
enc = self.encrypter(bytes(icn))
|
||||
res = []
|
||||
while len(data) > 0:
|
||||
res.append(strxor(self.encrypter(enc), data))
|
||||
enc = incr_r(enc, self.bs)
|
||||
data = data[self.bs:]
|
||||
return b"".join(res)
|
||||
|
||||
def _auth(self, icn, text, ad):
|
||||
icn[0] |= 0x80
|
||||
enc = self.encrypter(bytes(icn))
|
||||
_sum = self.bs * b"\x00"
|
||||
ad_len = len(ad)
|
||||
text_len = len(text)
|
||||
while len(ad) > 0:
|
||||
_sum = strxor(_sum, self._mul(
|
||||
self.encrypter(enc),
|
||||
pad1(ad[:self.bs], self.bs),
|
||||
))
|
||||
enc = incr_l(enc, self.bs)
|
||||
ad = ad[self.bs:]
|
||||
while len(text) > 0:
|
||||
_sum = strxor(_sum, self._mul(
|
||||
self.encrypter(enc),
|
||||
pad1(text[:self.bs], self.bs),
|
||||
))
|
||||
enc = incr_l(enc, self.bs)
|
||||
text = text[self.bs:]
|
||||
_sum = strxor(_sum, self._mul(self.encrypter(enc), (
|
||||
long2bytes(ad_len * 8, size=self.bs // 2) +
|
||||
long2bytes(text_len * 8, size=self.bs // 2)
|
||||
)))
|
||||
return self.encrypter(_sum)[:self.tag_size]
|
||||
|
||||
def seal(self, nonce, plaintext, additional_data):
|
||||
"""Seal plaintext
|
||||
|
||||
:param bytes nonce: blocksize-sized nonce.
|
||||
Assure that it does not have MSB bit set
|
||||
(:py:func:`pygost.mgm.nonce_prepare` helps)
|
||||
:param bytes plaintext: plaintext to be encrypted and authenticated
|
||||
:param bytes additional_data: additional data to be authenticated
|
||||
"""
|
||||
self._validate_nonce(nonce)
|
||||
self._validate_sizes(plaintext, additional_data)
|
||||
icn = bytearray(nonce)
|
||||
ciphertext = self._crypt(icn, plaintext)
|
||||
tag = self._auth(icn, ciphertext, additional_data)
|
||||
return ciphertext + tag
|
||||
|
||||
def open(self, nonce, ciphertext, additional_data):
|
||||
"""Open ciphertext
|
||||
|
||||
:param bytes nonce: blocksize-sized nonce.
|
||||
Assure that it does not have MSB bit set
|
||||
(:py:func:`pygost.mgm.nonce_prepare` helps)
|
||||
:param bytes ciphertext: ciphertext to be decrypted and authenticated
|
||||
:param bytes additional_data: additional data to be authenticated
|
||||
:raises ValueError: if ciphertext authentication fails
|
||||
"""
|
||||
self._validate_nonce(nonce)
|
||||
self._validate_sizes(ciphertext, additional_data)
|
||||
icn = bytearray(nonce)
|
||||
ciphertext, tag_expected = (
|
||||
ciphertext[:-self.tag_size],
|
||||
ciphertext[-self.tag_size:],
|
||||
)
|
||||
tag = self._auth(icn, ciphertext, additional_data)
|
||||
if not compare_digest(tag_expected, tag):
|
||||
raise ValueError("Invalid authentication tag")
|
||||
return self._crypt(icn, ciphertext)
|
||||
@ -1,41 +0,0 @@
|
||||
# coding: utf-8
|
||||
"""PBKDF2 implementation suitable for GOST R 34.11-94/34.11-2012.
|
||||
|
||||
This implementation is based on Python 3.5.2 source code's one.
|
||||
PyGOST does not register itself in hashlib anyway, so use it instead.
|
||||
"""
|
||||
|
||||
|
||||
from pygost.utils import bytes2long
|
||||
from pygost.utils import long2bytes
|
||||
from pygost.utils import strxor
|
||||
from pygost.utils import xrange
|
||||
|
||||
|
||||
def pbkdf2(hasher, password, salt, iterations, dklen):
|
||||
"""PBKDF2 implementation suitable for GOST R 34.11-94/34.11-2012
|
||||
"""
|
||||
inner = hasher()
|
||||
outer = hasher()
|
||||
password = password + b"\x00" * (inner.block_size - len(password))
|
||||
inner.update(strxor(password, len(password) * b"\x36"))
|
||||
outer.update(strxor(password, len(password) * b"\x5C"))
|
||||
|
||||
def prf(msg):
|
||||
icpy = inner.copy()
|
||||
ocpy = outer.copy()
|
||||
icpy.update(msg)
|
||||
ocpy.update(icpy.digest())
|
||||
return ocpy.digest()
|
||||
|
||||
dkey = b""
|
||||
loop = 1
|
||||
while len(dkey) < dklen:
|
||||
prev = prf(salt + long2bytes(loop, 4))
|
||||
rkey = bytes2long(prev)
|
||||
for _ in xrange(iterations - 1):
|
||||
prev = prf(prev)
|
||||
rkey ^= bytes2long(prev)
|
||||
loop += 1
|
||||
dkey += long2bytes(rkey, inner.digest_size)
|
||||
return dkey[:dklen]
|
||||
@ -1,101 +0,0 @@
|
||||
from typing import Callable
|
||||
from typing import Dict
|
||||
from typing import Sequence
|
||||
from typing import Tuple
|
||||
|
||||
|
||||
SBOXES = ... # type: Dict[str, Tuple[Tuple[int, ...], ...]]
|
||||
BLOCKSIZE = ... # type: int
|
||||
|
||||
Words = Tuple[int, int]
|
||||
|
||||
|
||||
def block2ns(data: bytes) -> Words: ...
|
||||
|
||||
|
||||
def ns2block(ns: Words) -> bytes: ...
|
||||
|
||||
|
||||
def validate_key(key: bytes) -> None: ...
|
||||
|
||||
|
||||
def validate_iv(iv: bytes) -> None: ...
|
||||
|
||||
|
||||
def validate_sbox(sbox: str) -> None: ...
|
||||
|
||||
|
||||
def xcrypt(seq: Sequence[int], sbox: str, key: bytes, ns: Words) -> Words: ...
|
||||
|
||||
|
||||
def encrypt(sbox: str, key: bytes, ns: Words) -> Words: ...
|
||||
|
||||
|
||||
def decrypt(sbox: str, key: bytes, ns: Words) -> Words: ...
|
||||
|
||||
|
||||
def ecb(
|
||||
key: bytes,
|
||||
data: bytes,
|
||||
action: Callable[[str, bytes, Words], Words],
|
||||
sbox: str = ...,
|
||||
) -> bytes: ...
|
||||
|
||||
|
||||
def ecb_encrypt(
|
||||
key: bytes,
|
||||
data: bytes,
|
||||
sbox: str = ...,
|
||||
) -> bytes: ...
|
||||
|
||||
|
||||
def ecb_decrypt(
|
||||
key: bytes,
|
||||
data: bytes,
|
||||
sbox: str = ...,
|
||||
) -> bytes: ...
|
||||
|
||||
|
||||
def cbc_encrypt(
|
||||
key: bytes,
|
||||
data: bytes,
|
||||
iv: bytes = ...,
|
||||
pad: bool = ...,
|
||||
sbox: str = ...,
|
||||
mesh: bool = ...,
|
||||
) -> bytes: ...
|
||||
|
||||
|
||||
def cbc_decrypt(
|
||||
key: bytes,
|
||||
data: bytes,
|
||||
pad: bool = ...,
|
||||
sbox: str = ...,
|
||||
mesh: bool = ...,
|
||||
) -> bytes: ...
|
||||
|
||||
|
||||
def cnt(
|
||||
key: bytes,
|
||||
data: bytes,
|
||||
iv: bytes = ...,
|
||||
sbox: str = ...,
|
||||
) -> bytes: ...
|
||||
|
||||
|
||||
def cfb_encrypt(
|
||||
key: bytes,
|
||||
data: bytes,
|
||||
iv: bytes = ...,
|
||||
sbox: str = ...,
|
||||
mesh: bool = ...,
|
||||
) -> bytes: ...
|
||||
|
||||
|
||||
def cfb_decrypt(
|
||||
key: bytes,
|
||||
data: bytes,
|
||||
iv: bytes = ...,
|
||||
sbox: str = ...,
|
||||
mesh: bool = ...,
|
||||
) -> bytes: ...
|
||||
@ -1,25 +0,0 @@
|
||||
from pygost.iface import PEP247
|
||||
|
||||
|
||||
class MAC(PEP247):
|
||||
def __init__(
|
||||
self,
|
||||
key: bytes,
|
||||
data: bytes = ...,
|
||||
iv: bytes = ...,
|
||||
sbox: str = ...,
|
||||
) -> None: ...
|
||||
|
||||
@property
|
||||
def digest_size(self) -> int: ...
|
||||
|
||||
def copy(self) -> "MAC": ...
|
||||
|
||||
def update(self, data: bytes) -> None: ...
|
||||
|
||||
def digest(self) -> bytes: ...
|
||||
|
||||
def hexdigest(self) -> str: ...
|
||||
|
||||
|
||||
def new(key: bytes, data: bytes = ..., iv: bytes = ..., sbox: str = ...) -> MAC: ...
|
||||
@ -1,72 +0,0 @@
|
||||
from typing import Dict
|
||||
from typing import Tuple
|
||||
|
||||
|
||||
DEFAULT_CURVE = ... # type: GOST3410Curve
|
||||
CURVES = ... # type: Dict[str, GOST3410Curve]
|
||||
PublicKey = Tuple[int, int]
|
||||
|
||||
|
||||
class GOST3410Curve(object):
|
||||
p = ... # type: int
|
||||
q = ... # type: int
|
||||
a = ... # type: int
|
||||
b = ... # type: int
|
||||
x = ... # type: int
|
||||
y = ... # type: int
|
||||
cofactor = ... # type: int
|
||||
e = ... # type: int
|
||||
d = ... # type: int
|
||||
name = ... # type: str
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
p: int,
|
||||
q: int,
|
||||
a: int,
|
||||
b: int,
|
||||
x: int,
|
||||
y: int,
|
||||
cofactor: int = 1,
|
||||
e: int = None,
|
||||
d: int = None,
|
||||
name: str = None,
|
||||
) -> None: ...
|
||||
|
||||
def pos(self, v: int) -> int: ...
|
||||
|
||||
def exp(self, degree: int, x: int = ..., y: int = ...) -> int: ...
|
||||
|
||||
def st(self) -> Tuple[int, int]: ...
|
||||
|
||||
@property
|
||||
def point_size(self) -> int: ...
|
||||
|
||||
def contains(self, point: Tuple[int, int]) -> bool: ...
|
||||
|
||||
|
||||
def public_key(curve: GOST3410Curve, prv: int) -> PublicKey: ...
|
||||
|
||||
|
||||
def sign(curve: GOST3410Curve, prv: int, digest: bytes, rand: bytes = None) -> bytes: ...
|
||||
|
||||
|
||||
def verify(curve: GOST3410Curve, pub: PublicKey, digest: bytes, signature: bytes) -> bool: ...
|
||||
|
||||
|
||||
def prv_unmarshal(prv: bytes) -> int: ...
|
||||
|
||||
|
||||
def prv_marshal(curve: GOST3410Curve, prv: int) -> bytes: ...
|
||||
|
||||
|
||||
def pub_marshal(pub: PublicKey) -> bytes: ...
|
||||
|
||||
|
||||
def pub_unmarshal(pub: bytes) -> PublicKey: ...
|
||||
|
||||
|
||||
def uv2xy(curve: GOST3410Curve, u: int, v: int) -> Tuple[int, int]: ...
|
||||
|
||||
|
||||
def xy2uv(curve: GOST3410Curve, x: int, y: int) -> Tuple[int, int]: ...
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user