[DEL] Delete pygost

This commit is contained in:
vadzik 2024-04-14 16:15:41 +03:00
parent 8c7a8c9675
commit f56f450fdf
130 changed files with 7 additions and 20548 deletions

View File

@ -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():

View File

@ -1 +0,0 @@
* Sergey Matveev <stargrave@stargrave.org>

View File

@ -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>.

View File

@ -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?!

View File

@ -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'.

View File

@ -1,8 +0,0 @@
include AUTHORS
include COPYING
include FAQ
include INSTALL
include NEWS
include README
include THANKS
include VERSION

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -1 +0,0 @@
5.13

View File

@ -1,6 +0,0 @@
"""Pure Python GOST cryptographic functions library.
PyGOST is free software: see the file COPYING for copying conditions.
"""
__version__ = "5.13"

View File

@ -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())

View File

@ -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)

View File

@ -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))),
)

View File

@ -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")

View File

@ -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

View File

@ -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()),
)

View File

@ -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)),
)

View File

@ -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),
)

View File

@ -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)

View File

@ -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)

View File

@ -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

View File

@ -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()

View File

@ -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:]

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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]

View File

@ -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]

View File

@ -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())

View File

@ -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))

View File

@ -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)

View File

@ -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]

View File

@ -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: ...

View File

@ -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: ...

View File

@ -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]: ...

View File

@ -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: ...

View File

@ -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: ...

View File

@ -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: ...

View File

@ -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: ...

View File

@ -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: ...

View File

@ -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: ...

View File

@ -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: ...

View File

@ -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: ...

View File

@ -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: ...

View File

@ -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: ...

View File

@ -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: ...

View File

@ -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

View File

@ -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)

View File

@ -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())

View File

@ -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,
),
)

View File

@ -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)

View File

@ -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",
)

View File

@ -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",
)

View File

@ -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)

View File

@ -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)

View File

@ -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"),
),
)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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==
""",
)

View File

@ -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

View File

@ -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

Binary file not shown.

View File

@ -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

View File

@ -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

View File

@ -1 +0,0 @@
pygost

View File

@ -1,6 +0,0 @@
"""Pure Python GOST cryptographic functions library.
PyGOST is free software: see the file COPYING for copying conditions.
"""
__version__ = "5.13"

View File

@ -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())

View File

@ -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)

View File

@ -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))),
)

View File

@ -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")

View File

@ -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

View File

@ -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()),
)

View File

@ -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)),
)

View File

@ -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),
)

View File

@ -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)

View File

@ -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)

View File

@ -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

View File

@ -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()

View File

@ -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:]

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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]

View File

@ -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]

View File

@ -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())

View File

@ -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))

View File

@ -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)

View File

@ -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]

View File

@ -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: ...

View File

@ -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: ...

View File

@ -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