pax_global_header00006660000000000000000000000064150013712450014510gustar00rootroot0000000000000052 comment=c90ff465dcdb6a6949542c72a26a8ab496daa8cb jitterentropy-library-3.6.3/000077500000000000000000000000001500137124500161055ustar00rootroot00000000000000jitterentropy-library-3.6.3/.gitignore000066400000000000000000000001441500137124500200740ustar00rootroot00000000000000SP800-90B_EntropyAssessment .kdev4 *.kdev4 build inst tests/raw-entropy/results-measurements/*.data jitterentropy-library-3.6.3/CHANGES.md000066400000000000000000000140461500137124500175040ustar00rootroot000000000000003.6.3 * Correct time stamp processing on AIX * Use high-resolution time stamp on Apple Silicon * GCD power-up test: consider OSR 3.6.2 * Fix RCT re-initialization in jent_read_entropy_safe (thanks to Joshua Hill for pointing this out) * simplify test code * improve keyword portability 3.6.1 * Add more test code * Add support for SunPRO compiler * Fix compilation on OpenBSD by replacing sed with tr * internal timer: Add support for Apple * Various small fixes to compilation to imporve portability 3.6.0 * Remove bi-modal behavior of conditioning function * Make jent_read_entropy_safe safer by retrying the health test * Move the version information to make them available at compile time 3.5.0 * add distinction between intermittent and permanent health failure * add compile time option to allow configuring a mask to reduce the size of the time stamp used for the APT 3.4.1 * add FIPS 140 hints to man page * simplify the test tool to search for optimal configurations * fix: jent_loop_shuffle: re-add setting the time that was lost with 3.4.0 * enhancement: add ARM64 assembler code to read high-res timer 3.4.0 * enhancement: add API call jent_set_fips_failure_callback as requested by Daniel Ojalvo * fix: Change the SHA-3 integration: The entropy pool is now a SHA-3 state. It is filled with the time delta containing entropy and auxiliary data that does not contain entropy using a SHA update operation. The auxiliary data is calculated by a SHA-3 hashing of some varying state data. The time delta that contains entropy is measured about the SHA-3 hasing of the auxiliary data. This satisfies FIPS 140-3 IG D.K resolutions 4, 6, and 8. * enhancement: add CMake support by Andrew Hopkins 3.3.1 * fix: bug fix in initialization logic by Vladis Dronov * fix: use __asm__ instead of asm to suit the C11 standard 3.3.0 * add jent_get_cachesize if _SC_LEVEL1_DCACHE_SIZE is not defined * limit the memory buffer size allocated and allow caller to provide the means to provide a limit, too * fix: update man page * update README explaining how to handle entropy shortfall to make it consistent with the current code base 3.2.0 * fix: add API call jent_read_entropy_safe to header file * enhancement: add jent_entropy_init_ex API call * enhancement: call jent_entropy_init_ex automatically when jent_entropy_collector_alloc_internal detects that no self test has yet been performed * test: provide jitterentropy-rng test tool allowing all options exported by the library to be invoked * fix: re-add check of time_backwards in power-on test * fix: silence static code analysis tool * test: add test for GCD * enhancement: add GCD selftest * fix: simplify memory management for SHA-3 * enhancement: add random memory access (JENT_RANDOM_MEMACCESS) 3.1.0 * Add link call to pthreads library as suggested by Mikhail Novosyolov * Add ENTROPY_SAFETY_FACTOR to apply consideration of asymptotically reaching full entropy following SP800-90C suggested by Joshua Hill * Add test for finiding more entropy by changing the memory buffer size used for the memory access loop * Increase the memory buffer size to 512 kBytes per default based on measurements on systems with low entropy. * Add jent_ncpu() detecting the number of existing CPUs. Only when more than one CPU is in the system, the internal timer thread is started. * add GCD testing and analysis suggested by Joshua Hill * add fixes to APT suggested by Joshua Hill * add lag predictor health test suggested by Joshua Hill * add jent_read_entropy_safe API call * break up jitterentropy-base.c into various smaller code files 3.0.2 * Small fixes suggested by Joshua Hill * Update the invocation of SHA-3 invocation: each loop iteration defined by the loop shuffle is a self-contained SHA-3 operation. Therefore, the conditioning information is always *one* SHA-3 operation with different time duration. * add JENT_CONF_DISABLE_LOOP_SHUFFLE config option allowing disabling of the shuffle operation * Use -O0 3.0.1 * on older GCC versions use -fstack-protector as suggested by Warszawski, Diego * prevent creating the internal timer thread if a high-res hardware timer is found as reported by Lonnie Abelbeck 3.0.0 * use RDTSC on x86 directly instead of clock_gettime * use SHA-3 instead of LFSR * add internal high-resolution timer support 2.2.0 * SP800-90B compliance: Add RCT runtime health test * SP800-90B compliance: Add Chi-Squared runtime health test as a replacement for the adaptive proportion test * SP800-90B compliance: Increase initial entropy test to 1024 rounds * SP800-90B compliance: Invoke runtime health tests during initialization * remove FIPS 140-2 continuous self test (RCT covers the requirement as per FIPS 140-2 IG 9.8) * SP800-90B compliance: Do not mix stuck time deltas into entropy pool 2.1.2: * Add static library compilation thanks to Neil Horman * Initialize variable ec to satisfy valgrind as suggested by Steve Grubb * Add cross-compilation support suggested by Lonnie Abelbeck 2.1.1: * Fix implementation of mathematical properties. 2.1.0: * Convert all __[u|s][32|64] into [uint|int][32|64]_t * Remove all code protected by #if defined(__KERNEL__) && !defined(MODULE) * Add JENT_PRIVATE_COMPILE: Enable flag during compile when compiling a private copy of the Jitter RNG * Remove unused statistical test code * Add FIPS 140-2 continuous self test code * threshold for init-time stuck test configurable with JENT_STUCK_INIT_THRES during compile time 2.0.1: * Invcation of stuck test during initalization 2.0.0: * Replace the XOR folding of a time delta with an LFSR -- the use of an LFSR is mathematically more sound for the argument to maintain entropy 1.2.0: * Use constant time operation of jent_stir_pool to prevent leaking timing information about RNG. * Make it compile on 32 bit archtectures 1.1.0: * start new numbering schema * update processing of bit that is deemed holding no entropy by heuristic: XOR it into pool without LSFR and bit rotation (reported and suggested by Kevin Fowler ) jitterentropy-library-3.6.3/CMakeLists.txt000066400000000000000000000127501500137124500206520ustar00rootroot00000000000000cmake_minimum_required(VERSION 2.8.12) project(jitterentropy C) set(CMAKE_C_STANDARD 99) option(STACK_PROTECTOR "Compile Jitter with stack protector enabled" ON) option(INTERNAL_TIMER "Compile Jitter with the internal thread based timer" ON) option(EXTERNAL_CRYPTO "Compile Jitter and use an external libcrypto, valid options are [AWSLC, OPENSSL, LIBGCRYPT]") option(OLDER_GLIBC "Compile Jitter and use an older versions of pthread symbols (create and join)" OFF) option(AARCH64_NSTIME_REGISTER "Name of the register that should be used in jent_get_nstime function") # CMake defines the variable MSVC to true automatically when building with MSVC, replicate that for other compilers if(CMAKE_C_COMPILER_ID MATCHES "Clang") set(CLANG 1) elseif(CMAKE_C_COMPILER_ID MATCHES "GNU") set(GCC 1) elseif(CMAKE_C_COMPILER_ID MATCHES "SunPro") set(SUNPRO 1) endif() if(INTERNAL_TIMER) list(APPEND JITTER_C_FLAGS -DJENT_CONF_ENABLE_INTERNAL_TIMER) endif() if(EXTERNAL_CRYPTO) list(APPEND JITTER_C_FLAGS -D${EXTERNAL_CRYPTO}) endif() if(OLDER_GLIBC) list(APPEND JITTER_C_FLAGS -DUSE_OLDER_GLIBC) endif() if (AARCH64_NSTIME_REGISTER) list(APPEND JITTER_C_FLAGS -DAARCH64_NSTIME_REGISTER="${AARCH64_NSTIME_REGISTER}") endif() if(WIN32) if(MSVC) list(APPEND JITTER_C_FLAGS /Od /W4 /DYNAMICBASE) else() list(APPEND JITTER_C_FLAGS -fwrapv --param ssp-buffer-size=4 -fvisibility=hidden -Wcast-align -Wmissing-field-initializers -Wshadow -Wswitch-enum -Wextra -Wall -pedantic -O0 -fwrapv -Wconversion) endif() else() list(APPEND JITTER_C_FLAGS -fvisibility=hidden -Wcast-align -Wmissing-field-initializers -Wshadow -Wswitch-enum -Wextra -Wall -pedantic -O0 -Wconversion) if(NOT APPLE) if(SUNPRO) list(APPEND JITTER_LINKER_FLAGS -Wl,-z,now) else() list(APPEND JITTER_LINKER_FLAGS -Wl,-z,now,-z,relro) endif() endif() if(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD") list(APPEND JITTER_LINKER_FLAGS -pthread) endif() if(SUNPRO) list(APPEND JITTER_C_FLAGS -m64 -Kpic -errtags=yes -erroff=E_KW_IS_AN_EXTENSION_OF_ANSI,E_ASM_UNUSED_PARAM) else() list(APPEND JITTER_C_FLAGS -fwrapv --param ssp-buffer-size=4 -fPIE -fPIC) endif() if ((NOT GCC) OR (GCC AND CMAKE_C_COMPILER_VERSION VERSION_GREATER "4.3")) # -Wconversion was changed from GCC version 4.3. Prior it was meant as # an aid in translating code from old C to modern C. It was not meant # to help detect troublesome implicit conversions. # https://gcc.gnu.org/wiki/NewWconversion. set(JITTER_COMPILE_FLAGS "${JITTER_COMPILE_FLAGS} -Wconversion") endif() endif() if(STACK_PROTECTOR) if(GCC) if(CMAKE_C_COMPILER_VERSION VERSION_GREATER "4.9.0") list(APPEND JITTER_C_FLAGS -fstack-protector-strong) else() list(APPEND JITTER_C_FLAGS -fstack-protector-all) endif() elseif(CLANG) list(APPEND JITTER_C_FLAGS -fstack-protector-strong) endif() endif() file(GLOB JITTER_SRC "src/*.c") add_library(${PROJECT_NAME}) target_sources(${PROJECT_NAME} PRIVATE ${JITTER_SRC}) set_target_properties(${PROJECT_NAME} PROPERTIES PUBLIC_HEADER "jitterentropy.h;jitterentropy-base-user.h") target_compile_options(${PROJECT_NAME} PRIVATE ${JITTER_C_FLAGS}) target_link_libraries(${PROJECT_NAME} PRIVATE ${JITTER_LINKER_FLAGS}) install(TARGETS ${PROJECT_NAME}) target_include_directories(${PROJECT_NAME} PUBLIC $ $) if(EXTERNAL_CRYPTO STREQUAL "AWSLC") # This header is unique from OpenSSL set(EXTERNAL_CRYPTO_HEADER "openssl/base.h") set(EXTERNAL_CRYPTO_LIBRARY_NAME libcrypto) elseif(EXTERNAL_CRYPTO STREQUAL "OPENSSL") set(EXTERNAL_CRYPTO_HEADER "openssl/crypto.h") set(EXTERNAL_CRYPTO_LIBRARY_NAME libcrypto) elseif(EXTERNAL_CRYPTO STREQUAL "LIBGCRYPT") set(EXTERNAL_CRYPTO_HEADER "g10lib.h") set(EXTERNAL_CRYPTO_LIBRARY_NAME libgcrypt) elseif(NOT EXTERNAL_CRYPTO) message(STATUS "Using internal functions for everything") else() message(FATAL_ERROR "Unknown EXTERNAL_CRYPTO option ${EXTERNAL_CRYPTO}") endif() if(EXTERNAL_CRYPTO) find_path(LIBCRYPTO_INCLUDE_DIR NAMES "${EXTERNAL_CRYPTO_HEADER}" PATH_SUFFIXES include ) message(STATUS "Found external crypto headers at ${LIBCRYPTO_INCLUDE_DIR}") target_include_directories(${PROJECT_NAME} PUBLIC ${LIBCRYPTO_INCLUDE_DIR}) if(BUILD_SHARED_LIBS) find_library(LIBCRYPTO_LIBRARY NAMES "${EXTERNAL_CRYPTO_LIBRARY_NAME}.so" "${EXTERNAL_CRYPTO_LIBRARY_NAME}.dylib" "${EXTERNAL_CRYPTO_LIBRARY_NAME}.dll" HINTS "${CMAKE_INSTALL_PREFIX}" PATH_SUFFIXES build/crypto build lib64 lib ) else() find_library(LIBCRYPTO_LIBRARY NAMES "${EXTERNAL_CRYPTO_LIBRARY_NAME}.so" "${EXTERNAL_CRYPTO_LIBRARY_NAME}.dylib" "${EXTERNAL_CRYPTO_LIBRARY_NAME}.dll" HINTS "${CMAKE_INSTALL_PREFIX}" PATH_SUFFIXES build/crypto build lib64 lib ) endif() message(STATUS "Found external crypto library ${LIBCRYPTO_LIBRARY}") target_link_libraries(${PROJECT_NAME} PUBLIC ${LIBCRYPTO_LIBRARY}) endif() if(INTERNAL_TIMER AND NOT ${ANDROID}) if(NOT CMAKE_SYSTEM_NAME STREQUAL "FreeBSD") target_link_libraries(${PROJECT_NAME} PUBLIC pthread) endif() endif() add_subdirectory(tests/raw-entropy/recording_userspace) jitterentropy-library-3.6.3/LICENSE000066400000000000000000000033661500137124500171220ustar00rootroot00000000000000Copyright (C) 2017 - 2025, Stephan Mueller Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, and the entire permission notice in its entirety, including the disclaimer of warranties. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. ALTERNATIVELY, this product may be distributed under the terms of the GNU General Public License, in which case the provisions of the GPL2 are required INSTEAD OF the above restrictions. (This clause is necessary due to a potential bad interaction between the GPL and the restrictions contained in a BSD-style copyright.) THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. jitterentropy-library-3.6.3/LICENSE.bsd000066400000000000000000000025461500137124500176700ustar00rootroot00000000000000Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. jitterentropy-library-3.6.3/LICENSE.gplv2000066400000000000000000000431331500137124500201470ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) 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 this service 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 make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. 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. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), 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 distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the 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 a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE 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. 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 convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 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 2 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, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision 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, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This 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 Library General Public License instead of this License. jitterentropy-library-3.6.3/Makefile000066400000000000000000000072201500137124500175460ustar00rootroot00000000000000# Compile Noise Source as user space application CC ?= gcc #Hardening ENABLE_STACK_PROTECTOR ?= 1 CFLAGS ?= -fwrapv --param ssp-buffer-size=4 -fvisibility=hidden -fPIE -Wcast-align -Wmissing-field-initializers -Wshadow -Wswitch-enum CFLAGS +=-Wextra -Wall -pedantic -fPIC -O0 -fwrapv -Wconversion LDFLAGS +=-Wl,-z,relro,-z,now -lpthread # Enable internal timer support CFLAGS += -DJENT_CONF_ENABLE_INTERNAL_TIMER GCCVERSIONFORMAT := $(shell echo `$(CC) -dumpversion | tr '.' '\n' | wc -l`) ifeq "$(GCCVERSIONFORMAT)" "3" GCC_GTEQ_490 := $(shell expr `$(CC) -dumpversion | sed -e 's/\.\([0-9][0-9]\)/\1/g' -e 's/\.\([0-9]\)/0\1/g' -e 's/^[0-9]\{3,4\}$$/&00/'` \>= 40900) else GCC_GTEQ_490 := $(shell expr `$(CC) -dumpfullversion | sed -e 's/\.\([0-9][0-9]\)/\1/g' -e 's/\.\([0-9]\)/0\1/g' -e 's/^[0-9]\{3,4\}$$/&00/'` \>= 40900) endif ifeq "$(ENABLE_STACK_PROTECTOR)" "1" ifeq "$(GCC_GTEQ_490)" "1" CFLAGS += -fstack-protector-strong else CFLAGS += -fstack-protector-all endif endif # Change as necessary PREFIX := /usr/local # library target directory (either lib or lib64) LIBDIR := lib # include target directory INCDIR := include SRCDIR := src INSTALL_STRIP ?= install -s NAME := jitterentropy LIBMAJOR=$(shell cat jitterentropy.h | egrep "define\s+JENT_MAJVERSION" | awk '{print $$3}') LIBMINOR=$(shell cat jitterentropy.h | egrep "define\s+JENT_MINVERSION" | awk '{print $$3}') LIBPATCH=$(shell cat jitterentropy.h | egrep "define\s+JENT_PATCHLEVEL" | awk '{print $$3}') LIBVERSION := $(LIBMAJOR).$(LIBMINOR).$(LIBPATCH) VPATH := $(SRCDIR) C_SRCS := $(notdir $(sort $(wildcard $(SRCDIR)/*.c))) C_OBJS := ${C_SRCS:.c=.o} OBJS := $(C_OBJS) analyze_srcs = $(filter %.c, $(sort $(C_SRCS))) analyze_plists = $(analyze_srcs:%.c=%.plist) INCLUDE_DIRS := . $(SRCDIR) LIBRARY_DIRS := LIBRARIES := rt CFLAGS += $(foreach includedir,$(INCLUDE_DIRS),-I$(includedir)) LDFLAGS += $(foreach librarydir,$(LIBRARY_DIRS),-L$(librarydir)) LDFLAGS += $(foreach library,$(LIBRARIES),-l$(library)) .PHONY: all scan install clean distclean check $(NAME) $(NAME)-static all: $(NAME) $(NAME)-static lib$(NAME).a: $(OBJS) $(AR) rcs lib$(NAME).a $(OBJS) lib$(NAME).so.$(LIBVERSION): $(OBJS) $(CC) -shared -Wl,-soname,lib$(NAME).so.$(LIBMAJOR) -o lib$(NAME).so.$(LIBVERSION) $(OBJS) $(LDFLAGS) $(NAME)-static: lib$(NAME).a $(NAME): lib$(NAME).so.$(LIBVERSION) $(analyze_plists): %.plist: %.c @echo " CCSA " $@ clang --analyze $(CFLAGS) $< -o $@ scan: $(analyze_plists) cppcheck: cppcheck --force -q --enable=performance --enable=warning --enable=portability $(shell find * -name \*.h -o -name \*.c) install: install-man install-shared install-includes install-man: install -d -m 0755 $(DESTDIR)$(PREFIX)/share/man/man3 install -m 644 doc/$(NAME).3 $(DESTDIR)$(PREFIX)/share/man/man3/ gzip -n -f -9 $(DESTDIR)$(PREFIX)/share/man/man3/$(NAME).3 install-shared: install -d -m 0755 $(DESTDIR)$(PREFIX)/$(LIBDIR) $(INSTALL_STRIP) -m 0755 lib$(NAME).so.$(LIBVERSION) $(DESTDIR)$(PREFIX)/$(LIBDIR)/ $(RM) $(DESTDIR)$(PREFIX)/$(LIBDIR)/lib$(NAME).so.$(LIBMAJOR) ln -sf lib$(NAME).so.$(LIBVERSION) $(DESTDIR)$(PREFIX)/$(LIBDIR)/lib$(NAME).so.$(LIBMAJOR) ln -sf lib$(NAME).so.$(LIBMAJOR) $(DESTDIR)$(PREFIX)/$(LIBDIR)/lib$(NAME).so install-includes: install -d -m 0755 $(DESTDIR)$(PREFIX)/$(INCDIR) install -m 0644 jitterentropy.h $(DESTDIR)$(PREFIX)/$(INCDIR)/ install -m 0644 jitterentropy-base-user.h $(DESTDIR)$(PREFIX)/$(INCDIR)/ install-static: install -d -m 0755 $(DESTDIR)$(PREFIX)/$(LIBDIR) install -m 0755 lib$(NAME).a $(DESTDIR)$(PREFIX)/$(LIBDIR)/ clean: @- $(RM) $(NAME) @- $(RM) $(OBJS) @- $(RM) lib$(NAME).so* @- $(RM) lib$(NAME).a @- $(RM) $(analyze_plists) distclean: clean jitterentropy-library-3.6.3/README.md000066400000000000000000000045261500137124500173730ustar00rootroot00000000000000Hardware RNG based on CPU timing jitter ======================================= The Jitter RNG provides a noise source using the CPU execution timing jitter. It does not depend on any system resource other than a high-resolution time stamp. It is a small-scale, yet fast entropy source that is viable in almost all environments and on a lot of CPU architectures. The implementation of the Jitter RNG is independent of any operating system. As such, it could even run on baremetal without any operating system. The design of the RNG is given in the documentation found in at http://www.chronox.de/jent . This documentation also covers the full assessment of the SP800-90B compliance as well as all required test code. API --- The API is documented in the man page jitterentropy.3. To use the Jitter RNG, the header file jitterentropy.h must be included. Build Instructions ================== To generate the shared library `make` followed by `make install`. Android ------- To compile the code on Android, use the following Makefile: arch/android/Android.mk -- NDK make file template that can be used to directly compile the CPU Jitter RNG code into Android binaries Direct CPU instructions ----------------------- If the function in jent_get_nstime is not available, you can replace the jitterentropy-base-user.h with examples from the arch/ directory. Testing ======= There are numerous tests around the Jitter RNG. Yet, they are too big to be loaded into the official repository. Email me, if you want them. Version Numbers =============== The version numbers for this library have the following schema: MAJOR.MINOR.PATCHLEVEL Changes in the major number implies API and ABI incompatible changes, or functional changes that require consumer to be updated (as long as this number is zero, the API is not considered stable and can change without a bump of the major version). Changes in the minor version are API compatible, but the ABI may change. Functional enhancements only are added. Thus, a consumer can be left unchanged if enhancements are not considered. The consumer only needs to be recompiled. Patchlevel changes are API / ABI compatible. No functional changes, no enhancements are made. This release is a bug fixe release only. The consumer can be left unchanged and does not need to be recompiled. Author ====== Stephan Mueller jitterentropy-library-3.6.3/SECURITY.md000066400000000000000000000016231500137124500177000ustar00rootroot00000000000000# Security Issues The following list tries to enumerate all security issues on a best-effort basis. # Reporting Of Issues If you detect any new security issues, please file a bug report or send a private email to . ## 2024-12-30 The API call `jent_read_entropy_safe` contains the logic to transparently handle intermittent health test errors by reallocating a new Jitter RNG entropy collector handle and increasing the OSR as well as the memory usage. During that reallocation, the currently observed APT and RCT counter values are copied info the new handle. That copy operation contains an failure for the RCT which effectively disabled the RCT for all newly allocated entropy collector instances - the other health tests as well as the Jitter RNG itself operates still as expected with the newly allocated entropy collector instances. Thanks to Joshua Hill for pointing this issue out. jitterentropy-library-3.6.3/arch/000077500000000000000000000000001500137124500170225ustar00rootroot00000000000000jitterentropy-library-3.6.3/arch/android/000077500000000000000000000000001500137124500204425ustar00rootroot00000000000000jitterentropy-library-3.6.3/arch/android/Android.mk000066400000000000000000000023651500137124500223610ustar00rootroot00000000000000# Copyright (C) 2009 The Android Open Source Project # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := jitterentropy LOCAL_CFLAGS := -O0 -DCRYPTO_CPU_JITTERENTROPY_STAT LOCAL_SRC_FILES := jitterentropy-base.c jitterentropy-stat.c jitterentropy-foldtime.c # compile into a shared library that can be pulled into an APK LOCAL_STATIC_LIBRARIES := android_native_app_glue include $(BUILD_SHARED_LIBRARY) $(call import-module,android/native_app_glue) # compilation of a standalone-binary that must be manually moved to # Android /data partition for execution. #include $(BUILD_EXECUTABLE) # compilation of the CPU Jitter RNG app #LOCAL_SRC_FILES := jitterentropy-base.c jitterentropy-main-user.c jitterentropy-library-3.6.3/arch/android/AndroidManifest.xml000066400000000000000000000015451500137124500242400ustar00rootroot00000000000000 jitterentropy-library-3.6.3/arch/android/README000066400000000000000000000006771500137124500213340ustar00rootroot00000000000000See comments in Android.mk When compiling an APK, follow roughly these steps 1. create dir /jitterentropy 2. copy AndroidManifest.xml to /jitterentropy 3. copy code and Android.mk to /jitterentropy/jni 4. cd /jitterentropy 5. open eclipse and import project 6. on console android update project -p . -s 7. ../ndk-build 8. in eclipse: open manifest and compile am start -n de.chronox.jitterentropy/android.app.NativeActivity jitterentropy-library-3.6.3/arch/jitterentropy-base-power.h000066400000000000000000000101511500137124500241550ustar00rootroot00000000000000/* * Non-physical true random number generator based on timing jitter. * * Copyright Stephan Mueller , 2013 - 2025 * * License * ======= * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, and the entire permission notice in its entirety, * including the disclaimer of warranties. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote * products derived from this software without specific prior * written permission. * * ALTERNATIVELY, this product may be distributed under the terms of * the GNU General Public License, in which case the provisions of the GPL are * required INSTEAD OF the above restrictions. (This clause is * necessary due to a potential bad interaction between the GPL and * the restrictions contained in a BSD-style copyright.) * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH * DAMAGE. */ #ifndef _JITTERENTROPY_BASE_POWER_H #define _JITTERENTROPY_BASE_POWER_H #include #include #include #include /* taken from http://www.ecrypt.eu.org/ebats/cpucycles.html */ static inline void jent_get_nstime(uint64_t *out) { unsigned long high; unsigned long low; unsigned long newhigh; uint64_t result; __asm__ __volatile__( "Lcpucycles:mftbu %0;mftb %1;mftbu %2;cmpw %0,%2;bne Lcpucycles" : "=r" (high), "=r" (low), "=r" (newhigh) ); result = high; result <<= 32; result |= low; *out = result; } static inline void *jent_zalloc(size_t len) { void *tmp = NULL; /* we have no secure memory allocation! Hence * we do not sed CRYPTO_CPU_JITTERENTROPY_SECURE_MEMORY */ tmp = malloc(len); if(NULL != tmp) memset(tmp, 0, len); return tmp; } static inline void jent_zfree(void *ptr, unsigned int len) { memset(ptr, 0, len); free(ptr); } static inline int jent_fips_enabled(void) { return 0; } static inline long jent_ncpu(void) { /* * TODO: return number of available CPUs - * this code disables timer thread as only one CPU is "detected". */ return 1; } static inline void jent_yield(void) { sched_yield(); } static inline uint32_t jent_cache_size_roundup(void) { #ifdef __linux__ long l1 = sysconf(_SC_LEVEL1_DCACHE_SIZE); long l2 = sysconf(_SC_LEVEL2_CACHE_SIZE); long l3 = sysconf(_SC_LEVEL3_CACHE_SIZE); uint32_t cache_size = 0; /* Cache size reported by system */ if (l1 > 0) cache_size += (uint32_t)l1; if (l2 > 0) cache_size += (uint32_t)l2; if (l3 > 0) cache_size += (uint32_t)l3; /* Force the output_size to be of the form (bounding_power_of_2 - 1). */ cache_size |= (cache_size >> 1); cache_size |= (cache_size >> 2); cache_size |= (cache_size >> 4); cache_size |= (cache_size >> 8); cache_size |= (cache_size >> 16); if (cache_size == 0) return 0; /* Make the output_size the smallest power of 2 strictly greater than cache_size. */ cache_size++; return cache_size; #else return 0; #endif } /* --- helpers needed in user space -- */ static inline uint64_t rol64(uint64_t x, int n) { return ( (x << (n&(64-1))) | (x >> ((64-n)&(64-1))) ); } #endif /* _JITTERENTROPY_BASE_POWER_H */ jitterentropy-library-3.6.3/arch/jitterentropy-base-s390.h000066400000000000000000000077531500137124500235350ustar00rootroot00000000000000/* * Non-physical true random number generator based on timing jitter. * * Copyright Stephan Mueller , 2013 - 2025 * * License * ======= * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, and the entire permission notice in its entirety, * including the disclaimer of warranties. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote * products derived from this software without specific prior * written permission. * * ALTERNATIVELY, this product may be distributed under the terms of * the GNU General Public License, in which case the provisions of the GPL are * required INSTEAD OF the above restrictions. (This clause is * necessary due to a potential bad interaction between the GPL and * the restrictions contained in a BSD-style copyright.) * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH * DAMAGE. */ #ifndef _JITTERENTROPY_BASE_S390_H #define _JITTERENTROPY_BASE_S390_H #include #include #include #include static inline void jent_get_nstime(uint64_t *out) { uint64_t clk; /* this is MVS code! enable with -S in the compiler */ /*__asm__ __volatile__("stck %0" : "=m" (clk) : : "cc"); */ /* this is gcc */ __asm__ __volatile__("stcke %0" : "=Q" (clk) : : "cc"); *out = (uint64_t)(clk); } static inline void *jent_zalloc(size_t len) { void *tmp = NULL; /* we have no secure memory allocation! Hence * we do not sed CRYPTO_CPU_JITTERENTROPY_SECURE_MEMORY */ tmp = malloc(len); if(NULL != tmp) memset(tmp, 0, len); return tmp; } static inline void jent_zfree(void *ptr, unsigned int len) { memset(ptr, 0, len); free(ptr); } static inline int jent_fips_enabled(void) { return 0; } static inline long jent_ncpu(void) { /* * TODO: return number of available CPUs - * this code disables timer thread as only one CPU is "detected". */ return 1; } static inline void jent_yield(void) { sched_yield(); } static inline uint32_t jent_cache_size_roundup(void) { #ifdef __linux__ long l1 = sysconf(_SC_LEVEL1_DCACHE_SIZE); long l2 = sysconf(_SC_LEVEL2_CACHE_SIZE); long l3 = sysconf(_SC_LEVEL3_CACHE_SIZE); uint32_t cache_size = 0; /* Cache size reported by system */ if (l1 > 0) cache_size += (uint32_t)l1; if (l2 > 0) cache_size += (uint32_t)l2; if (l3 > 0) cache_size += (uint32_t)l3; /* Force the output_size to be of the form (bounding_power_of_2 - 1). */ cache_size |= (cache_size >> 1); cache_size |= (cache_size >> 2); cache_size |= (cache_size >> 4); cache_size |= (cache_size >> 8); cache_size |= (cache_size >> 16); if (cache_size == 0) return 0; /* Make the output_size the smallest power of 2 strictly greater than cache_size. */ cache_size++; return cache_size; #else return 0; #endif } /* --- helpers needed in user space -- */ static inline uint64_t rol64(uint64_t x, int n) { return ( (x << (n&(64-1))) | (x >> ((64-n)&(64-1))) ); } #endif /* _JITTERENTROPY_BASE_S390_H */ jitterentropy-library-3.6.3/arch/jitterentropy-base-windows.h000066400000000000000000000075041500137124500245230ustar00rootroot00000000000000/* * Non-physical true random number generator based on timing jitter. * * Copyright Stephan Mueller , 2013 - 2025 * * License * ======= * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, and the entire permission notice in its entirety, * including the disclaimer of warranties. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote * products derived from this software without specific prior * written permission. * * ALTERNATIVELY, this product may be distributed under the terms of * the GNU General Public License, in which case the provisions of the GPL are * required INSTEAD OF the above restrictions. (This clause is * necessary due to a potential bad interaction between the GPL and * the restrictions contained in a BSD-style copyright.) * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE e USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH * DAMAGE. */ #ifndef _JITTERENTROPY_BASE_X86_H #define _JITTERENTROPY_BASE_X86_H #include #if defined(_MSC_VER) typedef int64_t ssize_t; #include #endif #include #include #include #if defined(AWSLC) #include #endif #if defined(_M_ARM) || defined(_M_ARM64) #include #include #endif static inline void jent_get_nstime(uint64_t *out) { #if defined(_M_ARM) || defined(_M_ARM64) /* Generic code. */ LARGE_INTEGER ticks; QueryPerformanceCounter(&ticks); *out = ticks.QuadPart; #else /* x86, x86_64 intrinsic */ *out = __rdtsc(); #endif } static inline void *jent_zalloc(size_t len) { void *tmp = NULL; /* we have no secure memory allocation! Hence * we do not sed CRYPTO_CPU_JITTERENTROPY_SECURE_MEMORY */ #if defined(AWSLC) tmp = OPENSSL_malloc(len); #else tmp = malloc(len); #endif if(NULL != tmp) memset(tmp, 0, len); return tmp; } static inline void jent_zfree(void *ptr, unsigned int len) { #if defined(AWSLC) (void) len; OPENSSL_free(ptr); #else memset(ptr, 0, len); free(ptr); #endif } static inline int jent_fips_enabled(void) { #if defined(AWSLC) return FIPS_mode(); #else return 0; #endif } static inline void jent_memset_secure(void *s, size_t n) { #if defined(AWSLC) OPENSSL_cleanse(s, n); #else SecureZeroMemory(s, n); #endif } static inline long jent_ncpu(void) { /* * TODO: return number of available CPUs - * this code disables timer thread as only one CPU is "detected". */ return 1; } static inline void jent_yield(void) { } static inline uint32_t jent_cache_size_roundup(void) { return 0; } /* --- helpers needed in user space -- */ /* note: these helper functions are shamelessly stolen from the kernel :-) */ static inline uint64_t rol64(uint64_t word, unsigned int shift) { return (word << shift) | (word >> (64 - shift)); } #endif /* _JITTERENTROPY_BASE_X86_H */ jitterentropy-library-3.6.3/arch/jitterentropy-base-x86.h000066400000000000000000000107571500137124500234620ustar00rootroot00000000000000/* * Non-physical true random number generator based on timing jitter. * * Copyright Stephan Mueller , 2013 - 2025 * * License * ======= * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, and the entire permission notice in its entirety, * including the disclaimer of warranties. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote * products derived from this software without specific prior * written permission. * * ALTERNATIVELY, this product may be distributed under the terms of * the GNU General Public License, in which case the provisions of the GPL are * required INSTEAD OF the above restrictions. (This clause is * necessary due to a potential bad interaction between the GPL and * the restrictions contained in a BSD-style copyright.) * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH * DAMAGE. */ #ifndef _JITTERENTROPY_BASE_X86_H #define _JITTERENTROPY_BASE_X86_H #include #include #include #include /* Timer-less entropy source */ #include typedef uint64_t __u64; /* taken from Linux kernel */ #ifdef __x86_64__ #define DECLARE_ARGS(val, low, high) unsigned long low, high #define EAX_EDX_VAL(val, low, high) ((low) | (high) << 32) #define EAX_EDX_RET(val, low, high) "=a" (low), "=d" (high) #else #define DECLARE_ARGS(val, low, high) unsigned long long val #define EAX_EDX_VAL(val, low, high) (val) #define EAX_EDX_RET(val, low, high) "=A" (val) #endif static inline void jent_get_nstime(uint64_t *out) { DECLARE_ARGS(val, low, high); __asm__ __volatile__("rdtsc" : EAX_EDX_RET(val, low, high)); *out = EAX_EDX_VAL(val, low, high); } static inline void *jent_zalloc(size_t len) { void *tmp = NULL; /* we have no secure memory allocation! Hence * we do not sed CRYPTO_CPU_JITTERENTROPY_SECURE_MEMORY */ tmp = malloc(len); if(NULL != tmp) memset(tmp, 0, len); return tmp; } static inline void jent_zfree(void *ptr, unsigned int len) { memset(ptr, 0, len); free(ptr); } static inline int jent_fips_enabled(void) { return 0; } static inline void jent_memset_secure(void *s, size_t n) { memset(s, 0, n); __asm__ __volatile__("" : : "r" (s) : "memory"); } static inline long jent_ncpu(void) { /* * TODO: return number of available CPUs - * this code disables timer thread as only one CPU is "detected". */ return 1; } static inline void jent_yield(void) { sched_yield(); } static inline uint32_t jent_cache_size_roundup(void) { #ifdef __linux__ long l1 = sysconf(_SC_LEVEL1_DCACHE_SIZE); long l2 = sysconf(_SC_LEVEL2_CACHE_SIZE); long l3 = sysconf(_SC_LEVEL3_CACHE_SIZE); uint32_t cache_size = 0; /* Cache size reported by system */ if (l1 > 0) cache_size += (uint32_t)l1; if (l2 > 0) cache_size += (uint32_t)l2; if (l3 > 0) cache_size += (uint32_t)l3; /* Force the output_size to be of the form (bounding_power_of_2 - 1). */ cache_size |= (cache_size >> 1); cache_size |= (cache_size >> 2); cache_size |= (cache_size >> 4); cache_size |= (cache_size >> 8); cache_size |= (cache_size >> 16); if (cache_size == 0) return 0; /* Make the output_size the smallest power of 2 strictly greater than cache_size. */ cache_size++; return cache_size; #else return 0; #endif } /* --- helpers needed in user space -- */ static inline uint64_t rol64(uint64_t x, int n) { return ( (x << (n&(64-1))) | (x >> ((64-n)&(64-1))) ); } #endif /* _JITTERENTROPY_BASE_X86_H */ jitterentropy-library-3.6.3/doc/000077500000000000000000000000001500137124500166525ustar00rootroot00000000000000jitterentropy-library-3.6.3/doc/README000066400000000000000000000000641500137124500175320ustar00rootroot00000000000000For design documentation, see http://www.chronox.de jitterentropy-library-3.6.3/doc/jitterentropy.3000066400000000000000000000312701500137124500216630ustar00rootroot00000000000000.\" Copyright (c) 2013 - 2025 by Stephan Mueller (smueller@chronox.de) .\" .\" Permission is granted to make and distribute verbatim copies of this .\" manual provided the copyright notice and this permission notice are .\" preserved on all copies. .\" .\" Permission is granted to copy and distribute modified versions of this .\" manual under the conditions for verbatim copying, provided that the .\" entire resulting derived work is distributed under the terms of a .\" permission notice identical to this one. .\" .\" Formatted or processed versions of this manual, if unaccompanied by .\" the source, must acknowledge the copyright and authors of this work. .\" License. .TH JITTERENTROPY 3 2021-03-08 .SH NAME jitterentropy \- CPU Jitter Random Number Generator .SH SYNOPSIS .nf .B #include .sp .BI "int jent_entropy_switch_notime_impl(struct jent_notime_thread *" new_thread ); .sp .BI "int jent_set_fips_failure_callback(jent_fips_failure_cb " cb "); .sp .BI "int jent_entropy_init(" void "); .sp .BI "int jent_entropy_init_ex(unsigned int " osr ", unsigned int " flags ); .sp .BI "struct rand_data *jent_entropy_collector_alloc(unsigned int " osr ", .BI " unsigned int " flags ); .sp .BI "void jent_entropy_collector_free(struct rand_data *" entropy_collector ); .sp .BI "ssize_t jent_read_entropy(struct rand_data *" entropy_collector ", .BI " char *" data ", size_t " len ); .sp .BI "ssize_t jent_read_entropy_safe(struct rand_data **" entropy_collector ", .BI " char *" data ", size_t " len ); .sp .BI "#define JENT_MAJVERSION x" .sp .BI "#define JENT_MINVERSION y" .sp .BI "#define JENT_PATCHLEVEL z" .sp .BI "#define JENT_VERSION (...)" .sp .BI "unsigned int jent_version(" void "); .fi .SH DESCRIPTION The .I jitterentropy library provides a source of good entropy by collecting CPU executing time jitter. The entropy in the CPU execution time jitter is magnified by the CPU Jitter Random Number Generator. The CPU Jitter Random Number Generator uses the CPU execution timing jitter to generate a bit stream which complies with different statistical measurements that determine the bit stream is random. .LP The CPU Jitter Random Number Generator delivers entropy which follows information theoretical requirements. Based on these studies and the implementation, the caller can assume that one bit of data extracted from the CPU Jitter Random Number Generator holds one bit of entropy. .LP The CPU Jitter Random Number Generator provides a decentralized source of entropy where the caller does not need to rely on a centrally maintained source of entropy like .IR /dev/random or .IR /dev/urandom . .LP .BR jent_entropy_switch_notime_impl () allows the caller to set a thread handler that is used by the Jitter RNG if it operates in the timer-less mode. See .IR jitterentropy.h for a documentation of .IR new_thread . This function must be called before .BR jent_entropy_init () as after this call, the change of the thread handler is denied. .LP .BR jent_set_fips_failure_callback () allows the caller to set a callback that is invoked by the Jitter RNG when a health test failure is detected. The callback specified with the parameter .BR cb to the API function receives the Jitter RNG state with the parameter .BR ec and the FIPS health test failure with the parameter .BR health_failure . his function must be called before .BR jent_entropy_init () as after this call, the change of the callback is denied. .LP .BR jent_entropy_init () initializes the CPU Jitter Random Number Generator. The function performs statistical tests to verify that the underlying system offers the properties needed for measuring and collecting entropy. If the initialization is successful, which implies that the statistical tests indicate the underlying system is appropriate, the call returns with .IR 0 . A return code other than .IR 0 indicates a failure where the calling application .B MUST NOT use the CPU Jitter Random Number Generator. .LP .BR jent_entropy_init_ex () behaves identically to .BR jent_entropy_init () except that it allows the caller to provide the .IR osr and .IR flags parameters which should be identical to the subsequent invocation of .BR jent_entropy_collector_alloc (). When specifying an oversampling rate .IR osr different than the default, the startup test honor this value and adjust the self-test cut-off thresholds to the same values as used at runtime. .LP .BR jent_entropy_collector_alloc () allocates a CPU Jitter entropy collector instance and returns the handle to the caller. If the allocation fails, including memory constraints, the call returns .IR NULL . The function requires two arguments, the oversampling rate .IR osr and a set of flags with .IR flags . The .IR osr value defines the amount of oversampling performed by the entropy collector. Usually, a caller wants to provide the value 0 here to apply the default oversampling. The call ensures that any value lower than .B JENT_MIN_OSR is converted to .B JENT_MIN_OSR automatically. .LP The .IR flags value is either zero or one or more of the following flags. .TP .B JENT_DISABLE_MEMORY_ACCESS If the system is constrained with memory, this flag disables the allocation of that memory and therefore memory accesses. But that also implies that the entropy collection process only relies on the complexity of the CPU. Note, if somebody knows all details of that CPU complexity, that person may potentially reduce the entropy delivered by the CPU complexity. If that person can push the generated entropy below a threshold, the CPU Jitter random number generator starts overestimating entropy from the noise source. Thus, disabling memory accesses and relying only on the CPU complexity should only be done if you really know what you are doing. .TP .B JENT_FORCE_INTERNAL_TIMER This flag can be used to force the Jitter RNG to use the internal high-resolution timer instead of using the hardware time stamp. Commonly, the startup self test performed with .BR jent_entropy_init () uses the hardware timer with precedence if it is identified to be appropriate for entropy collection. If the internal timer is not compiled, requesting this flag returns an error. Even though a separate thread is spawned to provide a high-resolution time stamp, this entire operation is completely thread-safe as all relevant data is maintained as part of the .IR entropy_collector data structure. .TP .B JENT_DISABLE_INTERNAL_TIMER This flag can be used to ensure that the internal timer is not used. If this flag is used together with .B JENT_FORCE_INTERNAL_TIMER this is treated as an error and the allocation returns NULL. Also, in case .BR jent_entropy_init () detects that the internal timer shall be used but the disable flag is set, the allocation returns NULL. .TP .B JENT_FORCE_FIPS Force full FIPS 140 and SP800-90B compliance irrespective of the FIPS setting of the underlying operating system. .TP .B JENT_MAX_MEMSIZE_* Define the maximum amount of memory that the Jitter RNG will use for its operation supporting the collection of raw noise. Without using one of these flags, the Jitter RNG uses a built-in limit. The larger the amount of memory is the more entropy is collected. Yet, the default value is safe on most CPUs. If you have memory pressure but the entropy rate of your CPU is sufficient a lower memory size may be used. Contrary when having sufficient memory but insufficient entropy, larger memory sizes may be specified. In any case, the Jitter RNG uses at most as much memory as the sum of the CPU's data caches. .LP .BR jent_entropy_collector_free() zeroizes and frees the given CPU Jitter entropy collector instance. .LP .BR jent_read_entropy () generates a random bit stream and returns it to the caller. .IR entropy_collector is the CPU Jitter entropy collector instance which shall be used to obtain random numbers. .IR data is the destination memory location where the random bit stream is written to. The memory must have already been allocated by the caller. .IR len is a length value provided by the caller indicating the number of bytes the CPU Jitter Random Number Generator shall generate. The caller can provide any value greater than 0. The caller must ensure that .IR data is at least als big as .IR len indicates. The function returns the number of bytes generated when the request is successfully completed. If the function returns the error code .IR -1 then the caller handed in a non-initialized (i.e. NULL value) for the entropy collector. The return code of .IR -2 indicates the SP800-90B repetition count online health test failed. The error code of .IR -3 specifies that the SP800-90B adaptive proportion online health test failed. .IR -4 marks that the internal timer generator cannot be initialized. .IR -5 specifies that the LAG predictor health test failed. .IR -6 indicates that the Repetitive Count Test (RCT) failed permanently. .IR -7 indicates that the Adaptive Proportion Test (APT) failed permanently. .IR -8 indicates that the LAG prediction test failed permanently. .LP When either online health test fails the Jitter RNG will not have any data provided in .IR data . The entropy collector instance will remain in error state. To recover, the entropy collector instance .B MUST be deallocated and a fresh instance must be allocated. It is recommended that you increase the .IR osr value at least by one when newly allocating the Jitter RNG with .BR jent_entropy_collector_alloc () which implies that the health tests are less sensitive due to the fact that the assumed entropy rate of the noise source is lower. .LP .BR jent_read_entropy_safe () is a service function to and therefore operates identically to .BR jent_read_entropy () with the exception that it automatically re-allocates the entropy collector if a health test failure is observed. Before reallocation, a new power-on health test is performed. The allocation of the new entropy collector automatically increases the OSR by one. This is done based on the idea that a health test failure indicates that the assumed entropy rate is too high. .LP Note the function returns with an health test error if the OSR is getting too large. If an error is returned by this function, the Jitter RNG is not safe to be used on the current system. .LP The function .BR jent_read_entropy_safe () has the same error codes as .BR jent_read_entropy (). .LP .BR JENT_MAJVERSION indicates API / ABI incompatible changes, functional changes that require consumer to be updated. .LP .BR JENT_MINVERSION indicates API compatible, ABI may change, functional enhancements only, consumer can be left unchanged if enhancements are not considered. .LP .BR JENT_PATCHLEVEL indicates API / ABI compatible, no functional changes, no enhancements, bug fixes only. Also, the entropy collection is not changed in any way that would necessitate a re-assessment. .LP .BR JENT_VERSION the version number of the library as an integer value that is monotonically increasing. The version numbers are multiples of 100. For example, version 1.2.3 is converted to 1020300 -- the last two digits are reserved for future use. .LP .BR jent_version () returns .BR JENT_VERSION. .PP .SH FIPS 140-3 Considerations In order for the Jitter RNG to execute compliant to FIPS 140-3 and by extension also SP800-90B and SP800-90C compliant, the following considerations must be applied: .TP .B Enable FIPS mode The FIPS mode is enabled by using the .IR JENT_FORCE_FIPS flag during initialization of the Jitter RNG library. On Linux, the the FIPS mode is transparently enabled if the entire operating system was booted in FIPS mode, usually by using the "fips=1" Linux kernel command line parameter. .TP .B Perform heursitic entropy analysis The test tool set provided as part of the Jitter RNG library source distribution contains the helper to obtain raw noise data at runtime as well as at initialization time to calculate the SP800-90B entropy rate. This rate must be above 0.333, the implied heuristic minimum by the Jitter RNG library. .TP .B Resolve insufficient entropy If insufficient entropy is found during the aforementioned SP800-90B analysis, the test tool set provides a helper to analyze optimal settings - see the test tool set for raw entropy for details. The resulting configuration values are expected to be used with the .IR flags parameter of the calls .BR jent_entropy_collector_alloc () and .BR jent_entropy_init_ex () . It is recommended that the function .BR jent_read_entropy_safe () API call is used for generating random numbers. .PP .SH NOTES In addition to use the generated random bit stream directly for cryptographic operations, the output of .BR jent_read_entropy () can be used for seeding a deterministic random number generator. .PP .SH SEE ALSO http://www.chronox.de provides the design description, the entropy and statistical analyses as well as a number of test cases. jitterentropy-library-3.6.3/jitterentropy-base-user.h000066400000000000000000000316451500137124500230750ustar00rootroot00000000000000/* * Non-physical true random number generator based on timing jitter. * * Copyright Stephan Mueller , 2013 - 2025 * * License * ======= * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, and the entire permission notice in its entirety, * including the disclaimer of warranties. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote * products derived from this software without specific prior * written permission. * * ALTERNATIVELY, this product may be distributed under the terms of * the GNU General Public License, in which case the provisions of the GPL are * required INSTEAD OF the above restrictions. (This clause is * necessary due to a potential bad interaction between the GPL and * the restrictions contained in a BSD-style copyright.) * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH * DAMAGE. */ #ifndef _JITTERENTROPY_BASE_USER_H #define _JITTERENTROPY_BASE_USER_H /* * Set the following defines as needed for your environment * Compilation for AWS-LC #define AWSLC * Compilation for libgcrypt #define LIBGCRYPT * Compilation for OpenSSL #define OPENSSL */ #include #include #include #include #include #include #include #include #include #include #include #include /* Timer-less entropy source */ #ifdef JENT_CONF_ENABLE_INTERNAL_TIMER #include #endif /* JENT_CONF_ENABLE_INTERNAL_TIMER */ #ifdef LIBGCRYPT #include #include "g10lib.h" #endif #ifdef OPENSSL #include #ifdef OPENSSL_FIPS #include #endif #endif #if defined(AWSLC) #include #endif #ifdef __MACH__ #include #include #include #include #include #endif #if (__x86_64__) || (__i386__) /* Support rdtsc read on 64-bit and 32-bit x86 architectures */ #ifdef __x86_64__ /* specify 64 bit type since long is 32 bits in LLP64 x86_64 systems */ # define DECLARE_ARGS(val, low, high) uint64_t low, high # define EAX_EDX_VAL(val, low, high) ((low) | (high) << 32) # define EAX_EDX_RET(val, low, high) "=a" (low), "=d" (high) #elif __i386__ # define DECLARE_ARGS(val, low, high) unsigned long val # define EAX_EDX_VAL(val, low, high) val # define EAX_EDX_RET(val, low, high) "=A" (val) #endif static inline void jent_get_nstime(uint64_t *out) { DECLARE_ARGS(val, low, high); #ifdef __sun__ __asm("rdtsc" : EAX_EDX_RET(val, low, high)); #else __asm__ __volatile__("rdtsc" : EAX_EDX_RET(val, low, high)); #endif *out = EAX_EDX_VAL(val, low, high); } #elif defined(__aarch64__) #ifndef AARCH64_NSTIME_REGISTER #define AARCH64_NSTIME_REGISTER "cntvct_el0" #endif static inline void jent_get_nstime(uint64_t *out) { uint64_t ctr_val; #if !defined(__MACH__) /* * Use the system counter for aarch64 (64 bit ARM)... */ __asm__ __volatile__("mrs %0, " AARCH64_NSTIME_REGISTER : "=r" (ctr_val)); #else /* * Except on modern Apple platforms. Especially on M1 generation Arm64 * CPUs, the system counter is too coarse. Instead, use * clock_gettime_nsec_np(CLOCK_UPTIME_RAW), that is equivalent to * march_absolute_time(), but scaled to nanoseconds. See e.g. * https://www.manpagez.com/man/3/clock_gettime_nsec_np/. */ ctr_val = clock_gettime_nsec_np(CLOCK_UPTIME_RAW); #endif *out = ctr_val; } #elif defined(__s390x__) static inline void jent_get_nstime(uint64_t *out) { /* * This is MVS+STCK code! Enable it with -S in the compiler. * * uint64_t clk; * __asm__ __volatile__("stck %0" : "=m" (clk) : : "cc"); * *out = (uint64_t)(clk); */ /* * This is GCC+STCKE code. STCKE command and data format: * z/Architecture - Principles of Operation * http://publibz.boulder.ibm.com/epubs/pdf/dz9zr007.pdf * * The current value of bits 0-103 of the TOD clock is stored in bytes * 1-13 of the sixteen-byte output: * * bits 0-7: zeros (reserved for future extention) * bits 8-111: TOD Clock value * bits 112-127: Programmable Field * * Output bit 59 (TOD-Clock bit 51) effectively increments every * microsecond. Bits 60 to 111 of STCKE output are fractions of * a miscrosecond: bit 59 is 1.0us, bit 60 is .5us, bit 61 is .25us, * bit 62 is .125us, bit 63 is 62.5ns, etc. * * Some of these bits can be implemented, some not. 64 bits of * the TOD clock are implemented usually nowadays, these are * bits 8-71 of the output. * * The stepping value of TOD-clock bit position 63, if implemented, * is 2^-12 microseconds, or approximately 244 picoseconds. This value * is called a clock unit. */ uint8_t clk[16]; __asm__ __volatile__("stcke %0" : "=Q" (clk) : : "cc"); /* s390x is big-endian, so just perfom a byte-by-byte copy */ *out = *(uint64_t *)(clk + 1); } #elif defined(__powerpc) /* * Uncomment this for newer PPC CPUs * Newer PPC CPUs do not support mftbu/mftb * these instructions were obsoleted and replaced by * mfspr. special processor registers 268 and 269 are the * ones we want. */ /* #define POWER_PC_USE_NEW_INSTRUCTIONS */ /* taken from http://www.ecrypt.eu.org/ebats/cpucycles.html */ static inline void jent_get_nstime(uint64_t *out) { unsigned long high; unsigned long low; unsigned long newhigh; uint64_t result; #ifdef POWER_PC_USE_NEW_INSTRUCTIONS /* Newer PPC CPUs do not support mftbu/mftb */ __asm__ __volatile__( "Lcpucycles:mfspr %0, 269;mfspr %1, 268;mfspr %2, 269;cmpw %0,%2;bne Lcpucycles" : "=r" (high), "=r" (low), "=r" (newhigh) ); #else __asm__ __volatile__( "Lcpucycles:mftbu %0;mftb %1;mftbu %2;cmpw %0,%2;bne Lcpucycles" : "=r" (high), "=r" (low), "=r" (newhigh) ); #endif result = high; result <<= 32; result |= low; *out = result; } #else /* (__x86_64__) || (__i386__) || (__aarch64__) || (__s390x__) || (__powerpc) */ static inline void jent_get_nstime(uint64_t *out) { /* OSX does not have clock_gettime -- taken from * http://developer.apple.com/library/mac/qa/qa1398/_index.html */ # ifdef __MACH__ *out = mach_absolute_time(); # elif _AIX /* clock_gettime() on AIX returns a timer value that increments in * steps of 1000 */ uint64_t tmp = 0; timebasestruct_t aixtime; tmp = aixtime.tb_high * 1000000000UL; tmp += aixtime.tb_low; *out = tmp; # else /* __MACH__ */ /* we could use CLOCK_MONOTONIC(_RAW), but with CLOCK_REALTIME * we get some nice extra entropy once in a while from the NTP actions * that we want to use as well... though, we do not rely on that * extra little entropy */ uint64_t tmp = 0; struct timespec time; if (clock_gettime(CLOCK_REALTIME, &time) == 0) { tmp = ((uint64_t)time.tv_sec & 0xFFFFFFFF) * 1000000000UL; tmp = tmp + (uint64_t)time.tv_nsec; } *out = tmp; # endif /* __MACH__ */ } #endif /* (__x86_64__) || (__i386__) || (__aarch64__) */ static inline void *jent_zalloc(size_t len) { void *tmp = NULL; #ifdef LIBGCRYPT /* When using the libgcrypt secure memory mechanism, all precautions * are taken to protect our state. If the user disables secmem during * runtime, it is his decision and we thus try not to overrule his * decision for less memory protection. */ #define CONFIG_CRYPTO_CPU_JITTERENTROPY_SECURE_MEMORY tmp = gcry_xmalloc_secure(len); #elif defined(OPENSSL) || defined(AWSLC) /* Does this allocation implies secure memory use? */ tmp = OPENSSL_malloc(len); #else /* we have no secure memory allocation! Hence * we do not set CONFIG_CRYPTO_CPU_JITTERENTROPY_SECURE_MEMORY */ tmp = malloc(len); #endif /* LIBGCRYPT */ if(NULL != tmp) memset(tmp, 0, len); return tmp; } static inline void jent_zfree(void *ptr, unsigned int len) { #ifdef LIBGCRYPT memset(ptr, 0, len); gcry_free(ptr); #elif defined(AWSLC) /* AWS-LC stores the length of allocated memory internally and automatically wipes it in OPENSSL_free */ (void) len; OPENSSL_free(ptr); #elif defined(OPENSSL) OPENSSL_cleanse(ptr, len); OPENSSL_free(ptr); #else memset(ptr, 0, len); free(ptr); #endif /* LIBGCRYPT */ } static inline int jent_fips_enabled(void) { #ifdef LIBGCRYPT return fips_mode(); #elif defined(AWSLC) return FIPS_mode(); #elif defined(OPENSSL) #ifdef OPENSSL_FIPS return 1; #else return 0; #endif #else #define FIPS_MODE_SWITCH_FILE "/proc/sys/crypto/fips_enabled" char buf[2] = "0"; int fd = 0; if ((fd = open(FIPS_MODE_SWITCH_FILE, O_RDONLY)) >= 0) { while (read(fd, buf, sizeof(buf)) < 0 && errno == EINTR); close(fd); } if (buf[0] == '1') return 1; else return 0; #endif } static inline void jent_memset_secure(void *s, size_t n) { #if defined(AWSLC) OPENSSL_cleanse(s, n); #else memset(s, 0, n); __asm__ __volatile__("" : : "r" (s) : "memory"); #endif } static inline long jent_ncpu(void) { #if defined(_POSIX_SOURCE) || defined(__APPLE__) long ncpu = sysconf(_SC_NPROCESSORS_ONLN); if (ncpu == -1) return -errno; if (ncpu == 0) return -EFAULT; return ncpu; #else return 1; #endif } #ifdef __linux__ # if defined(_SC_LEVEL1_DCACHE_SIZE) && \ defined(_SC_LEVEL2_CACHE_SIZE) && \ defined(_SC_LEVEL3_CACHE_SIZE) static inline void jent_get_cachesize(long *l1, long *l2, long *l3) { *l1 = sysconf(_SC_LEVEL1_DCACHE_SIZE); *l2 = sysconf(_SC_LEVEL2_CACHE_SIZE); *l3 = sysconf(_SC_LEVEL3_CACHE_SIZE); } # else static inline void jent_get_cachesize(long *l1, long *l2, long *l3) { #define JENT_SYSFS_CACHE_DIR "/sys/devices/system/cpu/cpu0/cache" long val; unsigned int i; char buf[10], file[50]; int fd = 0; /* Iterate over all caches */ for (i = 0; i < 4; i++) { unsigned int shift = 0; char *ext; /* * Check the cache type - we are only interested in Unified * and Data caches. */ memset(buf, 0, sizeof(buf)); snprintf(file, sizeof(file), "%s/index%u/type", JENT_SYSFS_CACHE_DIR, i); fd = open(file, O_RDONLY); if (fd < 0) continue; while (read(fd, buf, sizeof(buf)) < 0 && errno == EINTR); close(fd); buf[sizeof(buf) - 1] = '\0'; if (strncmp(buf, "Data", 4) && strncmp(buf, "Unified", 7)) continue; /* Get size of cache */ memset(buf, 0, sizeof(buf)); snprintf(file, sizeof(file), "%s/index%u/size", JENT_SYSFS_CACHE_DIR, i); fd = open(file, O_RDONLY); if (fd < 0) continue; while (read(fd, buf, sizeof(buf)) < 0 && errno == EINTR); close(fd); buf[sizeof(buf) - 1] = '\0'; ext = strstr(buf, "K"); if (ext) { shift = 10; *ext = '\0'; } else { ext = strstr(buf, "M"); if (ext) { shift = 20; *ext = '\0'; } } val = strtol(buf, NULL, 10); if (val == LONG_MAX) continue; val <<= shift; if (!*l1) *l1 = val; else if (!*l2) *l2 = val; else { *l3 = val; break; } } #undef JENT_SYSFS_CACHE_DIR } # endif static inline uint32_t jent_cache_size_roundup(void) { static int checked = 0; static uint32_t cache_size = 0; if (!checked) { long l1 = 0, l2 = 0, l3 = 0; jent_get_cachesize(&l1, &l2, &l3); checked = 1; /* Cache size reported by system */ if (l1 > 0) cache_size += (uint32_t)l1; if (l2 > 0) cache_size += (uint32_t)l2; if (l3 > 0) cache_size += (uint32_t)l3; /* * Force the output_size to be of the form * (bounding_power_of_2 - 1). */ cache_size |= (cache_size >> 1); cache_size |= (cache_size >> 2); cache_size |= (cache_size >> 4); cache_size |= (cache_size >> 8); cache_size |= (cache_size >> 16); if (cache_size == 0) return 0; /* * Make the output_size the smallest power of 2 strictly * greater than cache_size. */ cache_size++; } return cache_size; } #else /* __linux__ */ static inline uint32_t jent_cache_size_roundup(void) { return 0; } #endif /* __linux__ */ static inline void jent_yield(void) { sched_yield(); } /* --- helpers needed in user space -- */ static inline uint64_t rol64(uint64_t x, int n) { return ( (x << (n&(64-1))) | (x >> ((64-n)&(64-1))) ); } #endif /* _JITTERENTROPY_BASE_USER_H */ jitterentropy-library-3.6.3/jitterentropy.h000066400000000000000000000510051500137124500212010ustar00rootroot00000000000000/* * Non-physical true random number generator based on timing jitter. * * Copyright Stephan Mueller , 2014 - 2025 * * License * ======= * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, and the entire permission notice in its entirety, * including the disclaimer of warranties. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote * products derived from this software without specific prior * written permission. * * ALTERNATIVELY, this product may be distributed under the terms of * the GNU General Public License, in which case the provisions of the GPL are * required INSTEAD OF the above restrictions. (This clause is * necessary due to a potential bad interaction between the GPL and * the restrictions contained in a BSD-style copyright.) * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH * DAMAGE. */ #ifndef _JITTERENTROPY_H #define _JITTERENTROPY_H #ifdef __cplusplus extern "C" { #endif /* * API / ABI incompatible changes, functional changes that require consumer to * be updated (as long as this number is zero, the API is not considered stable * and can change without a bump of the major version). */ #define JENT_MAJVERSION 3 /* * API compatible, ABI may change, functional enhancements only, consumer can be * left unchanged if enhancements are not considered. */ #define JENT_MINVERSION 6 /* * API / ABI compatible, no functional changes, no enhancements, bug fixes only. * Also, the entropy collection is not changed in any way that would necessitate * a re-assessment. */ #define JENT_PATCHLEVEL 3 #define JENT_VERSION (JENT_MAJVERSION * 1000000 + \ JENT_MINVERSION * 10000 + \ JENT_PATCHLEVEL * 100) /*************************************************************************** * Jitter RNG Configuration Section * * You may alter the following options ***************************************************************************/ /* * Enable timer-less timer support with JENT_CONF_ENABLE_INTERNAL_TIMER * * In case the hardware is identified to not provide a high-resolution time * stamp, this option enables a built-in high-resolution time stamp mechanism. * * The timer-less noise source is based on threads. This noise source requires * the linking with the POSIX threads library. I.e. the executing environment * must offer POSIX threads. If this option is disabled, no linking * with the POSIX threads library is needed. */ /* * Disable the loop shuffle operation * * The shuffle operation enlarges the timing of the conditioning function * by a variable length defined by the LSB of a time stamp. Some mathematicians * are concerned that this pseudo-random selection of the loop iteration count * may create some form of dependency between the different loop counts * and the associated time duration of the conditioning function. It * also complicates entropy assessment because it effectively combines a bunch * of shifted/scaled copies the same distribution and masks failures from the * health testing. * * By enabling this flag, the loop shuffle operation is disabled and * the entropy collection operates in a way that honor the concerns. * * By enabling this flag, the time of collecting entropy may be enlarged. */ #define JENT_CONF_DISABLE_LOOP_SHUFFLE /* * Shall the LAG predictor health test be enabled? */ #define JENT_HEALTH_LAG_PREDICTOR /* * Shall the jent_memaccess use a (statistically) random selection for the * memory to update? */ #define JENT_RANDOM_MEMACCESS /* * Mask specifying the number of bits of the raw entropy data of the time delta * value used for the APT. * * This value implies that for the APT, only the bits specified by * JENT_APT_MASK are taken. This was suggested in a draft IG D.K resolution 22 * provided by NIST, but further analysis * (https://www.untruth.org/~josh/sp80090b/CMUF%20EWG%20Draft%20IG%20D.K%20Comments%20D10.pdf) * suggests that this truncation / translation generally results in a health * test with both a higher false positive rate (because multiple raw symbols * map to the same symbol within the health test) and a lower statistical power * when the APT cutoff is selected based on the apparent truncated entropy * (i.e., truncation generally makes the test worse). NIST has since withdrawn * this draft and stated that they will not propose truncation prior to * health testing. * Because the general tendency of such truncation to make the health test * worse the default value is set such that no data is masked out and this * should only be changed if a hardware-specific analysis suggests that some * other mask setting is beneficial. * The mask is applied to a time stamp where the GCD is already divided out, and thus no * "non-moving" low-order bits are present. */ #define JENT_APT_MASK (UINT64_C(0xffffffffffffffff)) /* This parameter establishes the multiplicative factor that the desired * memory region size should be larger than the observed cache size; the * multiplicative factor is 2^JENT_CACHE_SHIFT_BITS. * Set this to 0 if the desired memory region should be at least as large as * the cache. If one wants most of the memory updates to result in a memory * update, then this value should be at least 1. * If the memory updates should dominantly result in a memory update, then * the value should be set to at least 3. * The actual size of the memory region is never larger than requested by * the passed in JENT_MAX_MEMSIZE_* flag (if provided) or JENT_MEMORY_SIZE * (if no JENT_MAX_MEMSIZE_* flag is provided). */ #ifndef JENT_CACHE_SHIFT_BITS #define JENT_CACHE_SHIFT_BITS 0 #endif /*************************************************************************** * Jitter RNG State Definition Section ***************************************************************************/ #if defined(_MSC_VER) #include "arch/jitterentropy-base-windows.h" #else #include "jitterentropy-base-user.h" #endif #define JENT_SHA3_256_SIZE_DIGEST_BITS 256 #define JENT_SHA3_256_SIZE_DIGEST (JENT_SHA3_256_SIZE_DIGEST_BITS >> 3) /* * The output 256 bits can receive more than 256 bits of min entropy, * of course, but the 256-bit output of SHA3-256(M) can only asymptotically * approach 256 bits of min entropy, not attain that bound. Random maps will * tend to have output collisions, which reduces the creditable output entropy * (that is what SP 800-90B Section 3.1.5.1.2 attempts to bound). * * The value "64" is justified in Appendix A.4 of the current 90C draft, * and aligns with NIST's in "epsilon" definition in this document, which is * that a string can be considered "full entropy" if you can bound the min * entropy in each bit of output to at least 1-epsilon, where epsilon is * required to be <= 2^(-32). */ #define ENTROPY_SAFETY_FACTOR 64 /** * Function pointer data structure to register an external thread handler * used for the timer-less mode of the Jitter RNG. * * The external caller provides these function pointers to handle the * management of the timer thread that is spawned by the Jitter RNG. * * @var jent_notime_init This function is intended to initialize the threading * support. All data that is required by the threading code must be * held in the data structure @param ctx. The Jitter RNG maintains the * data structure and uses it for every invocation of the following calls. * * @var jent_notime_fini This function shall terminate the threading support. * The function must dispose of all memory and resources used for the * threading operation. It must also dispose of the @param ctx memory. * * @var jent_notime_start This function is called when the Jitter RNG wants * to start a thread. Besides providing a pointer to the @param ctx * allocated during initialization time, the Jitter RNG provides a * pointer to the function the thread shall execute and the argument * the function shall be invoked with. These two parameters have the * same purpose as the trailing two parameters of pthread_create(3). * * @var jent_notime_stop This function is invoked by the Jitter RNG when the * thread should be stopped. Note, the Jitter RNG intends to start/stop * the thread frequently. * * An example implementation is found in the Jitter RNG itself with its * default thread handler of jent_notime_thread_builtin. * * If the caller wants to register its own thread handler, it must be done * with the API call jent_entropy_switch_notime_impl as the first * call to interact with the Jitter RNG, even before jent_entropy_init. * After jent_entropy_init is called, changing of the threading implementation * is not allowed. */ struct jent_notime_thread { int (*jent_notime_init)(void **ctx); void (*jent_notime_fini)(void *ctx); int (*jent_notime_start)(void *ctx, void *(*start_routine) (void *), void *arg); void (*jent_notime_stop)(void *ctx); }; /* The entropy pool */ struct rand_data { /* all data values that are vital to maintain the security * of the RNG are marked as SENSITIVE. A user must not * access that information while the RNG executes its loops to * calculate the next random value. */ void *hash_state; /* SENSITIVE hash state entropy pool */ uint64_t prev_time; /* SENSITIVE Previous time stamp */ #define DATA_SIZE_BITS (JENT_SHA3_256_SIZE_DIGEST_BITS) #ifndef JENT_HEALTH_LAG_PREDICTOR uint64_t last_delta; /* SENSITIVE stuck test */ uint64_t last_delta2; /* SENSITIVE stuck test */ #endif /* JENT_HEALTH_LAG_PREDICTOR */ unsigned int flags; /* Flags used to initialize */ unsigned int osr; /* Oversampling rate */ #ifdef JENT_RANDOM_MEMACCESS /* The step size should be larger than the cacheline size. */ # ifndef JENT_MEMORY_BITS # define JENT_MEMORY_BITS 17 # endif # ifndef JENT_MEMORY_SIZE # define JENT_MEMORY_SIZE (UINT32_C(1)<> JENT_FLAGS_TO_MEMSIZE_SHIFT) #define JENT_MAX_MEMSIZE_TO_FLAGS(val) (val << JENT_FLAGS_TO_MEMSIZE_SHIFT) #define JENT_MAX_MEMSIZE_32kB JENT_MAX_MEMSIZE_TO_FLAGS(UINT32_C( 1)) #define JENT_MAX_MEMSIZE_64kB JENT_MAX_MEMSIZE_TO_FLAGS(UINT32_C( 2)) #define JENT_MAX_MEMSIZE_128kB JENT_MAX_MEMSIZE_TO_FLAGS(UINT32_C( 3)) #define JENT_MAX_MEMSIZE_256kB JENT_MAX_MEMSIZE_TO_FLAGS(UINT32_C( 4)) #define JENT_MAX_MEMSIZE_512kB JENT_MAX_MEMSIZE_TO_FLAGS(UINT32_C( 5)) #define JENT_MAX_MEMSIZE_1MB JENT_MAX_MEMSIZE_TO_FLAGS(UINT32_C( 6)) #define JENT_MAX_MEMSIZE_2MB JENT_MAX_MEMSIZE_TO_FLAGS(UINT32_C( 7)) #define JENT_MAX_MEMSIZE_4MB JENT_MAX_MEMSIZE_TO_FLAGS(UINT32_C( 8)) #define JENT_MAX_MEMSIZE_8MB JENT_MAX_MEMSIZE_TO_FLAGS(UINT32_C( 9)) #define JENT_MAX_MEMSIZE_16MB JENT_MAX_MEMSIZE_TO_FLAGS(UINT32_C(10)) #define JENT_MAX_MEMSIZE_32MB JENT_MAX_MEMSIZE_TO_FLAGS(UINT32_C(11)) #define JENT_MAX_MEMSIZE_64MB JENT_MAX_MEMSIZE_TO_FLAGS(UINT32_C(12)) #define JENT_MAX_MEMSIZE_128MB JENT_MAX_MEMSIZE_TO_FLAGS(UINT32_C(13)) #define JENT_MAX_MEMSIZE_256MB JENT_MAX_MEMSIZE_TO_FLAGS(UINT32_C(14)) #define JENT_MAX_MEMSIZE_512MB JENT_MAX_MEMSIZE_TO_FLAGS(UINT32_C(15)) #define JENT_MAX_MEMSIZE_MAX JENT_MAX_MEMSIZE_512MB #define JENT_MAX_MEMSIZE_MASK JENT_MAX_MEMSIZE_MAX /* We start at 32kB -> offset is log2(32768) */ #define JENT_MAX_MEMSIZE_OFFSET 14 #ifdef JENT_CONF_DISABLE_LOOP_SHUFFLE # define JENT_MIN_OSR 3 #else # define JENT_MIN_OSR 1 #endif #ifdef JENT_PRIVATE_COMPILE # define JENT_PRIVATE_STATIC static #else /* JENT_PRIVATE_COMPILE */ #if defined(_MSC_VER) #define JENT_PRIVATE_STATIC __declspec(dllexport) #else #define JENT_PRIVATE_STATIC __attribute__((visibility("default"))) #endif #endif /* Number of low bits of the time value that we want to consider */ /* get raw entropy */ JENT_PRIVATE_STATIC ssize_t jent_read_entropy(struct rand_data *ec, char *data, size_t len); JENT_PRIVATE_STATIC ssize_t jent_read_entropy_safe(struct rand_data **ec, char *data, size_t len); /* initialize an instance of the entropy collector */ JENT_PRIVATE_STATIC struct rand_data *jent_entropy_collector_alloc(unsigned int osr, unsigned int flags); /* clearing of entropy collector */ JENT_PRIVATE_STATIC void jent_entropy_collector_free(struct rand_data *entropy_collector); /* initialization of entropy collector */ JENT_PRIVATE_STATIC int jent_entropy_init(void); JENT_PRIVATE_STATIC int jent_entropy_init_ex(unsigned int osr, unsigned int flags); /* * Set a callback to run on health failure in FIPS mode. * This function will take an action determined by the caller. */ typedef void (*jent_fips_failure_cb)(struct rand_data *ec, unsigned int health_failure); JENT_PRIVATE_STATIC int jent_set_fips_failure_callback(jent_fips_failure_cb cb); /* return version number of core library */ JENT_PRIVATE_STATIC unsigned int jent_version(void); /* Set a different thread handling logic for the notimer support */ JENT_PRIVATE_STATIC int jent_entropy_switch_notime_impl(struct jent_notime_thread *new_thread); /* -- END of Main interface functions -- */ /* -- BEGIN timer-less threading support functions to prevent code dupes -- */ #ifdef JENT_CONF_ENABLE_INTERNAL_TIMER struct jent_notime_ctx { pthread_attr_t notime_pthread_attr; /* pthreads library */ pthread_t notime_thread_id; /* pthreads thread ID */ }; JENT_PRIVATE_STATIC int jent_notime_init(void **ctx); JENT_PRIVATE_STATIC void jent_notime_fini(void *ctx); #else static inline int jent_notime_init(void **ctx) { (void)ctx; return 0; } static inline void jent_notime_fini(void *ctx) { (void)ctx; } #endif /* JENT_CONF_ENABLE_INTERNAL_TIMER */ /* -- END timer-less threading support functions to prevent code dupes -- */ /* -- BEGIN error codes for init function -- */ #define ENOTIME 1 /* Timer service not available */ #define ECOARSETIME 2 /* Timer too coarse for RNG */ #define ENOMONOTONIC 3 /* Timer is not monotonic increasing */ #define EMINVARIATION 4 /* Timer variations too small for RNG */ #define EVARVAR 5 /* Timer does not produce variations of variations (2nd derivation of time is zero) */ #define EMINVARVAR 6 /* Timer variations of variations is too small */ #define EPROGERR 7 /* Programming error */ #define ESTUCK 8 /* Too many stuck results during init. */ #define EHEALTH 9 /* Health test failed during initialization */ #define ERCT 10 /* RCT failed during initialization */ #define EHASH 11 /* Hash self test failed */ #define EMEM 12 /* Can't allocate memory for initialization */ #define EGCD 13 /* GCD self-test failed */ /* -- END error codes for init function -- */ /* -- BEGIN error masks for health tests -- */ #define JENT_RCT_FAILURE 1 /* Failure in RCT health test. */ #define JENT_APT_FAILURE 2 /* Failure in APT health test. */ #define JENT_LAG_FAILURE 4 /* Failure in Lag predictor health test. */ #define JENT_PERMANENT_FAILURE_SHIFT 16 #define JENT_PERMANENT_FAILURE(x) (x << JENT_PERMANENT_FAILURE_SHIFT) #define JENT_RCT_FAILURE_PERMANENT JENT_PERMANENT_FAILURE(JENT_RCT_FAILURE) #define JENT_APT_FAILURE_PERMANENT JENT_PERMANENT_FAILURE(JENT_APT_FAILURE) #define JENT_LAG_FAILURE_PERMANENT JENT_PERMANENT_FAILURE(JENT_LAG_FAILURE) /* -- END error masks for health tests -- */ /* -- BEGIN statistical test functions only complied with CONFIG_CRYPTO_CPU_JITTERENTROPY_STAT -- */ #ifdef CONFIG_CRYPTO_CPU_JITTERENTROPY_STAT JENT_PRIVATE_STATIC uint64_t jent_lfsr_var_stat(struct rand_data *ec, unsigned int min); #endif /* CONFIG_CRYPTO_CPU_JITTERENTROPY_STAT */ /* -- END of statistical test function -- */ #ifdef __cplusplus } #endif #endif /* _JITTERENTROPY_H */ jitterentropy-library-3.6.3/src/000077500000000000000000000000001500137124500166745ustar00rootroot00000000000000jitterentropy-library-3.6.3/src/jitterentropy-base.c000066400000000000000000000546701500137124500227060ustar00rootroot00000000000000/* * Non-physical true random number generator based on timing jitter. * * Copyright Stephan Mueller , 2014 - 2025 * * Design * ====== * * See documentation in doc/ folder. * * Interface * ========= * * See documentation in jitterentropy(3) man page. * * License: see LICENSE file in root directory * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH * DAMAGE. */ #include "jitterentropy-base.h" #include "jitterentropy-gcd.h" #include "jitterentropy-health.h" #include "jitterentropy-internal.h" #include "jitterentropy-noise.h" #include "jitterentropy-timer.h" #include "jitterentropy-sha3.h" /*************************************************************************** * Jitter RNG Static Definitions * * None of the following should be altered ***************************************************************************/ #ifdef __OPTIMIZE__ #error "The CPU Jitter random number generator must not be compiled with optimizations. See documentation. Use the compiler switch -O0 for compiling jitterentropy.c." #endif /* * JENT_POWERUP_TESTLOOPCOUNT needs some loops to identify edge * systems. 100 is definitely too little. * * SP800-90B requires at least 1024 initial test cycles. */ #define JENT_POWERUP_TESTLOOPCOUNT 1024 /* * ensure_osr_is_at_least_minimal ensures that the over sampling rate is, at * minimum, JENT_MIN_OSR. * * @return returns the argument current_osr if equal to or larger than * JENT_MIN_OSR otherwise, returns JENT_MIN_OSR. */ static unsigned int ensure_osr_is_at_least_minimal(unsigned int current_osr) { if (current_osr < JENT_MIN_OSR) return (unsigned int) JENT_MIN_OSR; else return current_osr; } /** * jent_version() - Return machine-usable version number of jent library * * The function returns a version number that is monotonic increasing * for newer versions. The version numbers are multiples of 100. For example, * version 1.2.3 is converted to 1020300 -- the last two digits are reserved * for future use. * * The result of this function can be used in comparing the version number * in a calling program if version-specific calls need to be make. * * @return Version number of jitterentropy library */ JENT_PRIVATE_STATIC unsigned int jent_version(void) { return JENT_VERSION; } /*************************************************************************** * Helper ***************************************************************************/ /* Calculate log2 of given value assuming that the value is a power of 2 */ static inline unsigned int jent_log2_simple(unsigned int val) { unsigned int idx = 0; while (val >>= 1) idx++; return idx; } /* Increase the memory size by one step */ static inline unsigned int jent_update_memsize(unsigned int flags) { unsigned int global_max = JENT_FLAGS_TO_MAX_MEMSIZE( JENT_MAX_MEMSIZE_MAX); unsigned int max; max = JENT_FLAGS_TO_MAX_MEMSIZE(flags); if (!max) { /* * The safe starting value is the amount of memory we allocated * last round. */ max = jent_log2_simple(JENT_MEMORY_SIZE); /* Adjust offset */ max = (max > JENT_MAX_MEMSIZE_OFFSET) ? max - JENT_MAX_MEMSIZE_OFFSET : 0; } else { max++; } max = (max > global_max) ? global_max : max; /* Clear out the max size */ flags &= ~JENT_MAX_MEMSIZE_MASK; /* Set the freshly calculated max size */ flags |= JENT_MAX_MEMSIZE_TO_FLAGS(max); return flags; } /*************************************************************************** * Random Number Generation ***************************************************************************/ /** * Entry function: Obtain entropy for the caller. * * This function invokes the entropy gathering logic as often to generate * as many bytes as requested by the caller. The entropy gathering logic * creates 64 bit per invocation. * * This function truncates the last 64 bit entropy value output to the exact * size specified by the caller. * * @ec [in] Reference to entropy collector * @data [out] pointer to buffer for storing random data -- buffer must * already exist * @len [in] size of the buffer, specifying also the requested number of random * in bytes * * @return number of bytes returned when request is fulfilled or an error * * The following error codes can occur: * -1 entropy_collector is NULL * -2 RCT failed * -3 APT failed * -4 The timer cannot be initialized * -5 LAG failure * -6 RCT permanent failure * -7 APT permanent failure * -8 LAG permanent failure */ JENT_PRIVATE_STATIC ssize_t jent_read_entropy(struct rand_data *ec, char *data, size_t len) { char *p = data; size_t orig_len = len; int ret = 0; if (NULL == ec) return -1; if (jent_notime_settick(ec)) return -4; while (len > 0) { size_t tocopy; unsigned int health_test_result; jent_random_data(ec); if ((health_test_result = jent_health_failure(ec))) { if (health_test_result & JENT_RCT_FAILURE_PERMANENT) ret = -6; else if (health_test_result & JENT_APT_FAILURE_PERMANENT) ret = -7; else if (health_test_result & JENT_LAG_FAILURE_PERMANENT) ret = -8; else if (health_test_result & JENT_RCT_FAILURE) ret = -2; else if (health_test_result & JENT_APT_FAILURE) ret = -3; else ret = -5; goto err; } if ((DATA_SIZE_BITS / 8) < len) tocopy = (DATA_SIZE_BITS / 8); else tocopy = len; jent_read_random_block(ec, p, tocopy); len -= tocopy; p += tocopy; } /* * Enhanced backtracking support: At this point, the hash state * contains the digest of the previous Jitter RNG collection round * which is inserted there by jent_read_random_block with the SHA * update operation. At the current code location we completed * one request for a caller and we do not know how long it will * take until a new request is sent to us. To guarantee enhanced * backtracking resistance at this point (i.e. ensure that an attacker * cannot obtain information about prior random numbers we generated), * but still stirring the hash state with old data the Jitter RNG * obtains a new message digest from its state and re-inserts it. * After this operation, the Jitter RNG state is still stirred with * the old data, but an attacker who gets access to the memory after * this point cannot deduce the random numbers produced by the * Jitter RNG prior to this point. */ /* * If we use secured memory, where backtracking support may not be * needed because the state is protected in a different method, * it is permissible to drop this support. But strongly weigh the * pros and cons considering that the SHA3 operation is not that * expensive. */ #ifndef CONFIG_CRYPTO_CPU_JITTERENTROPY_SECURE_MEMORY jent_read_random_block(ec, NULL, 0); #endif err: jent_notime_unsettick(ec); return ret ? ret : (ssize_t)orig_len; } static struct rand_data *_jent_entropy_collector_alloc(unsigned int osr, unsigned int flags); /** * Entry function: Obtain entropy for the caller. * * This is a service function to jent_read_entropy() with the difference * that it automatically re-allocates the entropy collector if a health * test failure is observed. Before reallocation, a new power-on health test * is performed. The allocation of the new entropy collector automatically * increases the OSR by one. This is done based on the idea that a health * test failure indicates that the assumed entropy rate is too high. * * Note the function returns with an health test error if the OSR is * getting too large. If an error is returned by this function, the Jitter RNG * is not safe to be used on the current system. * * @ec [in] Reference to entropy collector - this is a double pointer as * The entropy collector may be freed and reallocated. * @data [out] pointer to buffer for storing random data -- buffer must * already exist * @len [in] size of the buffer, specifying also the requested number of random * in bytes * * @return see jent_read_entropy() */ JENT_PRIVATE_STATIC ssize_t jent_read_entropy_safe(struct rand_data **ec, char *data, size_t len) { char *p = data; size_t orig_len = len; ssize_t ret = 0; if (!ec) return -1; while (len > 0) { unsigned int osr, flags, max_mem_set, apt_observations = 0, lag_prediction_success_run, lag_prediction_success_count; uint64_t current_delta; ret = jent_read_entropy(*ec, p, len); switch (ret) { case -1: case -4: /* Permanent errors are returned immediately */ case -6: case -7: case -8: return ret; case -2: case -3: case -5: apt_observations = (*ec)->apt_observations; current_delta = (*ec)->apt_base; lag_prediction_success_run = (*ec)->lag_prediction_success_run; lag_prediction_success_count = (*ec)->lag_prediction_success_count; osr = (*ec)->osr + 1; flags = (*ec)->flags; max_mem_set = (*ec)->max_mem_set; /* generic arbitrary cutoff */ if (osr > 20) return ret; /* * If the caller did not set any specific maximum value * let the Jitter RNG increase the maximum memory by * one step. */ if (!max_mem_set) flags = jent_update_memsize(flags); /* * re-allocate entropy collector with higher OSR and * memory size */ jent_entropy_collector_free(*ec); *ec = NULL; /* Perform new health test with updated OSR */ while (jent_entropy_init_ex(osr, flags)) { osr++; if (osr > 20) return -1; } *ec = _jent_entropy_collector_alloc(osr, flags); if (!*ec) return -1; /* Remember whether caller configured memory size */ (*ec)->max_mem_set = !!max_mem_set; /* * Set the health test state in case of intermittent * failures. */ if (apt_observations) { /* * APT re-initialization to intermittent error */ jent_apt_reinit(*ec, current_delta, 0, apt_observations); /* * RCT re-initialization to intermittent error */ (*ec)->rct_count = (int)(JENT_HEALTH_RCT_INTERMITTENT_CUTOFF(osr)); /* LAG re-initialization */ (*ec)->lag_prediction_success_run = lag_prediction_success_run; (*ec)->lag_prediction_success_count = lag_prediction_success_count; } /* * We are not returning the intermittent or permanent * errors here. If a caller wants them, he should * register a callback with * jent_set_fips_failure_callback. */ break; default: len -= (size_t)ret; p += (size_t)ret; } } return (ssize_t)orig_len; } /*************************************************************************** * Initialization logic ***************************************************************************/ /* * Obtain memory size to allocate for memory access variations. * * The maximum variations we can get from the memory access is when we allocate * a bit more memory than we have as data cache. But allocating as much * memory as we have as data cache might strain the resources on the system * more than necessary. * * On a lot of systems it is not necessary to need so much memory as the * variations coming from the general Jitter RNG execution commonly provide * large amount of variations. * * Thus, the default is: * * min(JENT_MEMORY_SIZE, data cache size) * * In case the data cache size cannot be obtained, use JENT_MEMORY_SIZE. * * If the caller provides a maximum memory size, use * min(provided max memory, data cache size). */ static inline uint32_t jent_memsize(unsigned int flags) { uint32_t cache_memsize=0, max_memsize=0, memsize=0; max_memsize = JENT_FLAGS_TO_MAX_MEMSIZE(flags); if (max_memsize == 0) { max_memsize = JENT_MEMORY_SIZE; } else { max_memsize = UINT32_C(1) << (max_memsize + JENT_MAX_MEMSIZE_OFFSET); } /* Allocate memory for adding variations based on memory access */ cache_memsize = jent_cache_size_roundup(); memsize = cache_memsize << JENT_CACHE_SHIFT_BITS; /* If this value is left-shifted too much, it may be cleared. */ /* If so, set the maximum possible power of two. */ if (cache_memsize > memsize) memsize = 0x80000000; /* Limit the memory as defined by caller */ memsize = (memsize > max_memsize) ? max_memsize : memsize; /* Set a value if none was found */ if (!memsize) memsize = JENT_MEMORY_SIZE; return memsize; } static int jent_selftest_run = 0; static struct rand_data *jent_entropy_collector_alloc_internal(unsigned int osr, unsigned int flags) { struct rand_data *entropy_collector; uint32_t memsize = 0; /* * Requesting disabling and forcing of internal timer * makes no sense. */ if ((flags & JENT_DISABLE_INTERNAL_TIMER) && (flags & JENT_FORCE_INTERNAL_TIMER)) return NULL; /* * Ensure over sampling rate is not too low. */ osr = ensure_osr_is_at_least_minimal(osr); /* Force the self test to be run */ if (!jent_selftest_run && jent_entropy_init_ex(osr, flags)) return NULL; /* * If the initial test code concludes to force the internal timer * and the user requests it not to be used, do not allocate * the Jitter RNG instance. */ if (jent_notime_forced() && (flags & JENT_DISABLE_INTERNAL_TIMER)) return NULL; entropy_collector = jent_zalloc(sizeof(struct rand_data)); if (NULL == entropy_collector) return NULL; if (!(flags & JENT_DISABLE_MEMORY_ACCESS)) { memsize = jent_memsize(flags); entropy_collector->mem = (unsigned char *)jent_zalloc(memsize); #ifdef JENT_RANDOM_MEMACCESS /* * Transform the size into a mask - it is assumed that size is * a power of 2. */ entropy_collector->memmask = memsize - 1; #else /* JENT_RANDOM_MEMACCESS */ entropy_collector->memblocksize = memsize / JENT_MEMORY_BLOCKS; entropy_collector->memblocks = JENT_MEMORY_BLOCKS; /* sanity check */ if (entropy_collector->memblocksize * entropy_collector->memblocks != memsize) goto err; #endif /* JENT_RANDOM_MEMACCESS */ if (entropy_collector->mem == NULL) goto err; entropy_collector->memaccessloops = JENT_MEMORY_ACCESSLOOPS; } if (jent_sha3_alloc(&entropy_collector->hash_state)) goto err; /* Initialize the hash state */ jent_sha3_256_init(entropy_collector->hash_state); /* Set the oversampling rate */ entropy_collector->osr = osr; entropy_collector->flags = flags; if ((flags & JENT_FORCE_FIPS) || jent_fips_enabled()) entropy_collector->fips_enabled = 1; /* Initialize the APT */ jent_apt_init(entropy_collector, osr); /* Initialize the Lag Predictor Test */ jent_lag_init(entropy_collector, osr); /* Was jent_entropy_init run (establishing the common GCD)? */ if (jent_gcd_get(&entropy_collector->jent_common_timer_gcd)) { /* * It was not. This should probably be an error, but this * behavior breaks the test code. Set the gcd to a value that * won't hurt anything. */ entropy_collector->jent_common_timer_gcd = 1; } /* * Use timer-less noise source - note, OSR must be set in * entropy_collector! */ if (!(flags & JENT_DISABLE_INTERNAL_TIMER)) { if (jent_notime_enable(entropy_collector, flags)) goto err; } return entropy_collector; err: if (entropy_collector->mem != NULL) jent_zfree(entropy_collector->mem, memsize); if (entropy_collector->hash_state != NULL) jent_sha3_dealloc(entropy_collector->hash_state); jent_zfree(entropy_collector, sizeof(struct rand_data)); return NULL; } static struct rand_data *_jent_entropy_collector_alloc(unsigned int osr, unsigned int flags) { struct rand_data *ec = jent_entropy_collector_alloc_internal(osr, flags); if (!ec) return ec; /* fill the data pad with non-zero values */ if (jent_notime_settick(ec)) { jent_entropy_collector_free(ec); return NULL; } jent_random_data(ec); jent_notime_unsettick(ec); return ec; } JENT_PRIVATE_STATIC struct rand_data *jent_entropy_collector_alloc(unsigned int osr, unsigned int flags) { struct rand_data *ec = _jent_entropy_collector_alloc(osr, flags); /* Remember that the caller provided a maximum size flag */ if (ec) ec->max_mem_set = !!JENT_FLAGS_TO_MAX_MEMSIZE(flags); return ec; } JENT_PRIVATE_STATIC void jent_entropy_collector_free(struct rand_data *entropy_collector) { if (entropy_collector != NULL) { jent_sha3_dealloc(entropy_collector->hash_state); jent_notime_disable(entropy_collector); if (entropy_collector->mem != NULL) { jent_zfree(entropy_collector->mem, jent_memsize(entropy_collector->flags)); entropy_collector->mem = NULL; } jent_zfree(entropy_collector, sizeof(struct rand_data)); } } int jent_time_entropy_init(unsigned int osr, unsigned int flags) { struct rand_data *ec; uint64_t *delta_history; int i, time_backwards = 0, count_stuck = 0, ret = 0; unsigned int health_test_result; /* * Ensure over sampling rate is not too low. */ osr = ensure_osr_is_at_least_minimal(osr); delta_history = jent_gcd_init(JENT_POWERUP_TESTLOOPCOUNT); if (!delta_history) return EMEM; if (flags & JENT_FORCE_INTERNAL_TIMER) jent_notime_force(); else flags |= JENT_DISABLE_INTERNAL_TIMER; /* * If the start-up health tests (including the APT and RCT) are not * run, then the entropy source is not 90B compliant. We could test if * fips_enabled should be set using the jent_fips_enabled() function, * but this can be overridden using the JENT_FORCE_FIPS flag, which * isn't passed in yet. It is better to run the tests on the small * amount of data that we have, which should not fail unless things * are really bad. */ flags |= JENT_FORCE_FIPS; ec = jent_entropy_collector_alloc_internal(osr, flags); if (!ec) { ret = EMEM; goto out; } if (jent_notime_settick(ec)) { ret = EMEM; goto out; } /* To initialize the prior time. */ jent_measure_jitter(ec, 0, NULL); /* We could perform statistical tests here, but the problem is * that we only have a few loop counts to do testing. These * loop counts may show some slight skew leading to false positives. */ /* * We could add a check for system capabilities such as clock_getres or * check for CONFIG_X86_TSC, but it does not make much sense as the * following sanity checks verify that we have a high-resolution * timer. */ #define CLEARCACHE 100 for (i = -CLEARCACHE; i < JENT_POWERUP_TESTLOOPCOUNT; i++) { uint64_t start_time = 0, end_time = 0, delta = 0; unsigned int stuck; /* Invoke core entropy collection logic */ stuck = jent_measure_jitter(ec, 0, &delta); end_time = ec->prev_time; start_time = ec->prev_time - delta; /* test whether timer works */ if (!start_time || !end_time) { ret = ENOTIME; goto out; } /* * test whether timer is fine grained enough to provide * delta even when called shortly after each other -- this * implies that we also have a high resolution timer */ if (!delta || (end_time == start_time)) { ret = ECOARSETIME; goto out; } /* * up to here we did not modify any variable that will be * evaluated later, but we already performed some work. Thus we * already have had an impact on the caches, branch prediction, * etc. with the goal to clear it to get the worst case * measurements. */ if (i < 0) continue; if (stuck) count_stuck++; /* test whether we have an increasing timer */ if (!(end_time > start_time)) time_backwards++; /* Watch for common adjacent GCD values */ jent_gcd_add_value(delta_history, delta, i); } /* * we allow up to three times the time running backwards. * CLOCK_REALTIME is affected by adjtime and NTP operations. Thus, * if such an operation just happens to interfere with our test, it * should not fail. The value of 3 should cover the NTP case being * performed during our test run. */ if (time_backwards > 3) { ret = ENOMONOTONIC; goto out; } /* First, did we encounter a health test failure? */ if ((health_test_result = jent_health_failure(ec))) { ret = (health_test_result & JENT_RCT_FAILURE) ? ERCT : EHEALTH; goto out; } ret = jent_gcd_analyze(delta_history, JENT_POWERUP_TESTLOOPCOUNT, osr); if (ret) goto out; /* * If we have more than 90% stuck results, then this Jitter RNG is * likely to not work well. */ if (JENT_STUCK_INIT_THRES(JENT_POWERUP_TESTLOOPCOUNT) < count_stuck) ret = ESTUCK; out: jent_gcd_fini(delta_history, JENT_POWERUP_TESTLOOPCOUNT); if ((flags & JENT_FORCE_INTERNAL_TIMER) && ec) jent_notime_unsettick(ec); jent_entropy_collector_free(ec); return ret; } static inline int jent_entropy_init_common_pre(void) { int ret; jent_notime_block_switch(); jent_health_cb_block_switch(); if (jent_sha3_tester()) return EHASH; ret = jent_gcd_selftest(); jent_selftest_run = 1; return ret; } static inline int jent_entropy_init_common_post(int ret) { /* Unmark the execution of the self tests if they failed. */ if (ret) jent_selftest_run = 0; return ret; } JENT_PRIVATE_STATIC int jent_entropy_init(void) { int ret = jent_entropy_init_common_pre(); if (ret) return ret; ret = jent_time_entropy_init(0, JENT_DISABLE_INTERNAL_TIMER); #ifdef JENT_CONF_ENABLE_INTERNAL_TIMER if (ret) ret = jent_time_entropy_init(0, JENT_FORCE_INTERNAL_TIMER); #endif /* JENT_CONF_ENABLE_INTERNAL_TIMER */ return jent_entropy_init_common_post(ret); } JENT_PRIVATE_STATIC int jent_entropy_init_ex(unsigned int osr, unsigned int flags) { int ret = jent_entropy_init_common_pre(); if (ret) return ret; ret = ENOTIME; /* Test without internal timer unless caller does not want it */ if (!(flags & JENT_FORCE_INTERNAL_TIMER)) ret = jent_time_entropy_init(osr, flags | JENT_DISABLE_INTERNAL_TIMER); #ifdef JENT_CONF_ENABLE_INTERNAL_TIMER /* Test with internal timer unless caller does not want it */ if (ret && !(flags & JENT_DISABLE_INTERNAL_TIMER)) ret = jent_time_entropy_init(osr, flags | JENT_FORCE_INTERNAL_TIMER); #endif /* JENT_CONF_ENABLE_INTERNAL_TIMER */ return jent_entropy_init_common_post(ret); } JENT_PRIVATE_STATIC int jent_entropy_switch_notime_impl(struct jent_notime_thread *new_thread) { return jent_notime_switch(new_thread); } JENT_PRIVATE_STATIC int jent_set_fips_failure_callback(jent_fips_failure_cb cb) { return jent_set_fips_failure_callback_internal(cb); } jitterentropy-library-3.6.3/src/jitterentropy-base.h000066400000000000000000000021261500137124500227000ustar00rootroot00000000000000/* * Copyright (C) 2021 - 2025, Stephan Mueller * * License: see LICENSE file in root directory * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH * DAMAGE. */ #ifndef JITTERENTROPY_BASE_H #define JITTERENTROPY_BASE_H #ifdef __cplusplus extern "C" { #endif int jent_time_entropy_init(unsigned int osr, unsigned int flags); #ifdef __cplusplus } #endif #endif /* JITTERENTROPY_BASE_H */ jitterentropy-library-3.6.3/src/jitterentropy-gcd.c000066400000000000000000000111501500137124500225130ustar00rootroot00000000000000/* Jitter RNG: GCD health test * * Copyright (C) 2021 - 2025, Joshua E. Hill * Copyright (C) 2021 - 2025, Stephan Mueller * * License: see LICENSE file in root directory * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH * DAMAGE. */ #include "jitterentropy-gcd.h" #include "jitterentropy-internal.h" /* The common divisor for all timestamp deltas */ static uint64_t jent_common_timer_gcd = 0; static inline int jent_gcd_tested(void) { return (jent_common_timer_gcd != 0); } /* A straight forward implementation of the Euclidean algorithm for GCD. */ static inline uint64_t jent_gcd64(uint64_t a, uint64_t b) { /* Make a greater a than or equal b. */ if (a < b) { uint64_t c = a; a = b; b = c; } /* Now perform the standard inner-loop for this algorithm.*/ while (b != 0) { uint64_t r; r = a % b; a = b; b = r; } return a; } static int jent_gcd_analyze_internal(uint64_t *delta_history, size_t nelem, uint64_t *running_gcd_out, uint64_t *delta_sum_out) { uint64_t running_gcd, delta_sum = 0; size_t i; if (!delta_history) return -EAGAIN; running_gcd = delta_history[0]; /* Now perform the analysis on the accumulated delta data. */ for (i = 1; i < nelem; i++) { /* * ensure that we have a varying delta timer which is necessary * for the calculation of entropy -- perform this check * only after the first loop is executed as we need to prime * the old_data value */ if (delta_history[i] >= delta_history[i - 1]) delta_sum += delta_history[i] - delta_history[i - 1]; else delta_sum += delta_history[i - 1] - delta_history[i]; /* * This calculates the gcd of all the delta values. that is * gcd(delta_1, delta_2, ..., delta_nelem) * Some timers increment by a fixed (non-1) amount each step. * This code checks for such increments, and allows the library * to output the number of such changes have occurred. */ running_gcd = jent_gcd64(delta_history[i], running_gcd); } *running_gcd_out = running_gcd; *delta_sum_out = delta_sum; return 0; } int jent_gcd_analyze(uint64_t *delta_history, size_t nelem, size_t osr) { uint64_t running_gcd, delta_sum; int ret = jent_gcd_analyze_internal(delta_history, nelem, &running_gcd, &delta_sum); if (ret == -EAGAIN) return 0; /* * We assume 1/osr bits of entropy per sample. On average, variations * of deltas must be larger than 1 over osr cases; we do not capture * fractions. Hence delta_sum < (nelem / osr) means we cannot satisfy the * 1/osr bits of entropy per sample assumption. */ if ((delta_sum * osr) < nelem) { ret = EMINVARVAR; goto out; } /* Set a sensible maximum value. */ if (running_gcd >= UINT32_MAX / 2) { ret = ECOARSETIME; goto out; } /* Adjust all deltas by the observed (small) common factor. */ if (!jent_gcd_tested()) jent_common_timer_gcd = running_gcd; out: return ret; } uint64_t *jent_gcd_init(size_t nelem) { uint64_t *delta_history; delta_history = jent_zalloc(nelem * sizeof(uint64_t)); if (!delta_history) return NULL; return delta_history; } void jent_gcd_fini(uint64_t *delta_history, size_t nelem) { if (delta_history) jent_zfree(delta_history, (unsigned int)(nelem * sizeof(uint64_t))); } int jent_gcd_get(uint64_t *value) { if (!jent_gcd_tested()) return 1; *value = jent_common_timer_gcd; return 0; } int jent_gcd_selftest(void) { #define JENT_GCD_SELFTEST_ELEM 10 #define JENT_GCD_SELFTEST_EXP 3ULL uint64_t *gcd = jent_gcd_init(JENT_GCD_SELFTEST_ELEM); uint64_t running_gcd, delta_sum; unsigned int i; int ret = EGCD; if (!gcd) return EMEM; for (i = 0; i < JENT_GCD_SELFTEST_ELEM; i++) jent_gcd_add_value(gcd, i * JENT_GCD_SELFTEST_EXP, i); if (jent_gcd_analyze_internal(gcd, JENT_GCD_SELFTEST_ELEM, &running_gcd, &delta_sum)) goto out; if (running_gcd != JENT_GCD_SELFTEST_EXP) goto out; ret = 0; out: jent_gcd_fini(gcd, JENT_GCD_SELFTEST_ELEM); return ret; } jitterentropy-library-3.6.3/src/jitterentropy-gcd.h000066400000000000000000000026441500137124500225300ustar00rootroot00000000000000/* * Copyright (C) 2021 - 2025, Stephan Mueller * * License: see LICENSE file in root directory * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH * DAMAGE. */ #ifndef JITTERENTROPY_GCD_H #define JITTERENTROPY_GCD_H #include "jitterentropy-internal.h" #ifdef __cplusplus extern "C" { #endif int jent_gcd_analyze(uint64_t *delta_history, size_t nelem, size_t osr); uint64_t *jent_gcd_init(size_t nelem); void jent_gcd_fini(uint64_t *delta_history, size_t nelem); int jent_gcd_get(uint64_t *value); int jent_gcd_selftest(void); /* Watch for common adjacent GCD values */ #define jent_gcd_add_value(delta_history, delta, idx) \ delta_history[idx] = delta; #ifdef __cplusplus } #endif #endif /* JITTERENTROPY_GCD_H */ jitterentropy-library-3.6.3/src/jitterentropy-health.c000066400000000000000000000361461500137124500232370ustar00rootroot00000000000000/* Jitter RNG: Health Tests * * Copyright (C) 2021 - 2025, Joshua E. Hill * Copyright (C) 2021 - 2025, Stephan Mueller * * License: see LICENSE file in root directory * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH * DAMAGE. */ #include "jitterentropy-health.h" static jent_fips_failure_cb fips_cb = NULL; static int jent_health_cb_switch_blocked = 0; void jent_health_cb_block_switch(void) { jent_health_cb_switch_blocked = 1; } int jent_set_fips_failure_callback_internal(jent_fips_failure_cb cb) { if (jent_health_cb_switch_blocked) return -EAGAIN; fips_cb = cb; return 0; } /*************************************************************************** * Lag Predictor Test * * This test is a vendor-defined conditional test that is designed to detect * a known failure mode where the result becomes mostly deterministic * Note that (lag_observations & JENT_LAG_MASK) is the index where the next * value provided will be stored. ***************************************************************************/ #ifdef JENT_HEALTH_LAG_PREDICTOR /* * These cutoffs are configured using an entropy estimate of 1/osr under an * alpha=2^(-22) for a window size of 131072. The other health tests use * alpha=2^-30, but operate on much smaller window sizes. This larger selection * of alpha makes the behavior per-lag-window similar to the APT test. * * The global cutoffs are calculated using the * InverseBinomialCDF(n=(JENT_LAG_WINDOW_SIZE-JENT_LAG_HISTORY_SIZE), p=2^(-1/osr); 1-alpha) * The local cutoffs are somewhat more complicated. For background, see Feller's * _Introduction to Probability Theory and It's Applications_ Vol. 1, * Chapter 13, section 7 (in particular see equation 7.11, where x is a root * of the denominator of equation 7.6). * * We'll proceed using the notation of SP 800-90B Section 6.3.8 (which is * developed in Kelsey-McKay-Turan paper "Predictive Models for Min-entropy * Estimation".) * * Here, we set p=2^(-1/osr), seeking a run of successful guesses (r) with * probability of less than (1-alpha). That is, it is very very likely * (probability 1-alpha) that there is _no_ run of length r in a block of size * JENT_LAG_WINDOW_SIZE-JENT_LAG_HISTORY_SIZE. * * We have to iteratively look for an appropriate value for the cutoff r. */ static const unsigned int jent_lag_global_cutoff_lookup[20] = { 66443, 93504, 104761, 110875, 114707, 117330, 119237, 120686, 121823, 122739, 123493, 124124, 124660, 125120, 125520, 125871, 126181, 126457, 126704, 126926 }; static const unsigned int jent_lag_local_cutoff_lookup[20] = { 38, 75, 111, 146, 181, 215, 250, 284, 318, 351, 385, 419, 452, 485, 518, 551, 584, 617, 650, 683 }; void jent_lag_init(struct rand_data *ec, unsigned int osr) { /* * Establish the lag global and local cutoffs based on the presumed * entropy rate of 1/osr. */ /* TODO: add permanent health failure */ if (osr > ARRAY_SIZE(jent_lag_global_cutoff_lookup)) { ec->lag_global_cutoff = jent_lag_global_cutoff_lookup[ ARRAY_SIZE(jent_lag_global_cutoff_lookup) - 1]; } else { ec->lag_global_cutoff = jent_lag_global_cutoff_lookup[osr - 1]; } if (osr > ARRAY_SIZE(jent_lag_local_cutoff_lookup)) { ec->lag_local_cutoff = jent_lag_local_cutoff_lookup[ ARRAY_SIZE(jent_lag_local_cutoff_lookup) - 1]; } else { ec->lag_local_cutoff = jent_lag_local_cutoff_lookup[osr - 1]; } } /** * Reset the lag counters * * @ec [in] Reference to entropy collector */ static void jent_lag_reset(struct rand_data *ec) { unsigned int i; /* Reset Lag counters */ ec->lag_prediction_success_count = 0; ec->lag_prediction_success_run = 0; ec->lag_best_predictor = 0; /* The first guess is basically arbitrary. */ ec->lag_observations = 0; for (i = 0; i < JENT_LAG_HISTORY_SIZE; i++) { ec->lag_scoreboard[i] = 0; ec->lag_delta_history[i] = 0; } } /* * A macro for accessing the history. Index 0 is the last observed symbol * index 1 is the symbol observed two inputs ago, etc. */ #define JENT_LAG_HISTORY(EC,LOC) \ ((EC)->lag_delta_history[((EC)->lag_observations - (LOC) - 1) & \ JENT_LAG_MASK]) /** * Insert a new entropy event into the lag predictor test * * @ec [in] Reference to entropy collector * @current_delta [in] Current time delta */ static void jent_lag_insert(struct rand_data *ec, uint64_t current_delta) { uint64_t prediction; unsigned int i; /* Initialize the delta_history */ if (ec->lag_observations < JENT_LAG_HISTORY_SIZE) { ec->lag_delta_history[ec->lag_observations] = current_delta; ec->lag_observations++; return; } /* * The history is initialized. First make a guess and examine the * results. */ prediction = JENT_LAG_HISTORY(ec, ec->lag_best_predictor); if (prediction == current_delta) { /* The prediction was correct. */ ec->lag_prediction_success_count++; ec->lag_prediction_success_run++; /* TODO: add permanent health failure */ if ((ec->lag_prediction_success_run >= ec->lag_local_cutoff) || (ec->lag_prediction_success_count >= ec->lag_global_cutoff)) ec->health_failure |= JENT_LAG_FAILURE; } else { /* The prediction wasn't correct. End any run of successes.*/ ec->lag_prediction_success_run = 0; } /* Now update the predictors using the current data. */ for (i = 0; i < JENT_LAG_HISTORY_SIZE; i++) { if (JENT_LAG_HISTORY(ec, i) == current_delta) { /* * The ith predictor (which guesses i + 1 symbols in * the past) successfully guessed. */ ec->lag_scoreboard[i] ++; /* * Keep track of the best predictor (tie goes to the * shortest lag) */ if (ec->lag_scoreboard[i] > ec->lag_scoreboard[ec->lag_best_predictor]) ec->lag_best_predictor = i; } } /* * Finally, update the lag_delta_history array with the newly input * value. */ ec->lag_delta_history[(ec->lag_observations) & JENT_LAG_MASK] = current_delta; ec->lag_observations++; /* * lag_best_predictor now is the index of the predictor with the largest * number of correct guesses. * This establishes our next guess. */ /* Do we now need a new window? */ if (ec->lag_observations >= JENT_LAG_WINDOW_SIZE) jent_lag_reset(ec); } static inline uint64_t jent_delta2(struct rand_data *ec, uint64_t current_delta) { /* Note that delta2_n = delta_n - delta_{n-1} */ return jent_delta(JENT_LAG_HISTORY(ec, 0), current_delta); } static inline uint64_t jent_delta3(struct rand_data *ec, uint64_t delta2) { /* * Note that delta3_n = delta2_n - delta2_{n-1} * = delta2_n - (delta_{n-1} - delta_{n-2}) */ return jent_delta(jent_delta(JENT_LAG_HISTORY(ec, 1), JENT_LAG_HISTORY(ec, 0)), delta2); } #else /* JENT_HEALTH_LAG_PREDICTOR */ static inline void jent_lag_insert(struct rand_data *ec, uint64_t current_delta) { (void)ec; (void)current_delta; } static inline uint64_t jent_delta2(struct rand_data *ec, uint64_t current_delta) { uint64_t delta2 = jent_delta(ec->last_delta, current_delta); ec->last_delta = current_delta; return delta2; } static inline uint64_t jent_delta3(struct rand_data *ec, uint64_t delta2) { uint64_t delta3 = jent_delta(ec->last_delta2, delta2); ec->last_delta2 = delta2; return delta3; } #endif /* JENT_HEALTH_LAG_PREDICTOR */ /*************************************************************************** * Adaptive Proportion Test * * This test complies with SP800-90B section 4.4.2. ***************************************************************************/ /* * See the SP 800-90B comment #10b for the corrected cutoff for the SP 800-90B * APT. * http://www.untruth.org/~josh/sp80090b/UL%20SP800-90B-final%20comments%20v1.9%2020191212.pdf * In in the syntax of R, this is C = 2 + qbinom(1 − 2^(−30), 511, 2^(-1/osr)). * (The original formula wasn't correct because the first symbol must * necessarily have been observed, so there is no chance of observing 0 of these * symbols.) * * For the alpha < 2^-53, R cannot be used as it uses a float data type without * arbitrary precision. A SageMath script is used to calculate those cutoff * values. * * For any value above 14, this yields the maximal allowable value of 512 * (by FIPS 140-2 IG 7.19 Resolution # 16, we cannot choose a cutoff value that * renders the test unable to fail). */ static const unsigned int jent_apt_cutoff_lookup[15]= { 325, 422, 459, 477, 488, 494, 499, 502, 505, 507, 508, 509, 510, 511, 512 }; static const unsigned int jent_apt_cutoff_permanent_lookup[15]= { 355, 447, 479, 494, 502, 507, 510, 512, 512, 512, 512, 512, 512, 512, 512 }; void jent_apt_init(struct rand_data *ec, unsigned int osr) { /* * Establish the apt_cutoff based on the presumed entropy rate of * 1/osr. */ if (osr >= ARRAY_SIZE(jent_apt_cutoff_lookup)) { ec->apt_cutoff = jent_apt_cutoff_lookup[ ARRAY_SIZE(jent_apt_cutoff_lookup) - 1]; ec->apt_cutoff_permanent = jent_apt_cutoff_permanent_lookup[ ARRAY_SIZE(jent_apt_cutoff_permanent_lookup) - 1]; } else { ec->apt_cutoff = jent_apt_cutoff_lookup[osr - 1]; ec->apt_cutoff_permanent = jent_apt_cutoff_permanent_lookup[osr - 1]; } } void jent_apt_reinit(struct rand_data *ec, uint64_t current_delta, unsigned int apt_count, unsigned int apt_observations) { ec->apt_base = current_delta; /* APT Step 1 */ ec->apt_base_set = 1; /* APT Step 2 */ /* * Reset APT counter * Note that we've taken in the first symbol in the window. * * Thus, if apt_count is zero, set it to the intermittent error. */ if (apt_count) ec->apt_count = apt_count; else ec->apt_count = ec->apt_cutoff; ec->apt_observations = apt_observations; } /** * Reset the APT counter * * @ec [in] Reference to entropy collector */ static void jent_apt_reset(struct rand_data *ec) { /* When reset, accept the _next_ value input as the new base. */ ec->apt_base_set = 0; } /** * Insert a new entropy event into APT * * @ec [in] Reference to entropy collector * @current_delta [in] Current time delta */ static void jent_apt_insert(struct rand_data *ec, uint64_t current_delta) { current_delta &= JENT_APT_MASK; /* Initialize the base reference */ if (!ec->apt_base_set) { jent_apt_reinit(ec, current_delta, 1, 1); return; } if (current_delta == ec->apt_base) { ec->apt_count++; /* B = B + 1 */ /* Note, ec->apt_count starts with one. */ if (ec->apt_count >= ec->apt_cutoff_permanent) ec->health_failure |= JENT_APT_FAILURE_PERMANENT; else if (ec->apt_count == ec->apt_cutoff) ec->health_failure |= JENT_APT_FAILURE; } ec->apt_observations++; /* Completed one window, the next symbol input will be new apt_base. */ if (ec->apt_observations >= JENT_APT_WINDOW_SIZE) jent_apt_reset(ec); /* APT Step 4 */ } /*************************************************************************** * Stuck Test and its use as Repetition Count Test * * The Jitter RNG uses an enhanced version of the Repetition Count Test * (RCT) specified in SP800-90B section 4.4.1. Instead of counting identical * back-to-back values, the input to the RCT is the counting of the stuck * values during the generation of one Jitter RNG output block. * * The RCT is applied with an alpha of 2^{-30} compliant to SP800-90B section * 4.2 for the intermittent failure and 2^{-60} for permanent failures. * * During the counting operation, the Jitter RNG always calculates the RCT * cut-off value of C. If that value exceeds the allowed cut-off value, * the Jitter RNG output block will be calculated completely but discarded at * the end. The caller of the Jitter RNG is informed with an error code. ***************************************************************************/ /** * Repetition Count Test as defined in SP800-90B section 4.4.1 * * @ec [in] Reference to entropy collector * @stuck [in] Indicator whether the value is stuck */ static void jent_rct_insert(struct rand_data *ec, int stuck) { if (stuck) { ec->rct_count++; /* * The cutoff value is based on the following consideration: * alpha = 2^-30 or 2^-60 as recommended in SP800-90B. * In addition, we require an entropy value H of 1/osr as this * is the minimum entropy required to provide full entropy. * Note, we collect (DATA_SIZE_BITS + ENTROPY_SAFETY_FACTOR)*osr * deltas for inserting them into the entropy pool which should * then have (close to) DATA_SIZE_BITS bits of entropy in the * conditioned output. * * Note, ec->rct_count (which equals to value B in the pseudo * code of SP800-90B section 4.4.1) starts with zero. Hence * we need to subtract one from the cutoff value as calculated * following SP800-90B. Thus C = ceil(-log_2(alpha)/H) = 30*osr * or 60*osr. */ if ((unsigned int)ec->rct_count >= JENT_HEALTH_RCT_PERMANENT_CUTOFF(ec->osr)) { ec->health_failure |= JENT_RCT_FAILURE_PERMANENT; } else if ((unsigned int)ec->rct_count == JENT_HEALTH_RCT_INTERMITTENT_CUTOFF(ec->osr)) { ec->health_failure |= JENT_RCT_FAILURE; } } else { ec->rct_count = 0; } } /** * Stuck test by checking the: * 1st derivative of the jitter measurement (time delta) * 2nd derivative of the jitter measurement (delta of time deltas) * 3rd derivative of the jitter measurement (delta of delta of time deltas) * * All values must always be non-zero. * * @ec [in] Reference to entropy collector * @current_delta [in] Jitter time delta * * @return * 0 jitter measurement not stuck (good bit) * 1 jitter measurement stuck (reject bit) */ unsigned int jent_stuck(struct rand_data *ec, uint64_t current_delta) { uint64_t delta2 = jent_delta2(ec, current_delta); uint64_t delta3 = jent_delta3(ec, delta2); /* * Insert the result of the comparison of two back-to-back time * deltas. */ jent_apt_insert(ec, current_delta); jent_lag_insert(ec, current_delta); if (!current_delta || !delta2 || !delta3) { /* RCT with a stuck bit */ jent_rct_insert(ec, 1); return 1; } /* RCT with a non-stuck bit */ jent_rct_insert(ec, 0); return 0; } /** * Report any health test failures * * @ec [in] Reference to entropy collector * * @return a bitmask indicating which tests failed * 0 No health test failure * 1 RCT failure * 2 APT failure * 4 Lag predictor test failure * 1<fips_enabled) return 0; if (fips_cb && ec->health_failure) { fips_cb(ec, ec->health_failure); } return ec->health_failure; } jitterentropy-library-3.6.3/src/jitterentropy-health.h000066400000000000000000000041131500137124500232310ustar00rootroot00000000000000/* * Copyright (C) 2021 - 2025, Stephan Mueller * * License: see LICENSE file in root directory * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH * DAMAGE. */ #ifndef JITTERENTROPY_HEALTH_H #define JITTERENTROPY_HEALTH_H #include "jitterentropy-internal.h" #ifdef __cplusplus extern "C" { #endif void jent_health_cb_block_switch(void); int jent_set_fips_failure_callback_internal(jent_fips_failure_cb cb); static inline uint64_t jent_delta(uint64_t prev, uint64_t next) { return (next - prev); } #ifdef JENT_HEALTH_LAG_PREDICTOR void jent_lag_init(struct rand_data *ec, unsigned int osr); #else /* JENT_HEALTH_LAG_PREDICTOR */ static inline void jent_lag_init(struct rand_data *ec, unsigned int osr) { (void)ec; (void)osr; } #endif /* JENT_HEALTH_LAG_PREDICTOR */ /* RCT: Intermittent cutoff threshold for alpha = 2**-30 */ #define JENT_HEALTH_RCT_INTERMITTENT_CUTOFF(x) ((x) * 30) /* RCT: permanent cutoff threshold for alpha = 2**-60 */ #define JENT_HEALTH_RCT_PERMANENT_CUTOFF(x) ((x) * 60) void jent_apt_init(struct rand_data *ec, unsigned int osr); void jent_apt_reinit(struct rand_data *ec, uint64_t current_delta, unsigned int apt_count, unsigned int apt_observations); unsigned int jent_stuck(struct rand_data *ec, uint64_t current_delta); unsigned int jent_health_failure(struct rand_data *ec); #ifdef __cplusplus } #endif #endif /* JITTERENTROPY_HEALTH_H */ jitterentropy-library-3.6.3/src/jitterentropy-internal.h000066400000000000000000000047741500137124500236150ustar00rootroot00000000000000/* * Non-physical true random number generator based on timing jitter. * * Copyright Stephan Mueller , 2014 - 2025 * * License * ======= * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, and the entire permission notice in its entirety, * including the disclaimer of warranties. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote * products derived from this software without specific prior * written permission. * * ALTERNATIVELY, this product may be distributed under the terms of * the GNU General Public License, in which case the provisions of the GPL are * required INSTEAD OF the above restrictions. (This clause is * necessary due to a potential bad interaction between the GPL and * the restrictions contained in a BSD-style copyright.) * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH * DAMAGE. */ #ifndef _JITTERENTROPY_INTERNAL_H #define _JITTERENTROPY_INTERNAL_H #include "jitterentropy.h" #ifdef __cplusplus extern "C" { #endif #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) /* -- BEGIN Main interface functions -- */ #ifndef JENT_STUCK_INIT_THRES /* * Per default, not more than 90% of all measurements during initialization * are allowed to be stuck. * * It is allowed to change this value as required for the intended environment. */ #define JENT_STUCK_INIT_THRES(x) ((x*9) / 10) #endif #ifdef __cplusplus } #endif #endif /* _JITTERENTROPY_INTERNAL_H */ jitterentropy-library-3.6.3/src/jitterentropy-noise.c000066400000000000000000000335251500137124500231050ustar00rootroot00000000000000/* Jitter RNG: Noise Sources * * Copyright (C) 2021 - 2025, Stephan Mueller * * License: see LICENSE file in root directory * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH * DAMAGE. */ #include "jitterentropy-noise.h" #include "jitterentropy-health.h" #include "jitterentropy-timer.h" #include "jitterentropy-sha3.h" #define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)])) /*************************************************************************** * Noise sources ***************************************************************************/ /** * Update of the loop count used for the next round of * an entropy collection. * * @ec [in] entropy collector struct * @bits [in] is the number of low bits of the timer to consider * @min [in] is the number of bits we shift the timer value to the right at * the end to make sure we have a guaranteed minimum value * * @return Newly calculated loop counter */ static uint64_t jent_loop_shuffle(struct rand_data *ec, unsigned int bits, unsigned int min) { #ifdef JENT_CONF_DISABLE_LOOP_SHUFFLE (void)ec; (void)bits; return (UINT64_C(1)< i; i++) { shuffle ^= time_now & mask; time_now = time_now >> bits; } /* * We add a lower boundary value to ensure we have a minimum * RNG loop count. */ return (shuffle + (UINT64_C(1)< 63); uint64_t hash_loop_cnt = jent_loop_shuffle(ec, MAX_HASH_LOOP, MIN_HASH_LOOP); /* Ensure that everything will fit into the intermediary buffer. */ BUILD_BUG_ON(sizeof(intermediary) < (JENT_SHA3_256_SIZE_DIGEST + sizeof(uint64_t))); jent_sha3_256_init(&ctx); /* * testing purposes -- allow test app to set the counter, not * needed during runtime */ if (loop_cnt) hash_loop_cnt = loop_cnt; /* * This loop fills a buffer which is injected into the entropy pool. * The main reason for this loop is to execute something over which we * can perform a timing measurement. The injection of the resulting * data into the pool is performed to ensure the result is used and * the compiler cannot optimize the loop away in case the result is not * used at all. Yet that data is considered "additional information" * considering the terminology from SP800-90A without any entropy. * * Note, it does not matter which or how much data you inject, we are * interested in one Keccack1600 compression operation performed with * the sha3_final. */ for (j = 0; j < hash_loop_cnt; j++) { jent_sha3_update(&ctx, intermediary, JENT_SHA3_256_SIZE_DIGEST); jent_sha3_update(&ctx, (uint8_t *)&ec->rct_count, sizeof(ec->rct_count)); jent_sha3_update(&ctx, (uint8_t *)&ec->apt_cutoff, sizeof(ec->apt_cutoff)); jent_sha3_update(&ctx, (uint8_t *)&ec->apt_observations, sizeof(ec->apt_observations)); jent_sha3_update(&ctx, (uint8_t *)&ec->apt_count, sizeof(ec->apt_count)); jent_sha3_update(&ctx,(uint8_t *) &ec->apt_base, sizeof(ec->apt_base)); jent_sha3_update(&ctx, (uint8_t *)&j, sizeof(uint64_t)); jent_sha3_final(&ctx, intermediary); } /* * Insert the time stamp into the intermediary buffer after the message * digest of the intermediate data. * * If the time stamp is stuck, do not finally insert the value into the * intermediary buffer. Although this operation should not do any harm * even when the time stamp has no entropy, SP800-90B requires that any * conditioning operation to have an identical amount of input data * according to section 3.1.5. */ if (!stuck) { /* Insert the time. */ output_value = time_delta; } else { /* The time is considered stuck. Insert the fixed value 0. */ output_value = 0; } memcpy(intermediary + JENT_SHA3_256_SIZE_DIGEST, (uint8_t *)&output_value, sizeof(uint64_t)); /* * Inject the data from the intermediary buffer, including the hash we * are using for timing, and (if the timer is not stuck) the time stamp. * Only the time is considered to contain any entropy. The intermediary * buffer is exactly SHA3-256-rate-size to always cause a Keccak * operation. */ jent_sha3_update(ec->hash_state, intermediary, sizeof(intermediary)); jent_memset_secure(&ctx, JENT_SHA_MAX_CTX_SIZE); jent_memset_secure(intermediary, sizeof(intermediary)); } #define MAX_ACC_LOOP_BIT 7 #define MIN_ACC_LOOP_BIT 0 #ifdef JENT_RANDOM_MEMACCESS static inline uint32_t uint32rotl(const uint32_t x, int k) { return (x << k) | (x >> (32 - k)); } static inline uint32_t xoshiro128starstar(uint32_t *s) { const uint32_t result = uint32rotl(s[1] * 5, 7) * 9; const uint32_t t = s[1] << 9; s[2] ^= s[0]; s[3] ^= s[1]; s[1] ^= s[2]; s[0] ^= s[3]; s[2] ^= t; s[3] = uint32rotl(s[3], 11); return result; } static void jent_memaccess(struct rand_data *ec, uint64_t loop_cnt) { uint64_t i = 0, time_now = 0; union { uint32_t u[4]; uint8_t b[sizeof(uint32_t) * 4]; } prngState = { .u = {0x8e93eec0, 0xce65608a, 0xa8d46b46, 0xe83cef69} }; uint32_t addressMask; /* Ensure that macros cannot overflow jent_loop_shuffle() */ BUILD_BUG_ON((MAX_ACC_LOOP_BIT + MIN_ACC_LOOP_BIT) > 63); uint64_t acc_loop_cnt = jent_loop_shuffle(ec, MAX_ACC_LOOP_BIT, MIN_ACC_LOOP_BIT); if (NULL == ec || NULL == ec->mem) return; addressMask = ec->memmask; /* * Mix the current data into prngState * * Any time you see a PRNG in a noise source, you should be concerned. * * The PRNG doesn’t directly produce the raw noise, it just adjusts the * location being updated. The timing of the update is part of the raw * sample. The main thing this process gets you isn’t better * “per-update” timing, it gets you mostly independent “per-update” * timing, so we can now benefit from the Central Limit Theorem! */ for (i = 0; i < sizeof(prngState); i++) { jent_get_nstime_internal(ec, &time_now); prngState.b[i] ^= (uint8_t)(time_now & 0xff); } /* * testing purposes -- allow test app to set the counter, not * needed during runtime */ if (loop_cnt) acc_loop_cnt = loop_cnt; for (i = 0; i < (ec->memaccessloops + acc_loop_cnt); i++) { /* Take PRNG output to find the memory location to update. */ unsigned char *tmpval = ec->mem + (xoshiro128starstar(prngState.u) & addressMask); /* * memory access: just add 1 to one byte, * wrap at 255 -- memory access implies read * from and write to memory location */ *tmpval = (unsigned char)((*tmpval + 1) & 0xff); } } #else /* JENT_RANDOM_MEMACCESS */ /** * Memory Access noise source -- this is a noise source based on variations in * memory access times * * This function performs memory accesses which will add to the timing * variations due to an unknown amount of CPU wait states that need to be * added when accessing memory. The memory size should be larger than the L1 * caches as outlined in the documentation and the associated testing. * * The L1 cache has a very high bandwidth, albeit its access rate is usually * slower than accessing CPU registers. Therefore, L1 accesses only add minimal * variations as the CPU has hardly to wait. Starting with L2, significant * variations are added because L2 typically does not belong to the CPU any more * and therefore a wider range of CPU wait states is necessary for accesses. * L3 and real memory accesses have even a wider range of wait states. However, * to reliably access either L3 or memory, the ec->mem memory must be quite * large which is usually not desirable. * * @ec [in] Reference to the entropy collector with the memory access data -- if * the reference to the memory block to be accessed is NULL, this noise * source is disabled * @loop_cnt [in] if a value not equal to 0 is set, use the given value as * number of loops to perform the hash operation */ static void jent_memaccess(struct rand_data *ec, uint64_t loop_cnt) { unsigned int wrap = 0; uint64_t i = 0; /* Ensure that macros cannot overflow jent_loop_shuffle() */ BUILD_BUG_ON((MAX_ACC_LOOP_BIT + MIN_ACC_LOOP_BIT) > 63); uint64_t acc_loop_cnt = jent_loop_shuffle(ec, MAX_ACC_LOOP_BIT, MIN_ACC_LOOP_BIT); if (NULL == ec || NULL == ec->mem) return; wrap = ec->memblocksize * ec->memblocks; /* * testing purposes -- allow test app to set the counter, not * needed during runtime */ if (loop_cnt) acc_loop_cnt = loop_cnt; for (i = 0; i < (ec->memaccessloops + acc_loop_cnt); i++) { unsigned char *tmpval = ec->mem + ec->memlocation; /* * memory access: just add 1 to one byte, * wrap at 255 -- memory access implies read * from and write to memory location */ *tmpval = (unsigned char)((*tmpval + 1) & 0xff); /* * Addition of memblocksize - 1 to pointer * with wrap around logic to ensure that every * memory location is hit evenly */ ec->memlocation = ec->memlocation + ec->memblocksize - 1; ec->memlocation = ec->memlocation % wrap; } } #endif /* JENT_RANDOM_MEMACCESS */ /*************************************************************************** * Start of entropy processing logic ***************************************************************************/ /** * This is the heart of the entropy generation: calculate time deltas and * use the CPU jitter in the time deltas. The jitter is injected into the * entropy pool. * * WARNING: ensure that ->prev_time is primed before using the output * of this function! This can be done by calling this function * and not using its result. * * @ec [in] Reference to entropy collector * @loop_cnt [in] see jent_hash_time * @ret_current_delta [out] Test interface: return time delta - may be NULL * * @return: result of stuck test */ unsigned int jent_measure_jitter(struct rand_data *ec, uint64_t loop_cnt, uint64_t *ret_current_delta) { uint64_t time_now = 0; uint64_t current_delta = 0; unsigned int stuck; /* Invoke one noise source before time measurement to add variations */ jent_memaccess(ec, loop_cnt); /* * Get time stamp and calculate time delta to previous * invocation to measure the timing variations */ jent_get_nstime_internal(ec, &time_now); current_delta = jent_delta(ec->prev_time, time_now) / ec->jent_common_timer_gcd; ec->prev_time = time_now; /* Check whether we have a stuck measurement. */ stuck = jent_stuck(ec, current_delta); /* Now call the next noise sources which also injects the data */ jent_hash_time(ec, current_delta, loop_cnt, stuck); /* return the raw entropy value */ if (ret_current_delta) *ret_current_delta = current_delta; return stuck; } /** * Generator of one 256 bit random number * Function fills rand_data->hash_state * * @ec [in] Reference to entropy collector */ void jent_random_data(struct rand_data *ec) { unsigned int k = 0, safety_factor = 0; if (ec->fips_enabled) safety_factor = ENTROPY_SAFETY_FACTOR; /* priming of the ->prev_time value */ jent_measure_jitter(ec, 0, NULL); while (!jent_health_failure(ec)) { /* If a stuck measurement is received, repeat measurement */ if (jent_measure_jitter(ec, 0, NULL)) continue; /* * We multiply the loop value with ->osr to obtain the * oversampling rate requested by the caller */ if (++k >= ((DATA_SIZE_BITS + safety_factor) * ec->osr)) break; } } void jent_read_random_block(struct rand_data *ec, char *dst, size_t dst_len) { uint8_t jent_block[JENT_SHA3_256_SIZE_DIGEST]; BUILD_BUG_ON(JENT_SHA3_256_SIZE_DIGEST != (DATA_SIZE_BITS / 8)); /* The final operation automatically re-initializes the ->hash_state */ jent_sha3_final(ec->hash_state, jent_block); if (dst_len) memcpy(dst, jent_block, dst_len); /* * Stir the new state with the data from the old state - the digest * of the old data is not considered to have entropy. */ jent_sha3_update(ec->hash_state, jent_block, sizeof(jent_block)); jent_memset_secure(jent_block, sizeof(jent_block)); } jitterentropy-library-3.6.3/src/jitterentropy-noise.h000066400000000000000000000024511500137124500231040ustar00rootroot00000000000000/* * Copyright (C) 2021 - 2025, Stephan Mueller * * License: see LICENSE file in root directory * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH * DAMAGE. */ #ifndef JITTERENTROPY_NOISE_H #define JITTERENTROPY_NOISE_H #include "jitterentropy-internal.h" #ifdef __cplusplus extern "C" { #endif unsigned int jent_measure_jitter(struct rand_data *ec, uint64_t loop_cnt, uint64_t *ret_current_delta); void jent_random_data(struct rand_data *ec); void jent_read_random_block(struct rand_data *ec, char *dst, size_t dst_len); #ifdef __cplusplus } #endif #endif /* JITTERENTROPY_NOISE_H */ jitterentropy-library-3.6.3/src/jitterentropy-sha3.c000066400000000000000000000256001500137124500226210ustar00rootroot00000000000000/* Jitter RNG: SHA-3 Implementation * * Copyright (C) 2021 - 2025, Stephan Mueller * * License: see LICENSE file in root directory * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH * DAMAGE. */ #include "jitterentropy-sha3.h" #include "jitterentropy-internal.h" /*************************************************************************** * Message Digest Implementation ***************************************************************************/ /* * Conversion of Little-Endian representations in byte streams - the data * representation in the integer values is the host representation. */ static inline uint32_t ptr_to_le32(const uint8_t *p) { return (uint32_t)p[0] | (uint32_t)p[1] << 8 | (uint32_t)p[2] << 16 | (uint32_t)p[3] << 24; } static inline uint64_t ptr_to_le64(const uint8_t *p) { return (uint64_t)ptr_to_le32(p) | (uint64_t)ptr_to_le32(p + 4) << 32; } static inline void le32_to_ptr(uint8_t *p, const uint32_t value) { p[0] = (uint8_t)(value); p[1] = (uint8_t)(value >> 8); p[2] = (uint8_t)(value >> 16); p[3] = (uint8_t)(value >> 24); } static inline void le64_to_ptr(uint8_t *p, const uint64_t value) { le32_to_ptr(p + 4, (uint32_t)(value >> 32)); le32_to_ptr(p, (uint32_t)(value)); } /*********************************** Keccak ***********************************/ /* state[x + y*5] */ #define A(x, y) (x + 5 * y) static inline void jent_keccakp_theta(uint64_t s[25]) { uint64_t C[5], D[5]; /* Step 1 */ C[0] = s[A(0, 0)] ^ s[A(0, 1)] ^ s[A(0, 2)] ^ s[A(0, 3)] ^ s[A(0, 4)]; C[1] = s[A(1, 0)] ^ s[A(1, 1)] ^ s[A(1, 2)] ^ s[A(1, 3)] ^ s[A(1, 4)]; C[2] = s[A(2, 0)] ^ s[A(2, 1)] ^ s[A(2, 2)] ^ s[A(2, 3)] ^ s[A(2, 4)]; C[3] = s[A(3, 0)] ^ s[A(3, 1)] ^ s[A(3, 2)] ^ s[A(3, 3)] ^ s[A(3, 4)]; C[4] = s[A(4, 0)] ^ s[A(4, 1)] ^ s[A(4, 2)] ^ s[A(4, 3)] ^ s[A(4, 4)]; /* Step 2 */ D[0] = C[4] ^ rol64(C[1], 1); D[1] = C[0] ^ rol64(C[2], 1); D[2] = C[1] ^ rol64(C[3], 1); D[3] = C[2] ^ rol64(C[4], 1); D[4] = C[3] ^ rol64(C[0], 1); /* Step 3 */ s[A(0, 0)] ^= D[0]; s[A(1, 0)] ^= D[1]; s[A(2, 0)] ^= D[2]; s[A(3, 0)] ^= D[3]; s[A(4, 0)] ^= D[4]; s[A(0, 1)] ^= D[0]; s[A(1, 1)] ^= D[1]; s[A(2, 1)] ^= D[2]; s[A(3, 1)] ^= D[3]; s[A(4, 1)] ^= D[4]; s[A(0, 2)] ^= D[0]; s[A(1, 2)] ^= D[1]; s[A(2, 2)] ^= D[2]; s[A(3, 2)] ^= D[3]; s[A(4, 2)] ^= D[4]; s[A(0, 3)] ^= D[0]; s[A(1, 3)] ^= D[1]; s[A(2, 3)] ^= D[2]; s[A(3, 3)] ^= D[3]; s[A(4, 3)] ^= D[4]; s[A(0, 4)] ^= D[0]; s[A(1, 4)] ^= D[1]; s[A(2, 4)] ^= D[2]; s[A(3, 4)] ^= D[3]; s[A(4, 4)] ^= D[4]; } static inline void jent_keccakp_rho(uint64_t s[25]) { /* Step 1 */ /* s[A(0, 0)] = s[A(0, 0)]; */ #define RHO_ROL(t) (((t + 1) * (t + 2) / 2) % 64) /* Step 3 */ s[A(1, 0)] = rol64(s[A(1, 0)], RHO_ROL(0)); s[A(0, 2)] = rol64(s[A(0, 2)], RHO_ROL(1)); s[A(2, 1)] = rol64(s[A(2, 1)], RHO_ROL(2)); s[A(1, 2)] = rol64(s[A(1, 2)], RHO_ROL(3)); s[A(2, 3)] = rol64(s[A(2, 3)], RHO_ROL(4)); s[A(3, 3)] = rol64(s[A(3, 3)], RHO_ROL(5)); s[A(3, 0)] = rol64(s[A(3, 0)], RHO_ROL(6)); s[A(0, 1)] = rol64(s[A(0, 1)], RHO_ROL(7)); s[A(1, 3)] = rol64(s[A(1, 3)], RHO_ROL(8)); s[A(3, 1)] = rol64(s[A(3, 1)], RHO_ROL(9)); s[A(1, 4)] = rol64(s[A(1, 4)], RHO_ROL(10)); s[A(4, 4)] = rol64(s[A(4, 4)], RHO_ROL(11)); s[A(4, 0)] = rol64(s[A(4, 0)], RHO_ROL(12)); s[A(0, 3)] = rol64(s[A(0, 3)], RHO_ROL(13)); s[A(3, 4)] = rol64(s[A(3, 4)], RHO_ROL(14)); s[A(4, 3)] = rol64(s[A(4, 3)], RHO_ROL(15)); s[A(3, 2)] = rol64(s[A(3, 2)], RHO_ROL(16)); s[A(2, 2)] = rol64(s[A(2, 2)], RHO_ROL(17)); s[A(2, 0)] = rol64(s[A(2, 0)], RHO_ROL(18)); s[A(0, 4)] = rol64(s[A(0, 4)], RHO_ROL(19)); s[A(4, 2)] = rol64(s[A(4, 2)], RHO_ROL(20)); s[A(2, 4)] = rol64(s[A(2, 4)], RHO_ROL(21)); s[A(4, 1)] = rol64(s[A(4, 1)], RHO_ROL(22)); s[A(1, 1)] = rol64(s[A(1, 1)], RHO_ROL(23)); } static inline void jent_keccakp_pi(uint64_t s[25]) { uint64_t t = s[A(4, 4)]; /* Step 1 */ /* s[A(0, 0)] = s[A(0, 0)]; */ s[A(4, 4)] = s[A(1, 4)]; s[A(1, 4)] = s[A(3, 1)]; s[A(3, 1)] = s[A(1, 3)]; s[A(1, 3)] = s[A(0, 1)]; s[A(0, 1)] = s[A(3, 0)]; s[A(3, 0)] = s[A(3, 3)]; s[A(3, 3)] = s[A(2, 3)]; s[A(2, 3)] = s[A(1, 2)]; s[A(1, 2)] = s[A(2, 1)]; s[A(2, 1)] = s[A(0, 2)]; s[A(0, 2)] = s[A(1, 0)]; s[A(1, 0)] = s[A(1, 1)]; s[A(1, 1)] = s[A(4, 1)]; s[A(4, 1)] = s[A(2, 4)]; s[A(2, 4)] = s[A(4, 2)]; s[A(4, 2)] = s[A(0, 4)]; s[A(0, 4)] = s[A(2, 0)]; s[A(2, 0)] = s[A(2, 2)]; s[A(2, 2)] = s[A(3, 2)]; s[A(3, 2)] = s[A(4, 3)]; s[A(4, 3)] = s[A(3, 4)]; s[A(3, 4)] = s[A(0, 3)]; s[A(0, 3)] = s[A(4, 0)]; s[A(4, 0)] = t; } static inline void jent_keccakp_chi(uint64_t s[25]) { uint64_t t0[5], t1[5]; t0[0] = s[A(0, 0)]; t0[1] = s[A(0, 1)]; t0[2] = s[A(0, 2)]; t0[3] = s[A(0, 3)]; t0[4] = s[A(0, 4)]; t1[0] = s[A(1, 0)]; t1[1] = s[A(1, 1)]; t1[2] = s[A(1, 2)]; t1[3] = s[A(1, 3)]; t1[4] = s[A(1, 4)]; s[A(0, 0)] ^= ~s[A(1, 0)] & s[A(2, 0)]; s[A(0, 1)] ^= ~s[A(1, 1)] & s[A(2, 1)]; s[A(0, 2)] ^= ~s[A(1, 2)] & s[A(2, 2)]; s[A(0, 3)] ^= ~s[A(1, 3)] & s[A(2, 3)]; s[A(0, 4)] ^= ~s[A(1, 4)] & s[A(2, 4)]; s[A(1, 0)] ^= ~s[A(2, 0)] & s[A(3, 0)]; s[A(1, 1)] ^= ~s[A(2, 1)] & s[A(3, 1)]; s[A(1, 2)] ^= ~s[A(2, 2)] & s[A(3, 2)]; s[A(1, 3)] ^= ~s[A(2, 3)] & s[A(3, 3)]; s[A(1, 4)] ^= ~s[A(2, 4)] & s[A(3, 4)]; s[A(2, 0)] ^= ~s[A(3, 0)] & s[A(4, 0)]; s[A(2, 1)] ^= ~s[A(3, 1)] & s[A(4, 1)]; s[A(2, 2)] ^= ~s[A(3, 2)] & s[A(4, 2)]; s[A(2, 3)] ^= ~s[A(3, 3)] & s[A(4, 3)]; s[A(2, 4)] ^= ~s[A(3, 4)] & s[A(4, 4)]; s[A(3, 0)] ^= ~s[A(4, 0)] & t0[0]; s[A(3, 1)] ^= ~s[A(4, 1)] & t0[1]; s[A(3, 2)] ^= ~s[A(4, 2)] & t0[2]; s[A(3, 3)] ^= ~s[A(4, 3)] & t0[3]; s[A(3, 4)] ^= ~s[A(4, 4)] & t0[4]; s[A(4, 0)] ^= ~t0[0] & t1[0]; s[A(4, 1)] ^= ~t0[1] & t1[1]; s[A(4, 2)] ^= ~t0[2] & t1[2]; s[A(4, 3)] ^= ~t0[3] & t1[3]; s[A(4, 4)] ^= ~t0[4] & t1[4]; } static const uint64_t jent_keccakp_iota_vals[] = { 0x0000000000000001ULL, 0x0000000000008082ULL, 0x800000000000808aULL, 0x8000000080008000ULL, 0x000000000000808bULL, 0x0000000080000001ULL, 0x8000000080008081ULL, 0x8000000000008009ULL, 0x000000000000008aULL, 0x0000000000000088ULL, 0x0000000080008009ULL, 0x000000008000000aULL, 0x000000008000808bULL, 0x800000000000008bULL, 0x8000000000008089ULL, 0x8000000000008003ULL, 0x8000000000008002ULL, 0x8000000000000080ULL, 0x000000000000800aULL, 0x800000008000000aULL, 0x8000000080008081ULL, 0x8000000000008080ULL, 0x0000000080000001ULL, 0x8000000080008008ULL }; static inline void jent_keccakp_iota(uint64_t s[25], unsigned int round) { s[0] ^= jent_keccakp_iota_vals[round]; } static inline void jent_keccakp_1600(uint64_t s[25]) { unsigned int round; for (round = 0; round < 24; round++) { jent_keccakp_theta(s); jent_keccakp_rho(s); jent_keccakp_pi(s); jent_keccakp_chi(s); jent_keccakp_iota(s, round); } } /*********************************** SHA-3 ************************************/ static inline void jent_sha3_init(struct jent_sha_ctx *ctx) { unsigned int i; for (i = 0; i < 25; i++) ctx->state[i] = 0; ctx->msg_len = 0; } void jent_sha3_256_init(struct jent_sha_ctx *ctx) { jent_sha3_init(ctx); ctx->r = JENT_SHA3_256_SIZE_BLOCK; ctx->rword = JENT_SHA3_256_SIZE_BLOCK / sizeof(uint64_t); ctx->digestsize = JENT_SHA3_256_SIZE_DIGEST; } static inline void jent_sha3_fill_state(struct jent_sha_ctx *ctx, const uint8_t *in) { unsigned int i; for (i = 0; i < ctx->rword; i++) { ctx->state[i] ^= ptr_to_le64(in); in += 8; } } void jent_sha3_update(struct jent_sha_ctx *ctx, const uint8_t *in, size_t inlen) { size_t partial = ctx->msg_len % ctx->r; ctx->msg_len += inlen; /* Sponge absorbing phase */ /* Check if we have a partial block stored */ if (partial) { size_t todo = ctx->r - partial; /* * If the provided data is small enough to fit in the partial * buffer, copy it and leave it unprocessed. */ if (inlen < todo) { memcpy(ctx->partial + partial, in, inlen); return; } /* * The input data is large enough to fill the entire partial * block buffer. Thus, we fill it and transform it. */ memcpy(ctx->partial + partial, in, todo); inlen -= todo; in += todo; jent_sha3_fill_state(ctx, ctx->partial); jent_keccakp_1600(ctx->state); } /* Perform a transformation of full block-size messages */ for (; inlen >= ctx->r; inlen -= ctx->r, in += ctx->r) { jent_sha3_fill_state(ctx, in); jent_keccakp_1600(ctx->state); } /* If we have data left, copy it into the partial block buffer */ memcpy(ctx->partial, in, inlen); } void jent_sha3_final(struct jent_sha_ctx *ctx, uint8_t *digest) { size_t partial = ctx->msg_len % ctx->r; unsigned int i; /* Final round in sponge absorbing phase */ /* Fill the unused part of the partial buffer with zeros */ memset(ctx->partial + partial, 0, ctx->r - partial); /* * Add the leading and trailing bit as well as the 01 bits for the * SHA-3 suffix. */ ctx->partial[partial] = 0x06; ctx->partial[ctx->r - 1] |= 0x80; /* Final transformation */ jent_sha3_fill_state(ctx, ctx->partial); jent_keccakp_1600(ctx->state); /* * Sponge squeeze phase - the digest size is always smaller as the * state size r which implies we only have one squeeze round. */ for (i = 0; i < ctx->digestsize / 8; i++, digest += 8) le64_to_ptr(digest, ctx->state[i]); /* Add remaining 4 bytes if we use SHA3-224 */ if (ctx->digestsize % 8) le32_to_ptr(digest, (uint32_t)(ctx->state[i])); memset(ctx->partial, 0, ctx->r); jent_sha3_init(ctx); } int jent_sha3_tester(void) { HASH_CTX_ON_STACK(ctx); static const uint8_t msg_256[] = { 0x5E, 0x5E, 0xD6 }; static const uint8_t exp_256[] = { 0xF1, 0x6E, 0x66, 0xC0, 0x43, 0x72, 0xB4, 0xA3, 0xE1, 0xE3, 0x2E, 0x07, 0xC4, 0x1C, 0x03, 0x40, 0x8A, 0xD5, 0x43, 0x86, 0x8C, 0xC4, 0x0E, 0xC5, 0x5E, 0x00, 0xBB, 0xBB, 0xBD, 0xF5, 0x91, 0x1E }; uint8_t act[JENT_SHA3_256_SIZE_DIGEST] = { 0 }; unsigned int i; jent_sha3_256_init(&ctx); jent_sha3_update(&ctx, msg_256, 3); jent_sha3_final(&ctx, act); for (i = 0; i < JENT_SHA3_256_SIZE_DIGEST; i++) { if (exp_256[i] != act[i]) return 1; } return 0; } int jent_sha3_alloc(void **hash_state) { struct sha_ctx *tmp; tmp = jent_zalloc(JENT_SHA_MAX_CTX_SIZE); if (!tmp) return 1; *hash_state = tmp; return 0; } void jent_sha3_dealloc(void *hash_state) { struct sha_ctx *ctx = (struct sha_ctx *)hash_state; jent_zfree(ctx, JENT_SHA_MAX_CTX_SIZE); } jitterentropy-library-3.6.3/src/jitterentropy-sha3.h000066400000000000000000000036441500137124500226320ustar00rootroot00000000000000/* * Copyright (C) 2021 - 2025, Stephan Mueller * * License: see LICENSE file in root directory * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH * DAMAGE. */ #ifndef JITTERENTROPY_SHA3_H #define JITTERENTROPY_SHA3_H #include "jitterentropy-internal.h" #ifdef __cplusplus extern "C" { #endif #define JENT_SHA3_SIZE_BLOCK(bits) ((1600 - 2 * bits) >> 3) #define JENT_SHA3_256_SIZE_BLOCK \ JENT_SHA3_SIZE_BLOCK(JENT_SHA3_256_SIZE_DIGEST_BITS) #define JENT_SHA3_MAX_SIZE_BLOCK JENT_SHA3_256_SIZE_BLOCK struct jent_sha_ctx { uint64_t state[25]; size_t msg_len; unsigned int r; unsigned int rword; unsigned int digestsize; uint8_t partial[JENT_SHA3_MAX_SIZE_BLOCK]; }; #define JENT_SHA_MAX_CTX_SIZE (sizeof(struct jent_sha_ctx)) #define HASH_CTX_ON_STACK(name) \ struct jent_sha_ctx name void jent_sha3_256_init(struct jent_sha_ctx *ctx); void jent_sha3_update(struct jent_sha_ctx *ctx, const uint8_t *in, size_t inlen); void jent_sha3_final(struct jent_sha_ctx *ctx, uint8_t *digest); int jent_sha3_alloc(void **hash_state); void jent_sha3_dealloc(void *hash_state); int jent_sha3_tester(void); #ifdef __cplusplus } #endif #endif /* JITTERENTROPY_SHA3_H */ jitterentropy-library-3.6.3/src/jitterentropy-timer.c000066400000000000000000000142541500137124500231060ustar00rootroot00000000000000/* Jitter RNG: Internal timer implementation * * Copyright (C) 2021 - 2025, Stephan Mueller * * License: see LICENSE file in root directory * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH * DAMAGE. */ #include "jitterentropy-base.h" #include "jitterentropy-timer.h" #ifdef JENT_CONF_ENABLE_INTERNAL_TIMER /*************************************************************************** * Thread handler ***************************************************************************/ #ifdef USE_OLDER_GLIBC __asm__(".symver pthread_join, pthread_join@GLIBC_2.2.5"); __asm__(".symver pthread_create, pthread_create@GLIBC_2.2.5"); #endif JENT_PRIVATE_STATIC int jent_notime_init(void **ctx) { struct jent_notime_ctx *thread_ctx; long ncpu = jent_ncpu(); if (ncpu < 0) return (int)ncpu; /* We need at least two CPUs to enable the timer thread */ if (ncpu < 2) return -EOPNOTSUPP; thread_ctx = calloc(1, sizeof(struct jent_notime_ctx)); if (!thread_ctx) return -errno; *ctx = thread_ctx; return 0; } JENT_PRIVATE_STATIC void jent_notime_fini(void *ctx) { struct jent_notime_ctx *thread_ctx = (struct jent_notime_ctx *)ctx; if (thread_ctx) free(thread_ctx); } static int jent_notime_start(void *ctx, void *(*start_routine) (void *), void *arg) { struct jent_notime_ctx *thread_ctx = (struct jent_notime_ctx *)ctx; int ret; if (!thread_ctx) return -EINVAL; ret = -pthread_attr_init(&thread_ctx->notime_pthread_attr); if (ret) return ret; return -pthread_create(&thread_ctx->notime_thread_id, &thread_ctx->notime_pthread_attr, start_routine, arg); } static void jent_notime_stop(void *ctx) { struct jent_notime_ctx *thread_ctx = (struct jent_notime_ctx *)ctx; pthread_join(thread_ctx->notime_thread_id, NULL); pthread_attr_destroy(&thread_ctx->notime_pthread_attr); } static struct jent_notime_thread jent_notime_thread_builtin = { .jent_notime_init = jent_notime_init, .jent_notime_fini = jent_notime_fini, .jent_notime_start = jent_notime_start, .jent_notime_stop = jent_notime_stop }; /*************************************************************************** * Timer-less timer replacement * * If there is no high-resolution hardware timer available, we create one * ourselves. This logic is only used when the initialization identifies * that no suitable time source is available. ***************************************************************************/ static int jent_force_internal_timer = 0; static int jent_notime_switch_blocked = 0; void jent_notime_block_switch(void) { jent_notime_switch_blocked = 1; } static struct jent_notime_thread *notime_thread = &jent_notime_thread_builtin; /** * Timer-replacement loop * * @brief The measurement loop triggers the read of the value from the * counter function. It conceptually acts as the low resolution * samples timer from a ring oscillator. */ static void *jent_notime_sample_timer(void *arg) { struct rand_data *ec = (struct rand_data *)arg; ec->notime_timer = 0; while (1) { if (ec->notime_interrupt) return NULL; ec->notime_timer++; } return NULL; } /* * Enable the clock: spawn a new thread that holds a counter. * * Note, although creating a thread is expensive, we do that every time a * caller wants entropy from us and terminate the thread afterwards. This * is to ensure an attacker cannot easily identify the ticking thread. */ int jent_notime_settick(struct rand_data *ec) { if (!ec->enable_notime || !notime_thread) return 0; ec->notime_interrupt = 0; ec->notime_prev_timer = 0; ec->notime_timer = 0; return notime_thread->jent_notime_start(ec->notime_thread_ctx, jent_notime_sample_timer, ec); } void jent_notime_unsettick(struct rand_data *ec) { if (!ec->enable_notime || !notime_thread) return; ec->notime_interrupt = 1; notime_thread->jent_notime_stop(ec->notime_thread_ctx); } void jent_get_nstime_internal(struct rand_data *ec, uint64_t *out) { if (ec->enable_notime) { /* * Allow the counting thread to be initialized and guarantee * that it ticked since last time we looked. * * Note, we do not use an atomic operation here for reading * jent_notime_timer since if this integer is garbled, it even * adds to entropy. But on most architectures, read/write * of an uint64_t should be atomic anyway. */ while (ec->notime_timer == ec->notime_prev_timer) jent_yield(); ec->notime_prev_timer = ec->notime_timer; *out = ec->notime_prev_timer; } else { jent_get_nstime(out); } } static inline int jent_notime_enable_thread(struct rand_data *ec) { if (notime_thread) return notime_thread->jent_notime_init(&ec->notime_thread_ctx); return 0; } void jent_notime_disable(struct rand_data *ec) { if (notime_thread) notime_thread->jent_notime_fini(ec->notime_thread_ctx); } int jent_notime_enable(struct rand_data *ec, unsigned int flags) { /* Use internal timer */ if (jent_force_internal_timer || (flags & JENT_FORCE_INTERNAL_TIMER)) { /* Self test not run yet */ if (!jent_force_internal_timer && jent_time_entropy_init(ec->osr, flags | JENT_FORCE_INTERNAL_TIMER)) return EHEALTH; ec->enable_notime = 1; return jent_notime_enable_thread(ec); } return 0; } int jent_notime_switch(struct jent_notime_thread *new_thread) { if (jent_notime_switch_blocked) return -EAGAIN; notime_thread = new_thread; return 0; } void jent_notime_force(void) { jent_force_internal_timer = 1; } int jent_notime_forced(void) { return jent_force_internal_timer; } #endif /* JENT_CONF_ENABLE_INTERNAL_TIMER */ jitterentropy-library-3.6.3/src/jitterentropy-timer.h000066400000000000000000000047431500137124500231150ustar00rootroot00000000000000/* * Copyright (C) 2021 - 2025, Stephan Mueller * * License: see LICENSE file in root directory * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH * DAMAGE. */ #ifndef JITTERENTROPY_TIMER_H #define JITTERENTROPY_TIMER_H #include "jitterentropy-internal.h" #ifdef __cplusplus extern "C" { #endif #ifdef JENT_CONF_ENABLE_INTERNAL_TIMER void jent_notime_block_switch(void); int jent_notime_settick(struct rand_data *ec); void jent_notime_unsettick(struct rand_data *ec); void jent_get_nstime_internal(struct rand_data *ec, uint64_t *out); int jent_notime_enable(struct rand_data *ec, unsigned int flags); void jent_notime_disable(struct rand_data *ec); int jent_notime_switch(struct jent_notime_thread *new_thread); void jent_notime_force(void); int jent_notime_forced(void); #else /* JENT_CONF_ENABLE_INTERNAL_TIMER */ static inline void jent_notime_block_switch(void) { } static inline int jent_notime_settick(struct rand_data *ec) { (void)ec; return 0; } static inline void jent_notime_unsettick(struct rand_data *ec) { (void)ec; } static inline void jent_get_nstime_internal(struct rand_data *ec, uint64_t *out) { (void)ec; jent_get_nstime(out); } static inline int jent_notime_enable(struct rand_data *ec, unsigned int flags) { (void)ec; /* If we force the timer-less noise source, we return an error */ if (flags & JENT_FORCE_INTERNAL_TIMER) return EHEALTH; return 0; } static inline void jent_notime_disable(struct rand_data *ec) { (void)ec; } static inline int jent_notime_switch(struct jent_notime_thread *new_thread) { (void)new_thread; return -EOPNOTSUPP; } static inline void jent_notime_force(void) { } static inline int jent_notime_forced(void) { return 0; } #endif /* JENT_CONF_ENABLE_INTERNAL_TIMER */ #ifdef __cplusplus } #endif #endif /* JITTERENTROPY-TIMER_H */ jitterentropy-library-3.6.3/tests/000077500000000000000000000000001500137124500172475ustar00rootroot00000000000000jitterentropy-library-3.6.3/tests/README.md000066400000000000000000000004231500137124500205250ustar00rootroot00000000000000# Jitter RNG Tests The following Jitter RNG tests are available in the following directories: * `raw-entropy`: Gathering of the raw unprocessed entropy data and restart test entropy data required for the SP800-90B analysis # Author Stephan Mueller jitterentropy-library-3.6.3/tests/gcd/000077500000000000000000000000001500137124500200045ustar00rootroot00000000000000jitterentropy-library-3.6.3/tests/gcd/CMakeLists.txt000066400000000000000000000001671500137124500225500ustar00rootroot00000000000000add_executable(gcd gcd.c) target_include_directories(gcd PRIVATE ../../src) target_link_libraries(gcd ${PROJECT_NAME}) jitterentropy-library-3.6.3/tests/gcd/Makefile000066400000000000000000000122431500137124500214460ustar00rootroot00000000000000# # Copyright (C) 2021 - 2025, Stephan Mueller # CC ?= gcc CFLAGS += -Wextra -Wall -pedantic -fPIC -O2 -std=gnu18 #Hardening CFLAGS += -D_FORTIFY_SOURCE=2 -fstack-protector-strong -fwrapv --param ssp-buffer-size=4 -fvisibility=hidden -fPIE -Wconversion -Wcast-align -Wmissing-field-initializers -Wshadow -Wswitch-enum #Optimizations CFLAGS += -flto LDFLAGS += -flto UNAME_S := $(shell uname -s) ifeq ($(UNAME_S),Linux) LDFLAGS += -Wl,-z,relro,-z,now,--as-needed -pie endif NAME := gcd DESTDIR := ETCDIR := /etc BINDIR := /bin SBINDIR := /sbin SHAREDIR := /usr/share/keyutils MANDIR := /usr/share/man MAN1 := $(MANDIR)/man1 MAN3 := $(MANDIR)/man3 MAN5 := $(MANDIR)/man5 MAN7 := $(MANDIR)/man7 MAN8 := $(MANDIR)/man8 INCLUDEDIR := /usr/include LN := ln LNS := $(LN) -sf STRIP ?= strip -s ############################################################################### # # Define compilation options # ############################################################################### INCLUDE_DIRS := ../../ ../../src LIBRARY_DIRS := LIBRARIES := CFLAGS += $(foreach includedir,$(INCLUDE_DIRS),-I$(includedir)) LDFLAGS += $(foreach librarydir,$(LIBRARY_DIRS),-L$(librarydir)) LDFLAGS += $(foreach library,$(LIBRARIES),-l$(library)) ############################################################################### # # Get version name and cross check # ############################################################################### VERFILE := gcd.c APPMAJOR := $(shell grep '^\#define.*MAJVERSION' $(VERFILE) | awk '{print $$3}') APPMINOR := $(shell grep '^\#define.*MINVERSION' $(VERFILE) | awk '{print $$3}') APPPATCH := $(shell grep '^\#define.*PATCHLEVEL' $(VERFILE) | awk '{print $$3}') APPVERSION := $(APPMAJOR).$(APPMINOR).$(APPPATCH) ############################################################################### # # Guess at the appropriate lib directory and word size # ############################################################################### ifeq ($(UNAME_S),Linux) ifeq ($(origin LIBDIR),undefined) LIBDIR := $(shell ldd /usr/bin/make | grep '\(/libc\.\)' | sed -e 's!.*\(/.*\)/libc[.].*!\1!') endif ifeq ($(origin USRLIBDIR),undefined) USRLIBDIR := $(patsubst /lib/%,/usr/lib/%,$(LIBDIR)) endif BUILDFOR := $(shell file /usr/bin/make | sed -e 's!.*ELF \(32\|64\)-bit.*!\1!')-bit ifeq ($(origin CFLAGS),undefined) ifeq ($(BUILDFOR),32-bit) CFLAGS += -m32 LIBDIR := /lib USRLIBDIR := /usr/lib else ifeq ($(BUILDFOR),64-bit) CFLAGS += -m64 LIBDIR := /lib64 USRLIBDIR := /usr/lib64 endif endif endif else LIBDIR := /lib USRLIBDIR := /usr/lib endif ############################################################################### # # Define files to be compiled # ############################################################################### C_SRCS := $(wildcard *.c) ../../src/jitterentropy-gcd.c C_OBJS := ${C_SRCS:.c=.o} C_GCOV := ${C_SRCS:.c=.gcda} C_GCOV += ${C_SRCS:.c=.gcno} C_GCOV += ${C_SRCS:.c=.gcov} OBJS := $(C_OBJS) analyze_srcs = $(filter %.c, $(sort $(C_SRCS))) analyze_plists = $(analyze_srcs:%.c=%.plist) .PHONY: all scan install clean cppcheck distclean debug asanaddress asanthread leak gcov all: $(NAME) debug: CFLAGS += -g -DDEBUG debug: DBG-$(NAME) asanaddress: CFLAGS += -g -DDEBUG -fsanitize=address -fno-omit-frame-pointer asanaddress: LDFLAGS += -fsanitize=address asanaddress: DBG-$(NAME) asanthread: CFLAGS += -g -DDEBUG -fsanitize=thread -fno-omit-frame-pointer asanthread: LDFLAGS += -fsanitize=thread asanthread: DBG-$(NAME) leak: CFLAGS += -g -DDEBUG -fsanitize=leak -fno-omit-frame-pointer leak: LDFLAGS += -fsanitize=leak leak: DBG-$(NAME) # Compile for the use of GCOV # Usage after compilation: gcov .c gcov: CFLAGS += -g -DDEBUG -fprofile-arcs -ftest-coverage gcov: LDFLAGS += -fprofile-arcs gcov: DBG-$(NAME) ############################################################################### # # Build the library # ############################################################################## $(NAME): $(OBJS) $(CC) -o $(NAME) $(OBJS) $(LDFLAGS) $(STRIP) $(NAME) DBG-$(NAME): $(OBJS) $(CC) -g -DDEBUG -o $(NAME) $(OBJS) $(LDFLAGS) $(analyze_plists): %.plist: %.c @echo " CCSA " $@ clang --analyze $(CFLAGS) $< -o $@ scan: $(analyze_plists) cppcheck: cppcheck --force -q --enable=performance --enable=warning --enable=portability *.h *.c ../lib/*.c ../lib/*.h asm: $(foreach b, $(C_SRCS), $(CC) $(CFLAGS) -S -fverbose-asm -o ${b:.c=.s} $(b);) install: install -m 0755 $(NAME) -D -t $(DESTDIR)$(BINDIR)/ ############################################################################### # # Clean # ############################################################################### clean: @- $(RM) $(OBJS) @- $(RM) $(NAME) @- $(RM) $(C_GCOV) @- $(RM) *.gcov @- $(RM) $(analyze_plists) distclean: clean ############################################################################### # # Show variables # ############################################################################### show_vars: @echo APPVERSION=$(APPVERSION) @echo DESTDIR=$(DESTDIR) @echo BINDIR=$(BINDIR) @echo LIBDIR=$(LIBDIR) @echo USRLIBDIR=$(USRLIBDIR) @echo BUILDFOR=$(BUILDFOR) @echo NAME=$(NAME) @echo LDFLAGS=$(LDFLAGS) @echo CFLAGS=$(CFLAGS) jitterentropy-library-3.6.3/tests/gcd/gcd.c000066400000000000000000000040051500137124500207040ustar00rootroot00000000000000/* * Copyright (C) 2021 - 2025, Stephan Mueller * * License: see LICENSE file in root directory * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH * DAMAGE. */ #include #include #include #include "jitterentropy-gcd.h" #define MAJVERSION 0 /* API / ABI incompatible changes, * functional changes that require consumer * to be updated (as long as this number is * zero, the API is not considered stable * and can change without a bump of the * major version). */ #define MINVERSION 1 /* API compatible, ABI may change, * functional enhancements only, consumer * can be left unchanged if enhancements are * not considered. */ #define PATCHLEVEL 0 /* API / ABI compatible, no functional * changes, no enhancements, bug fixes * only. */ #define ELEM 1000 #define EXP_GCD 50ULL int main(int argc, char *argv[]) { uint64_t *gcd = jent_gcd_init(ELEM); uint64_t val; unsigned int i; /* * Assumed over sampling rate. Equal to the default over sampling rate. */ const size_t osr = JENT_MIN_OSR; (void)argc; (void)argv; for (i = 0; i < ELEM; i++) jent_gcd_add_value(gcd, i * EXP_GCD, i); if (jent_gcd_analyze(gcd, ELEM, osr)) return 1; jent_gcd_fini(gcd, ELEM); if (jent_gcd_get(&val)) return 2; if (val != EXP_GCD) return 3; return 0; } jitterentropy-library-3.6.3/tests/raw-entropy/000077500000000000000000000000001500137124500215365ustar00rootroot00000000000000jitterentropy-library-3.6.3/tests/raw-entropy/README.md000066400000000000000000000174211500137124500230220ustar00rootroot00000000000000# Jitter RNG SP800-90B Entropy Analysis Tool This archive contains the SP800-90B analysis tool to be used for the Jitter RNG. The tool set consists of the following individual tools: - `recording_kernelspace`: This tool is used to gather the raw entropy of the Linux kernel space Jitter RNG. - `recording_userspace`: This tools is used to gather the raw entropy of the user space Jitter RNG implementation. - `validation-runtime`: This tool is used to calculate the minimum entropy values compliant to SP800-90B section 3.1.3. - `validation-restart`: This tool is used to calculate the minimum entropy values for the restart test compliant to SP800-90B section 3.1.4 See the README files in the different subdirectories. # Interpretation of Results ## Runtime Tests The result of the data analysis performed with `validation-runtime` contains in the file `jent-raw-noise-0001.minentropy_FF_8bits.var.txt` at the bottom data like the following: ``` H_original: 2.387470 H_bitstring: 0.337104 min(H_original, 8 X H_bitstring): 2.387470 ``` The last value gives you the entropy estimate per time delta. That means for one time delta the given number of entropy in bits is collected on average. Per default, the Jitter RNG heuristic applies 1/3 bit of entropy per time delta. This implies that the measurement must show that *at least* 1/3 bit of entropy is present. In the example above, the measurement shows that 2.3 bits of entropy is present which implies that the available amount of entropy is more than what the Jitter RNG heuristic applies. ## Restart Tests The results of the restart tests obtained with `validation-restart` contains in the file `jent-raw-noise-restart-consolidated.minentropy_FF_8bits.var.txt` at the bottom data like the following: ``` H_r: 0.545707 H_c: 1.363697 H_I: 0.333000 Validation Test Passed... min(H_r, H_c, H_I): 0.333000 ``` The last value gives you the entropy estimate per time delta for the restart tests. That means for one time delta the given number of entropy in bits collected on average. Per default, the Jitter RNG heuristic applies 1/3 bit of entropy per time delta. This implies that the measurement must show that 1/3 bit of entropy is present. Unlike with the runtime tests, the restart tests results compares the data against the Jitter RNG's H_I value of 1/3 bits. Thus, the value must show 1/3 bits to show that sufficient entropy is provided. In the example above, the measurement shows that 1/3 bits of entropy is present which implies that the available amount of entropy is more than what the Jitter RNG heuristic applies. # Approach to Solve Insufficient Entropy The Jitter RNG does not need any specific configurations or settings. However, in case your entropy assessment shows that insufficient entropy is present (e.g. by showing that the measured entropy rate is less than 1/3), you can perform a search whether different memory access values gives better entropy. ## Tool for Searching for More Entropy It is possible that the the default setting of the Jitter RNG does not deliver sufficient entropy. It is possible to adjust the memory access part of the Jitter RNG which may deliver more entropy. To support analysis of insufficient entropy, the following tools are provided. The goal of those test tools is to detect the proper memory setting that is appropriate for your environment. One memory setting consists of two values, one for the number of memory blocks and one for the memory block size. - `recording_userspace/analyze_options.sh`: This tool generates a large number of different test results for different settings for the memory access. Simply execute the tool without any options. A large set of different test results directories are created. - `validation-runtime/analyze_options.sh`: This tool analyzes all test results directories created by the `recording_userspace/analyze_options.sh` for the runtime data. It generates an overview file with all test results in `results-runtime-multi`. Analyze it and extract the memory access settings that gives you the intended entropy rate. - `validation-restart/analyze_options.sh`: This tool analyzes all test results directories created by the `recording_userspace/analyze_options.sh` for the restart data. It generates an overview file with all test results in `results-restart-multi`. Analyze it and extract the memory access settings that gives you the intended entropy rate. After you concluded the testing you have 2 memory settings that should be appropriate for you. As you need exactly one memory setting, analyze again the results to detect the memory setting that gives suitable entropy rates for both, the runtime and restart tests. Once you found the suitable memory setting, compile the Jitter RNG library with the following defines: `CFLAGS="-DJENT_MEMORY_BLOCKS= -DJENT_MEMORY_BLOCKSIZE="` ### Example - JENT_RANDOM_MEMACCESS not defined For example, the test returns the following data (this list is truncated) ``` Number of blocks Blocksize min entropy 64 32 0.542445 64 64 0.232963 64 128 0.232486 64 256 0.231005 64 512 0.401778 64 1024 0.326805 64 2048 0.319931 64 4096 0.225761 64 8192 0.220877 64 16384 0.330431 128 32 0.069033 128 64 0.068805 128 128 0.221863 ... ``` You now conclude that the following line is good for you: ``` 64 512 0.401778 ``` This now implies that your CFLAGS setting for compiling the Jitter RNG is `CFLAGS="-DJENT_MEMORY_BLOCKS=64 -DJENT_MEMORY_BLOCKSIZE=512"` Note, the Jitter RNG will allocate JENT_MEMORY_BLOCKS * JENT_MEMORY_BLOCKSIZE bytes for its memory access operation. ### Example - JENT_RANDOM_MEMACCESS defined For example, the test returns the following data ``` Number of bits min entropy 10 0.406505 11 0.445082 12 0.402972 13 0.459021 14 0.436911 15 0.578995 16 0.643272 17 0.573532 18 0.627915 19 0.503923 20 0.720609 21 1.871527 22 2.491569 23 2.481533 24 2.493987 25 2.491303 26 2.495017 ``` This stack tells you in the first column the actual amount of memory requested to be allocated by the Jitter RNG for the memory access in powers of 2 (Note, this amount is limited by the CPU's data cache size.). The second column is what you can ignore for this test. You now conclude that the following line is good for you because the measurement shows that about 1 bit of entropy per Jitter RNG time delta is received. This is compared with the Jitter RNG internally applied entropy rate of 1/3 bits of entropy per time delta which means that the Jitter RNG heuristics underestimates the available entropy - which is the result you want. ``` 21 1.871527 ``` This value means that the allocated memory is 2^21 = 2MBytes. You now have two options how to apply this value: either recompiling the library and use this value as the default allocation or use it as a flags field when allocating your Jitter RNG instance which does not need to change the binary. When recompiling, you need to apply the value `21` with your CFLAGS setting for compiling the Jitter RNG like this: `CFLAGS="-DJENT_MEMORY_BITS=21"` When using the value to allocate the Jitter RNG instance when you did not recompile the library code you specify this value when invoking `jent_entropy_init_ex` and `jent_entropy_collector_alloc` by adding the following to your flags field: ``` unsigned int flags = 0; ... flags |= JENT_MAX_MEMSIZE_2MB; ret = jent_entropy_init_ex(0, flags); ... ret = jent_entropy_collector_alloc(0, flags); ... ``` Note, the Jitter RNG will allocate 1 << JENT_MEMORY_BITS bytes for its memory access operation, but at most what jent_cache_size_roundup() returns. # Author Stephan Mueller jitterentropy-library-3.6.3/tests/raw-entropy/recording_restart_kernelspace/000077500000000000000000000000001500137124500276325ustar00rootroot00000000000000jitterentropy-library-3.6.3/tests/raw-entropy/recording_restart_kernelspace/README.md000066400000000000000000000013101500137124500311040ustar00rootroot00000000000000# Tests of Entropy during early boot This test collects the first 1,001 entropy event values generated during boot of the Linux kernel. The collection of raw entropy after reboot is compliant to SP800-90B section 3.1.4. The test infrastructure sets the Linux system up to reboot the system some 1,000 times to collect these 1,001 event values. # Test procedure See boottime_test_record.sh. The result is a matrix where on each line the 1,001 successive time stamps of the interrupts for one boot operation are recorded. The number of lines equals to the number of reboots. # Test analysis Copy the obtained output file into results and process the result by invoking validation-restart-*/processdata.sh. boottime_test_record.service000066400000000000000000000003701500137124500353540ustar00rootroot00000000000000jitterentropy-library-3.6.3/tests/raw-entropy/recording_restart_kernelspace# Systemd configuration file # [Unit] Description=Boot time test for Kernel Jitter RNG DefaultDependencies=no After=local-fs.target Before=sysinit.target [Service] ExecStart=/usr/local/sbin/boottime_test_record.sh [Install] WantedBy=basic.target jitterentropy-library-3.6.3/tests/raw-entropy/recording_restart_kernelspace/boottime_test_record.sh000077500000000000000000000074231500137124500344160ustar00rootroot00000000000000#!/bin/bash # # Copyright (C) 2023 - 2025, Stephan Mueller # # Test for analyzing the boot time entropy by power cycling the test machine # many times and record the first time stamps. # # Test execution: # 1. Enable kernel option `CONFIG_CRYPTO_JITTERENTROPY_TESTINTERFACE`, # enable configuration option `CONFIG_CRYPTO_USER_API_RNG`, # compile, install and reboot the kernel, and ensure that the # Linux kernel command line contains # `jitterentropy_rng.boot_raw_hires_test=1` # 2. Compile getrawentropy.c and install into /usr/local/sbin # 3. Copy this file to /usr/local/sbin and make it executable and do not # forget restorecon if applicable # 4. Copy boottime_test_record.service to /etc/systemd/system/ # 5. systemctl enable boottime_test_record # 6. reboot and wait until reboot test completes # 7. Pick up $OUTFILE and analyze # # If you want to restart the test, do: # 1. Clean out $OUTFILE # 2. start with step 4 from above # # Test interruption: # Boot with kernel command line option of boottime_test_stop. After this # interruption, the next reboot will continue collecting data for this # test. The interruption does not affect the test data. # OUTFILE="/root/jent_raw_noise_restart" STATE="/root/jent_state" TESTS=1000 # Location of libkcapi helper tool KCAPIRNG=/usr/bin/kcapi-rng DIR=$(dirname $OUTFILE) if [ ! -d "$DIR" ] then mkdir -p $DIR fi #testruns=$(ls $OUTFILE* | wc -l | cut -d" " -f1) testruns=$(cat $STATE) echo $((testruns+1)) > $STATE #add leading zeros # If leading zeros are missing, execute: # for i in jent_raw_noise_restart.?.data; do mv $i $(echo $i | cut -d. -f1).0000$(echo $i | cut -d. -f2).$(echo $i | cut -d. -f3) ; done # for i in jent_raw_noise_restart.??.data; do mv $i $(echo $i | cut -d. -f1).000$(echo $i | cut -d. -f2).$(echo $i | cut -d. -f3) ; done # for i in jent_raw_noise_restart.???.data; do mv $i $(echo $i | cut -d. -f1).00$(echo $i | cut -d. -f2).$(echo $i | cut -d. -f3) ; done # for i in jent_raw_noise_restart.????.data; do mv $i $(echo $i | cut -d. -f1).0$(echo $i | cut -d. -f2).$(echo $i | cut -d. -f3) ; done printf -v testruns "%05d" $testruns if [ ! -x "$KCAPIRNG" ] then echo "Test tool $KCAPIRNG not found" > $OUTFILE.$testruns.data echo "Test tool $KCAPIRNG not found" testruns=$TESTS else ( ( /usr/local/sbin/getrawentropy -f /sys/kernel/debug/jitterentropy_testing/jent_raw_hires -s 1001 > $OUTFILE.$testruns.data ) & ) $KCAPIRNG -n "jitterentropy_rng" -b 2000 fi testruns=$((testruns+1)) if [ $testruns -ge $TESTS ]; then systemctl stop boottime_test_record systemctl disable boottime_test_record uname -a > /root/platform.txt && cat /proc/cpuinfo >> /root/platform.txt && echo "" >> /root/platform.txt && cat /proc/cpuinfo >> /root/platform.txt && echo "" >> /root/platform.txt && echo "lspci" >> /root/platform.txt && lspci -vvv >> /root/platform.txt exit 0 fi if (cat /proc/cmdline | grep -q boottime_test_stop) ; then exit 0 fi # cannot kexec in VM (corruptions) # Here's the snipped to run the VM: # kvm -k de -vga vmware -usbdevice tablet -name bootloop -m 768 -smp 2 \ # -net nic,model=e1000,macaddr=00:50:45:00:34:0F -net user,hostfwd=tcp:127.0.0.1:24-:22 # -drive file=/vm-image-bootlooptests.img,format=raw,cache=writeback -boot c # mount -t proc proc /proc > /dev/null 2>&1 if ! grep hypervisor /proc/cpuinfo > /dev/null 2>&1 ; then if [ -f /boot/vmlinuz -a -f /boot/initrd ]; then e=$( cat /proc/cmdline) kexec -l /boot/vmlinuz --initrd=/boot/initrd --append="$e" fi fi # With kernel 4.9, the reboot may corrupt the file system. # Hence, the following lines. # Note, however, that it may be neccessary to enforce disc scan with outomatic repair on every reboot. sync ; sync mount -o remount,ro / # kexec will only return upon error, like if not set up or fail of set up. kexec -e reboot -f jitterentropy-library-3.6.3/tests/raw-entropy/recording_restart_kernelspace/install.sh000077500000000000000000000012411500137124500316350ustar00rootroot00000000000000#!/bin/bash # Install the linux kernel and the service running the boottime test # Note: restorecon is needed for Fedora if [ ! -x /usr/local/sbin/getrawentropy ]; then echo "getrawentropy must be installed in /usr/local/sbin" exit 1 fi cp boottime_test_record.sh /usr/local/sbin/ && chmod u+x /usr/local/sbin/boottime_test_record.sh && cp boottime_test_record.service /etc/systemd/system/ && systemctl enable boottime_test_record && restorecon -v -R / echo "To improve the reboot speed change the timeout in /etc/default/grub as follows" echo "GRUB_TIMEOUT=1" echo "Then run grub2-mkconfig to update the grub configuration file for the new setting to take effect." jitterentropy-library-3.6.3/tests/raw-entropy/recording_runtime_kernelspace/000077500000000000000000000000001500137124500276315ustar00rootroot00000000000000jitterentropy-library-3.6.3/tests/raw-entropy/recording_runtime_kernelspace/LICENSE000066400000000000000000000033651500137124500306450ustar00rootroot00000000000000Copyright (C) 2016 - 2025, Stephan Mueller Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, and the entire permission notice in its entirety, including the disclaimer of warranties. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. ALTERNATIVELY, this product may be distributed under the terms of the GNU General Public License, in which case the provisions of the GPL2 are required INSTEAD OF the above restrictions. (This clause is necessary due to a potential bad interaction between the GPL and the restrictions contained in a BSD-style copyright.) THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. jitterentropy-library-3.6.3/tests/raw-entropy/recording_runtime_kernelspace/LICENSE.bsd000066400000000000000000000025461500137124500314140ustar00rootroot00000000000000Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. jitterentropy-library-3.6.3/tests/raw-entropy/recording_runtime_kernelspace/LICENSE.gplv2000066400000000000000000000431331500137124500316730ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) 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 this service 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 make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. 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. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), 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 distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the 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 a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE 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. 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 convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 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 2 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, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision 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, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This 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 Library General Public License instead of this License. jitterentropy-library-3.6.3/tests/raw-entropy/recording_runtime_kernelspace/README.md000066400000000000000000000027321500137124500311140ustar00rootroot00000000000000# Obtain Raw Noise Data This tool offers the collection of raw entropy from the running Linux kernel Jitter RNG, compliant to SP800-90B section 3.1.3 To obtain raw noise data from the Jitter RNG, follow these steps: 1. Ensure patch providing kernel Jitter RNG test interface is applied, select `CONFIG_CRYPTO_JITTERENTROPY_TESTINTERFACE`, compile, install and reboot the kernel - if you want to stimulate the generation of entropy with the command below, ensure the kernel option `CONFIG_CRYPTO_USER_API_RNG` is set to `m` or `y`. 2. Compile getrawentropy.c as documented in that file. NOTE: Starting from 6.13, the data size storing raw entropy has changed from `u32` to `u64` in the kernel (see `crypto/jitterentropy-testing.c` and check the data type of the variable `jent_testing_rb`). When the data type is set to `u64` you MUST compile the tool with `-DRAW_DATATYPE_U64`. 3. Execute as root to obtain the raw entropy data: `getrawentropy -f /sys/kernel/debug/jitterentropy_testing/jent_raw_hires -s 1000001 > /dev/shm/jent_raw_noise.data` 4. In parallel to step 3, stimulate the generation of entropy, e.g. by using the following command with a tool from libkcapi using the following command `kcapi-rng -n "jitterentropy_rng" -b 2000000 > /dev/null` 5. Process the obtained data with validation-runtime-kernel/processdata.sh NOTE: The generated output is already in the correct format for processdata.sh and does not need to be converted any more. jitterentropy-library-3.6.3/tests/raw-entropy/recording_runtime_kernelspace/attic/000077500000000000000000000000001500137124500307355ustar00rootroot00000000000000jitterentropy-library-3.6.3/tests/raw-entropy/recording_runtime_kernelspace/attic/Makefile.foldtime000066400000000000000000000015121500137124500341760ustar00rootroot00000000000000# Compile Noise Source as user space application CC ?= gcc override CFLAGS +=-pedantic -Wall -Wextra -DROUNDS=100000000 -O0 -Wno-long-long program_NAME := jitterentropy-kernel-foldtime #program_C_SRCS := $(wildcard *.c) program_C_SRCS := jitterentropy-foldtime.c program_C_OBJS := ${program_C_SRCS:.c=.o} program_OBJS := $(program_C_OBJS) program_INCLUDE_DIRS := program_LIBRARY_DIRS := program_LIBRARIES := rt CPPFLAGS += $(foreach includedir,$(program_INCLUDE_DIRS),-I$(includedir)) LDFLAGS += $(foreach librarydir,$(program_LIBRARY_DIRS),-L$(librarydir)) LDFLAGS += $(foreach library,$(program_LIBRARIES),-l$(library)) .PHONY: all clean distclean all: $(program_NAME) $(program_NAME): $(program_OBJS) $(CC) $(program_OBJS) -o $(program_NAME) $(LDFLAGS) clean: @- $(RM) $(program_NAME) @- $(RM) $(program_OBJS) distclean: clean jitterentropy-library-3.6.3/tests/raw-entropy/recording_runtime_kernelspace/attic/Makefile.lfsrtime000066400000000000000000000015121500137124500342200ustar00rootroot00000000000000# Compile Noise Source as user space application CC ?= gcc override CFLAGS +=-pedantic -Wall -Wextra -DROUNDS=100000000 -O0 -Wno-long-long program_NAME := jitterentropy-kernel-lfsrtime #program_C_SRCS := $(wildcard *.c) program_C_SRCS := jitterentropy-lfsrtime.c program_C_OBJS := ${program_C_SRCS:.c=.o} program_OBJS := $(program_C_OBJS) program_INCLUDE_DIRS := program_LIBRARY_DIRS := program_LIBRARIES := rt CPPFLAGS += $(foreach includedir,$(program_INCLUDE_DIRS),-I$(includedir)) LDFLAGS += $(foreach librarydir,$(program_LIBRARY_DIRS),-L$(librarydir)) LDFLAGS += $(foreach library,$(program_LIBRARIES),-l$(library)) .PHONY: all clean distclean all: $(program_NAME) $(program_NAME): $(program_OBJS) $(CC) $(program_OBJS) -o $(program_NAME) $(LDFLAGS) clean: @- $(RM) $(program_NAME) @- $(RM) $(program_OBJS) distclean: clean jitterentropy-library-3.6.3/tests/raw-entropy/recording_runtime_kernelspace/attic/README.md000066400000000000000000000042161500137124500322170ustar00rootroot00000000000000# Jitter RNG Kernel Space SP800-90B Data Collector This tool collects the raw data used for SP800-90B analysis. I.e. the collected raw entropy data is obtained before any post processing. The collected data is simply the execution time of the functions jent_memaccess and jent_lfsrtime which both are the heart of the Jitter RNG. The reader should understand that additional functions in the Jitter RNG contribute to the entropy. However, this collection tool disregards them which implies that the analysis tool already applies a worst case analysis. ## Test Implementations The following test implementations are available: - `Makefile.foldtime`: This tool is used for Linux kernels <= 5.1 - `Makefile.lfsrtime`: This tools is used for Linux kernel > 5.1 ## Getting Started When standard testing shall be performed, the collection of raw entropy is performed with the script `invoke_testing.sh`. Before executing the script, the following files from the used Jitter RNG noise source shall be copied into this directory: * crypto/jitterentropy.c The results are stored in `../results-measurements` which then needs to be processed with the `validation` and `validation-restart` logic. Please see the caveats for obtaining Jitter RNG output below. ## Obtain Raw Entropy To use the data collection tool, follow these steps: 1. Copy the file crypto/jitterentropy.c from the kernel code into this directory. 2. Compile the code with the available Makefile 3. Execute the test and collect the output `./jitterentropy-kernel-lfsrtime > ../validation/jent-raw-noise.data` or `./jitterentropy-kernel-foldtime > ../validation/jent-raw-noise.data` 4. Analyze the output with the code in the validation directory # Obtain Jitter RNG Output To generate Jitter RNG output, the Linux kernel AF_ALG interface can be used. This implies that the kcapi-rng tool from [1] must be present. The following invocation provides the Jitter RNG output for further analysis: `kcapi-rng -n "jitterentropy_rng" -b ` Analyze the output with the code in the validation directory. [1] https://www.chronox.de/libkcapi.html # Author Stephan Mueller jitterentropy-library-3.6.3/tests/raw-entropy/recording_runtime_kernelspace/attic/invoke_testing.sh000077500000000000000000000030571500137124500343310ustar00rootroot00000000000000#!/bin/bash # Directory where to store the measurements OUTDIR="../results-measurements" # Maximum number of entries to be extracted from the original file NUM_EVENTS=1000000 # Number of restart tests NUM_EVENTS_RESTART=1000 NUM_RESTART=1000 NONIID_RESTART_DATA="jent-raw-noise-restart" NONIID_DATA="jent-raw-noise" IID_DATA="jent-conditioned.data" initialization() { if [ ! -d $OUTDIR ] then mkdir $OUTDIR if [ $? -ne 0 ] then echo "Creation of $OUTDIR failed" exit 1 fi fi trap "make -s -f Makefile.lfsrtime clean; exit" 0 1 2 3 15 } lfsroutput() { echo "Obtaining $NUM_EVENTS blocks of output from Jitter RNG" local kcapi="/usr/bin/kcapi-rng" if [ ! -x "${kcapi}" ] then kcapi="/usr/local/bin/kcapi-rng" fi if [ ! -x "${kcapi}" ] then echo "Application kcapi-rng does not exist - this is needed to obtain the LFSR output data on the current system" return fi local bytes=$(($NUM_EVENTS*8)) ${kcapi} -n "jitterentropy_rng" -b $bytes > $OUTDIR/$IID_DATA } raw_entropy_restart() { echo "Obtaining $NUM_RESTART raw entropy measurement with $NUM_EVENTS_RESTART restarts from Jitter RNG" make -s -f Makefile.lfsrtime ./jitterentropy-kernel-lfsrtime $NUM_EVENTS_RESTART $NUM_RESTART $OUTDIR/$NONIID_RESTART_DATA make -s -f Makefile.lfsrtime clean } raw_entropy() { echo "Obtaining $NUM_EVENTS raw entropy measurement from Jitter RNG" make -s -f Makefile.lfsrtime ./jitterentropy-kernel-lfsrtime $NUM_EVENTS 1 $OUTDIR/$NONIID_DATA make -s -f Makefile.lfsrtime clean } initialization lfsroutput raw_entropy raw_entropy_restart jitterentropy-foldtime.c000066400000000000000000000126261500137124500355540ustar00rootroot00000000000000jitterentropy-library-3.6.3/tests/raw-entropy/recording_runtime_kernelspace/attic/* * Copyright (C) 2019 - 2025, Stephan Mueller * * License: see LICENSE file in root directory * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH * DAMAGE. */ #include #include #include #include #include #include #ifdef __MACH__ #include #include #include #include #include #endif #undef NULL typedef unsigned long long __u64; /*************************************************************************** * Link code for user space ***************************************************************************/ __u64 jent_rol64(__u64 word, unsigned int shift) { return (word << shift) | (word >> (64 - shift)); } void *jent_zalloc(unsigned int len) { return calloc(1, len); } void jent_zfree(void *ptr) { free(ptr); } int jent_fips_enabled(void) { return 1; } void jent_panic(char *s) { printf("%s", s); exit(1); } void jent_memcpy(void *dest, const void *src, unsigned int n) { memcpy(dest, src, n); } /* taken from Linux kernel */ #ifdef X86_64 #define DECLARE_ARGS(val, low, high) unsigned low, high #define EAX_EDX_VAL(val, low, high) ((low) | ((__u64)(high) << 32)) #define EAX_EDX_RET(val, low, high) "=a" (low), "=d" (high) #else #define DECLARE_ARGS(val, low, high) unsigned long long val #define EAX_EDX_VAL(val, low, high) (val) #define EAX_EDX_RET(val, low, high) "=A" (val) #endif /* * Obtain a high-resolution time stamp value. The time stamp is used to measure * the execution time of a given code path and its variations. Hence, the time * stamp must have a sufficiently high resolution. * * Note, if the function returns zero because a given architecture does not * implement a high-resolution time stamp, the RNG code's runtime test * will detect it and will not produce output. */ void jent_get_nstime(__u64 *out) { /* OSX does not have clock_gettime -- taken from * http://developer.apple.com/library/mac/qa/qa1398/_index.html */ #ifdef __MACH__ *out = mach_absolute_time(); #elif _AIX /* clock_gettime() on AIX returns a timer value that increments in * steps of 1000 */ uint64_t tmp = 0; timebasestruct_t aixtime; read_real_time(&aixtime, TIMEBASE_SZ); tmp = aixtime.tb_high; tmp = tmp << 32; tmp = tmp | aixtime.tb_low; *out = tmp; #elif (defined(__i386__) || defined(__x86_64__)) DECLARE_ARGS(val, low, high); __asm__ __volatile__("rdtsc" : EAX_EDX_RET(val, low, high)); *out = EAX_EDX_VAL(val, low, high); #else /* we could use CLOCK_MONOTONIC(_RAW), but with CLOCK_REALTIME * we get some nice extra entropy once in a while from the NTP actions * that we want to use as well... though, we do not rely on that * extra little entropy */ uint64_t tmp = 0; struct timespec time; if (clock_gettime(CLOCK_REALTIME, &time) == 0) { tmp = time.tv_sec; tmp = tmp << 32; tmp = tmp | time.tv_nsec; } *out = tmp; #endif } /*************************************************************************** * Include Jitter RNG code ***************************************************************************/ #include "jitterentropy.c" /*************************************************************************** * Statistical test logic not compiled for regular operation ***************************************************************************/ /* * Statistical test: return the time duration for the folding operation. If min * is set, perform the given number of LFSR ops. Otherwise, allow the * loop count shuffling to define the number of LFSR ops. */ static uint64_t jent_fold_var_stat(struct rand_data *ec, unsigned int min) { __u64 time = 0; __u64 time2 = 0; __u64 data = 0; jent_get_nstime(&time); jent_memaccess(ec, min); jent_fold_time(ec, time, &data, min); jent_get_nstime(&time2); return ((time2 - time)); } int main(int argc, char *argv[]) { (void)argc; (void)argv; #ifdef ROUNDS size_t size = 0; struct rand_data *ec; ec = jent_entropy_collector_alloc(0, 0); if(!ec) return 1; while(size < ROUNDS) #else while(1) #endif { uint64_t duration = 0; uint64_t duration_min = 0; /* When enabling the for loops, you effectively get a cache * and TLB flush -- but tests show that flushing the cache * does not change the results, considering that you want to * remove the outliers from the dataset before processing it * as you do not want to have measurements based interferred * by interrupts, etc. */ /* int i = 0; for(i=0; i<1000; i++) */ /* mb(); */ duration = jent_fold_var_stat(ec, 0); /* mb(); */ /* for(i=0; i<1000; i++) */ duration_min = jent_fold_var_stat(ec, 1); /* mb(); */ printf("%lu %lu\n", duration, duration_min); #ifdef ROUNDS size++; #endif } return 0; } jitterentropy-lfsrtime.c000066400000000000000000000137431500137124500355770ustar00rootroot00000000000000jitterentropy-library-3.6.3/tests/raw-entropy/recording_runtime_kernelspace/attic/* * Copyright (C) 2019 - 2025, Stephan Mueller * * License: see LICENSE file in root directory * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH * DAMAGE. */ #include #include #include #include #include #include #include #ifdef __MACH__ #include #include #include #include #include #endif #undef NULL typedef unsigned long long __u64; /*************************************************************************** * Link code for user space ***************************************************************************/ void *jent_zalloc(unsigned int len) { return calloc(1, len); } void jent_zfree(void *ptr) { free(ptr); } int jent_fips_enabled(void) { /* Enable full SP800-90B health test handling */ return 1; } void jent_panic(char *s) { printf("%s", s); exit(1); } void jent_memcpy(void *dest, const void *src, unsigned int n) { memcpy(dest, src, n); } /* taken from Linux kernel */ #ifdef X86_64 #define DECLARE_ARGS(val, low, high) unsigned low, high #define EAX_EDX_VAL(val, low, high) ((low) | ((__u64)(high) << 32)) #define EAX_EDX_RET(val, low, high) "=a" (low), "=d" (high) #else #define DECLARE_ARGS(val, low, high) unsigned long long val #define EAX_EDX_VAL(val, low, high) (val) #define EAX_EDX_RET(val, low, high) "=A" (val) #endif /* * Obtain a high-resolution time stamp value. The time stamp is used to measure * the execution time of a given code path and its variations. Hence, the time * stamp must have a sufficiently high resolution. * * Note, if the function returns zero because a given architecture does not * implement a high-resolution time stamp, the RNG code's runtime test * will detect it and will not produce output. */ void jent_get_nstime(__u64 *out) { /* OSX does not have clock_gettime -- taken from * http://developer.apple.com/library/mac/qa/qa1398/_index.html */ #ifdef __MACH__ *out = mach_absolute_time(); #elif _AIX /* clock_gettime() on AIX returns a timer value that increments in * steps of 1000 */ uint64_t tmp = 0; timebasestruct_t aixtime; read_real_time(&aixtime, TIMEBASE_SZ); tmp = aixtime.tb_high; tmp = tmp << 32; tmp = tmp | aixtime.tb_low; *out = tmp; #elif (defined(__i386__) || defined(__x86_64__)) DECLARE_ARGS(val, low, high); __asm__ __volatile__("rdtsc" : EAX_EDX_RET(val, low, high)); *out = EAX_EDX_VAL(val, low, high); #else /* we could use CLOCK_MONOTONIC(_RAW), but with CLOCK_REALTIME * we get some nice extra entropy once in a while from the NTP actions * that we want to use as well... though, we do not rely on that * extra little entropy */ uint64_t tmp = 0; struct timespec time; if (clock_gettime(CLOCK_REALTIME, &time) == 0) { tmp = time.tv_sec; tmp = tmp << 32; tmp = tmp | time.tv_nsec; } *out = tmp; #endif } /*************************************************************************** * Include Jitter RNG code ***************************************************************************/ #include "jitterentropy.c" /*************************************************************************** * Statistical test logic not compiled for regular operation ***************************************************************************/ /* * Statistical test: return the time duration for the folding operation. If min * is set, perform the given number of LFSR ops. Otherwise, allow the * loop count shuffling to define the number of LFSR ops. */ static uint64_t jent_lfsr_var_stat(struct rand_data *ec, unsigned int min) { __u64 time = 0; __u64 time2 = 0; jent_get_nstime(&time); jent_memaccess(ec, min); jent_lfsr_time(ec, time, min, 0); jent_get_nstime(&time2); return ((time2 - time)); } static int jent_one_test(const char *pathname, unsigned long rounds) { unsigned long size = 0; struct rand_data *ec; FILE *out = NULL; int ret = 0; printf("Processing %s\n", pathname); out = fopen(pathname, "w"); if (!out) { ret = 1; goto out; } ec = jent_entropy_collector_alloc(0, 0); if(!ec) { ret = 1; goto out; } for (size = 0; size < rounds; size++) { uint64_t duration = 0; uint64_t duration_min = 0; duration = jent_lfsr_var_stat(ec, 0); duration_min = jent_lfsr_var_stat(ec, 1); fprintf(out, "%lu %lu\n", duration, duration_min); } out: if (out) fclose(out); return ret; } /* * Invoke the application with * argv[1]: number of raw entropy measurements to be obtained for one * entropy collector instance. * argv[2]: number of test repetitions with a new entropy estimator * allocated for each round - this satisfies the restart tests * defined in SP800-90B section 3.1.4.3 and FIPS IG 7.18. * argv[3]: File name of the output data */ int main(int argc, char * argv[]) { unsigned long i, rounds, repeats; int ret; char pathname[4096]; if (argc != 4) { printf("%s \n", argv[0]); return 1; } rounds = strtoul(argv[1], NULL, 10); if (rounds >= UINT_MAX) return 1; repeats = strtoul(argv[2], NULL, 10); if (repeats >= UINT_MAX) return 1; for (i = 1; i <= repeats; i++) { snprintf(pathname, sizeof(pathname), "%s-%.4lu.data", argv[3], i); ret = jent_one_test(pathname, rounds); if (ret) return ret; } return 0; } jitterentropy-library-3.6.3/tests/raw-entropy/recording_runtime_kernelspace/getrawentropy.c000066400000000000000000000073751500137124500327230ustar00rootroot00000000000000/* * Copyright (C) 2019 - 2025, Stephan Mueller * * License: see LICENSE file in root directory * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH * DAMAGE. */ /* * Compile: * gcc -Wall -pedantic -Wextra -o getrawentropy getrawentropy.c */ #include #include #include #include #include #include #include #include #include #include #include #include #define RAWENTROPY_SAMPLES 1000 #define DEBUGFS_INTERFACE "/sys/kernel/debug/jitterentropy_testing/jent_raw_hires" /* * Starting with Linux kernel version 6.13, the data size changed from u32 to * u64 (see crypto/jitterentropy-testing.c:jent_testing_rb). Therefore, starting * from this kernel onwards, this tool MUST be compiled with -DRAW_DATATYPE_U64. */ #ifdef RAW_DATATYPE_U64 #define DATASIZE sizeof(uint64_t) #define PR_DATATYPE PRIu64 typedef uint64_t lrngval_t; #else /* RAW_DATATYPE_U64 */ #define DATASIZE sizeof(uint32_t) #define PR_DATATYPE PRIu32 typedef uint32_t lrngval_t; #endif /* RAW_DATATYPE_U64 */ struct opts { size_t samples; char *debugfs_file; }; static int getrawentropy(struct opts *opts) { #define BUFFER_SIZE (RAWENTROPY_SAMPLES * DATASIZE) uint32_t requested = opts->samples * DATASIZE; lrngval_t leftover; uint8_t leftover_present = 0; uint8_t *buffer_p, buffer[BUFFER_SIZE]; ssize_t ret; int fd = -1; fd = open(opts->debugfs_file, O_RDONLY); if (fd < 0) return errno; while (requested) { unsigned int i; unsigned int gather = ((BUFFER_SIZE > (requested + DATASIZE)) ? (requested + DATASIZE) : BUFFER_SIZE); buffer_p = buffer; ret = read(fd, buffer_p, gather); if (ret < 0) { ret = -errno; goto out; } for (i = 0; i < ret / (DATASIZE); i++) { lrngval_t val; memcpy(&val, buffer_p, DATASIZE); if (leftover_present) { printf("%"PR_DATATYPE"\n", val - leftover); leftover = val; requested -= DATASIZE; if (requested == 0) break; } else { leftover = val; leftover_present = 1; } buffer_p += DATASIZE; } } ret = 0; out: if (fd >= 0) close(fd); return (int)ret; } int main(int argc, char *argv[]) { struct opts opts; int c = 0; opts.samples = RAWENTROPY_SAMPLES; opts.debugfs_file = DEBUGFS_INTERFACE; while (1) { int opt_index = 0; static struct option options[] = { {"samples", required_argument, 0, 's'}, {"debugfs-file", required_argument, 0, 'f'}, {0, 0, 0, 0} }; c = getopt_long(argc, argv, "f:s:", options, &opt_index); if (c == -1) break; switch (c) { case 0: switch (opt_index) { case 0: opts.samples = strtoul(optarg, NULL, 10); if (opts.samples == ULONG_MAX) return -EINVAL; break; case 1: opts.debugfs_file = optarg; break; } break; case 's': opts.samples = strtoul(optarg, NULL, 10); if (opts.samples == ULONG_MAX) return -EINVAL; break; case 'f': opts.debugfs_file = optarg; break; default: return -EINVAL; } } return getrawentropy(&opts); } jitterentropy-library-3.6.3/tests/raw-entropy/recording_userspace/000077500000000000000000000000001500137124500255645ustar00rootroot00000000000000jitterentropy-library-3.6.3/tests/raw-entropy/recording_userspace/CMakeLists.txt000066400000000000000000000015231500137124500303250ustar00rootroot00000000000000cmake_minimum_required(VERSION 3.14) project(jitterentropy C) set(CMAKE_C_STANDARD 99) function(testprogram name) add_executable(${name} ${name}.c) target_link_libraries(${name} ${PROJECT_NAME}) target_link_directories(${name} PUBLIC $) target_include_directories(${name} PUBLIC $ $) if(NOT MSVC) target_compile_options(${name} PRIVATE -fwrapv --param ssp-buffer-size=4 -fvisibility=hidden -Wcast-align -Wmissing-field-initializers -Wshadow -Wswitch-enum -Wextra -Wall -pedantic -O0 -fwrapv -Wconversion) endif() include(GNUInstallDirs) install(TARGETS ${name}) endfunction() testprogram(jitterentropy-hashtime) jitterentropy-library-3.6.3/tests/raw-entropy/recording_userspace/LICENSE000066400000000000000000000033651500137124500266000ustar00rootroot00000000000000Copyright (C) 2016 - 2025, Stephan Mueller Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, and the entire permission notice in its entirety, including the disclaimer of warranties. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. ALTERNATIVELY, this product may be distributed under the terms of the GNU General Public License, in which case the provisions of the GPL2 are required INSTEAD OF the above restrictions. (This clause is necessary due to a potential bad interaction between the GPL and the restrictions contained in a BSD-style copyright.) THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. jitterentropy-library-3.6.3/tests/raw-entropy/recording_userspace/LICENSE.bsd000066400000000000000000000025461500137124500273470ustar00rootroot00000000000000Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. jitterentropy-library-3.6.3/tests/raw-entropy/recording_userspace/LICENSE.gplv2000066400000000000000000000431331500137124500276260ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) 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 this service 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 make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. 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. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), 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 distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the 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 a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE 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. 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 convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 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 2 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, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision 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, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This 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 Library General Public License instead of this License. jitterentropy-library-3.6.3/tests/raw-entropy/recording_userspace/Makefile.foldtime000066400000000000000000000016721500137124500310340ustar00rootroot00000000000000# Compile Noise Source as user space application CC ?= gcc override CFLAGS +=-pedantic -Wall -DCONFIG_CRYPTO_CPU_JITTERENTROPY_STAT -DROUNDS=10000000 -I../../ -O0 -Wno-long-long program_NAME := jitterentropy-foldtime #program_C_SRCS := $(wildcard *.c) program_C_SRCS := jitterentropy-base.c jitterentropy-foldtime.c jitterentropy-stat.c program_C_OBJS := ${program_C_SRCS:.c=.o} program_OBJS := $(program_C_OBJS) program_INCLUDE_DIRS := program_LIBRARY_DIRS := ifneq (Darwin,$(shell uname)) program_LIBRARIES := rt endif CPPFLAGS += $(foreach includedir,$(program_INCLUDE_DIRS),-I$(includedir)) LDFLAGS += $(foreach librarydir,$(program_LIBRARY_DIRS),-L$(librarydir)) LDFLAGS += $(foreach library,$(program_LIBRARIES),-l$(library)) .PHONY: all clean distclean all: $(program_NAME) $(program_NAME): $(program_OBJS) $(CC) $(program_OBJS) -o $(program_NAME) $(LDFLAGS) clean: @- $(RM) $(program_NAME) @- $(RM) $(program_OBJS) distclean: clean jitterentropy-library-3.6.3/tests/raw-entropy/recording_userspace/Makefile.hashtime000066400000000000000000000033371500137124500310330ustar00rootroot00000000000000# Compile Noise Source as user space application CC ?= gcc CFLAGS +=-Wextra -Wall -pedantic -fPIC -O0 #Hardening CFLAGS +=-fwrapv --param ssp-buffer-size=4 -fvisibility=hidden -fPIE -Wcast-align -Wmissing-field-initializers -Wshadow -Wswitch-enum ifneq (Darwin,$(shell uname)) LDFLAGS +=-Wl,-z,relro,-z,now endif # Enable internal timer support CFLAGS += -DJENT_CONF_ENABLE_INTERNAL_TIMER GCCVERSIONFORMAT := $(shell echo `$(CC) -dumpversion | sed 's/\./\n/g' | wc -l`) ifeq "$(GCCVERSIONFORMAT)" "3" GCC_GTEQ_490 := $(shell expr `$(CC) -dumpversion | sed -e 's/\.\([0-9][0-9]\)/\1/g' -e 's/\.\([0-9]\)/0\1/g' -e 's/^[0-9]\{3,4\}$$/&00/'` \>= 40900) else GCC_GTEQ_490 := $(shell expr `$(CC) -dumpfullversion | sed -e 's/\.\([0-9][0-9]\)/\1/g' -e 's/\.\([0-9]\)/0\1/g' -e 's/^[0-9]\{3,4\}$$/&00/'` \>= 40900) endif ifeq "$(GCC_GTEQ_490)" "1" CFLAGS += -fstack-protector-strong else CFLAGS += -fstack-protector-all endif JENT_DIR := jitterentropy program_NAME := jitterentropy-hashtime #program_C_SRCS := $(wildcard *.c) program_C_SRCS := jitterentropy-hashtime.c program_C_OBJS := ${program_C_SRCS:.c=.o} program_OBJS := $(program_C_OBJS) program_INCLUDE_DIRS := $(JENT_DIR) $(JENT_DIR)/src program_LIBRARY_DIRS := ifeq (Darwin,$(shell uname)) program_LIBRARIES := pthread else program_LIBRARIES := rt pthread endif CPPFLAGS += $(foreach includedir,$(program_INCLUDE_DIRS),-I$(includedir)) LDFLAGS += $(foreach librarydir,$(program_LIBRARY_DIRS),-L$(librarydir)) LDFLAGS += $(foreach library,$(program_LIBRARIES),-l$(library)) .PHONY: all clean distclean all: $(program_NAME) $(program_NAME): $(program_OBJS) $(CC) $(program_OBJS) -o $(program_NAME) $(LDFLAGS) clean: @- $(RM) $(program_NAME) @- $(RM) $(program_OBJS) distclean: clean jitterentropy-library-3.6.3/tests/raw-entropy/recording_userspace/Makefile.lfsrtime000066400000000000000000000017721500137124500310570ustar00rootroot00000000000000# Compile Noise Source as user space application CC ?= gcc CFLAGS +=-Wextra -Wall -pedantic -fPIC -O0 #Hardening CFLAGS +=-fstack-protector-all -fwrapv --param ssp-buffer-size=4 ifneq (Darwin,$(shell uname)) LDFLAGS +=-Wl,-z,relro,-z,now endif program_NAME := jitterentropy-lfsrtime #program_C_SRCS := $(wildcard *.c) program_C_SRCS := jitterentropy-lfsrtime.c program_C_OBJS := ${program_C_SRCS:.c=.o} program_OBJS := $(program_C_OBJS) program_INCLUDE_DIRS := program_LIBRARY_DIRS := ifeq (Darwin,$(shell uname)) program_LIBRARIES := pthread else program_LIBRARIES := rt pthread endif CPPFLAGS += $(foreach includedir,$(program_INCLUDE_DIRS),-I$(includedir)) LDFLAGS += $(foreach librarydir,$(program_LIBRARY_DIRS),-L$(librarydir)) LDFLAGS += $(foreach library,$(program_LIBRARIES),-l$(library)) .PHONY: all clean distclean all: $(program_NAME) $(program_NAME): $(program_OBJS) $(CC) $(program_OBJS) -o $(program_NAME) $(LDFLAGS) clean: @- $(RM) $(program_NAME) @- $(RM) $(program_OBJS) distclean: clean jitterentropy-library-3.6.3/tests/raw-entropy/recording_userspace/Makefile.osr000066400000000000000000000025641500137124500300350ustar00rootroot00000000000000# Compile Noise Source as user space application CC ?= gcc CFLAGS +=-Wextra -Wall -pedantic -fPIC -O0 -DCONFIG_CRYPTO_CPU_JITTERENTROPY_SECURE_MEMORY #Hardening CFLAGS +=-fwrapv --param ssp-buffer-size=4 LDFLAGS +=-Wl,-z,relro,-z,now -lm GCCVERSIONFORMAT := $(shell echo `$(CC) -dumpversion | sed 's/\./\n/g' | wc -l`) ifeq "$(GCCVERSIONFORMAT)" "3" GCC_GTEQ_490 := $(shell expr `$(CC) -dumpversion | sed -e 's/\.\([0-9][0-9]\)/\1/g' -e 's/\.\([0-9]\)/0\1/g' -e 's/^[0-9]\{3,4\}$$/&00/'` \>= 40900) else GCC_GTEQ_490 := $(shell expr `$(CC) -dumpfullversion | sed -e 's/\.\([0-9][0-9]\)/\1/g' -e 's/\.\([0-9]\)/0\1/g' -e 's/^[0-9]\{3,4\}$$/&00/'` \>= 40900) endif ifeq "$(GCC_GTEQ_490)" "1" CFLAGS += -fstack-protector-strong else CFLAGS += -fstack-protector-all endif JENT_DIR := jitterentropy JENT_SRCS := $(wildcard $(JENT_DIR)/src/*.c) NAME := jitterentropy-osr C_SRCS := $(JENT_SRCS) jitterentropy-osr.c C_OBJS := ${C_SRCS:.c=.o} OBJS := $(C_OBJS) INCLUDE_DIRS := $(JENT_DIR) $(JENT_DIR)/src LIBRARY_DIRS := LIBRARIES := rt pthread CFLAGS += $(foreach includedir,$(INCLUDE_DIRS),-I$(includedir)) LDFLAGS += $(foreach librarydir,$(LIBRARY_DIRS),-L$(librarydir)) LDFLAGS += $(foreach library,$(LIBRARIES),-l$(library)) .PHONY: all clean distclean all: $(NAME) $(NAME): $(OBJS) $(CC) $(OBJS) -o $(NAME) $(LDFLAGS) clean: @- $(RM) $(NAME) @- $(RM) $(OBJS) distclean: clean jitterentropy-library-3.6.3/tests/raw-entropy/recording_userspace/Makefile.rng000066400000000000000000000026241500137124500300150ustar00rootroot00000000000000# Compile Noise Source as user space application CC ?= gcc CFLAGS +=-Wextra -Wall -pedantic -fPIC -O0 -DCONFIG_CRYPTO_CPU_JITTERENTROPY_SECURE_MEMORY #Hardening CFLAGS +=-fwrapv --param ssp-buffer-size=4 ifneq (Darwin,$(shell uname)) LDFLAGS +=-Wl,-z,relro,-z,now endif GCCVERSIONFORMAT := $(shell echo `$(CC) -dumpversion | sed 's/\./\n/g' | wc -l`) ifeq "$(GCCVERSIONFORMAT)" "3" GCC_GTEQ_490 := $(shell expr `$(CC) -dumpversion | sed -e 's/\.\([0-9][0-9]\)/\1/g' -e 's/\.\([0-9]\)/0\1/g' -e 's/^[0-9]\{3,4\}$$/&00/'` \>= 40900) else GCC_GTEQ_490 := $(shell expr `$(CC) -dumpfullversion | sed -e 's/\.\([0-9][0-9]\)/\1/g' -e 's/\.\([0-9]\)/0\1/g' -e 's/^[0-9]\{3,4\}$$/&00/'` \>= 40900) endif ifeq "$(GCC_GTEQ_490)" "1" CFLAGS += -fstack-protector-strong else CFLAGS += -fstack-protector-all endif JENT_DIR := jitterentropy JENT_SRCS := $(wildcard $(JENT_DIR)/src/*.c) NAME := jitterentropy-rng C_SRCS := $(JENT_SRCS) jitterentropy-rng.c C_OBJS := ${C_SRCS:.c=.o} OBJS := $(C_OBJS) INCLUDE_DIRS := $(JENT_DIR) $(JENT_DIR)/src LIBRARY_DIRS := LIBRARIES := rt pthread CFLAGS += $(foreach includedir,$(INCLUDE_DIRS),-I$(includedir)) LDFLAGS += $(foreach librarydir,$(LIBRARY_DIRS),-L$(librarydir)) LDFLAGS += $(foreach library,$(LIBRARIES),-l$(library)) .PHONY: all clean distclean all: $(NAME) $(NAME): $(OBJS) $(CC) $(OBJS) -o $(NAME) $(LDFLAGS) clean: @- $(RM) $(NAME) @- $(RM) $(OBJS) distclean: clean jitterentropy-library-3.6.3/tests/raw-entropy/recording_userspace/README.md000066400000000000000000000061621500137124500270500ustar00rootroot00000000000000# Linux Entropy Recording and Validation The test provided here is split into two aspects: the recording of the raw entropy data and the validation of the data. Both aspects are implemented with the code in the respective directories. The idea is that you give the recording directory to the customer so that he obtains the data. Once you receive the data, you process it with the code in the validation directory. ## Getting Started When standard testing shall be performed, the collection of raw entropy is performed with the script `invoke_testing.sh`. Before executing the script, the following files from the used Jitter RNG noise source shall be copied into this directory: * jitterentropy-base.c * jitterentropy.h * jitterentropy-base-user.h The results are stored in `../results-measurements` which then needs to be processed with the `validation-runtime` and `validation-restart` logic. ## Recording of Raw Entropy Data If the `invoke_testing.sh` is not helpful for performing the test, the following explanation outlines the specific test steps to be invoked manually. For recoding the raw entropic data, the user has to compile the code. To do that, he has to copy the following files into the recording directory prior compilation. These files are taken from his Jitter RNG implementation that he uses: * jitterentropy-base.c * jitterentropy.h * jitterentropy-base-user.h Depending on the version of the Jitter RNG, the following commands have to be invoked for compiling the test tool: * Jitter RNG 1.x and older: make -f Makefile.foldtime * Jitter RNG 2.x: make -f Makefile.lfsrtime * Jitter RNG 3.x: make -f Makefile.hashtime The test is now invoked with the following command: * Jitter RNG 1.x and older: ./jitterentropy-foldtime > /dev/shm/jent-raw.data * Jitter RNG 2.x: ./jitterentropy-lfsrtime > /dev/shm/jent-raw.data * Jitter RNG 3.x: ./jitterentropy-hashtime > /dev/shm/jent-raw.data In addition, the collection of output data from the Jitter RNG must be compiled with the following command: make -f Makefile.rng To generate output data from the Jitter RNG for validation, invoke: ./jitterentropy-rng 2> /dev/shm/jent.rngout The recording program collects two sets of sample of time deltas obtained from the Jitter RNG: * var: this is the normal behavior of the Jitter RNG. The time delta is not only used to feed the pool, but also to determine the number of LFSR operations (1 to 15 in the current configuration) that will be performed before returning each bit to the pool. The different number of cycles used on each bit produce variations in the memory access time, increasing the entropy of the noise source. * single: in this case, there is only one cycle of LFSR operations per bit. This is the worst case scenario forced by the recording program in order to have the lowest minimum entropy estimation. The program is compiled to collect two samples of 10000000 events each (see the ROUNDS parameter in Makefile). The file contains one line per item, each line contains two decimal numbers: the first is for the var noise source, the second for the single noise source. jitterentropy-library-3.6.3/tests/raw-entropy/recording_userspace/analyze_options.sh000077500000000000000000000017721500137124500313500ustar00rootroot00000000000000#!/bin/bash # # Tool to generate test results for various Jitter RNG memory settings # # This tool is only needed if you have insufficient entropy. See ../README.md # for details # OUTDIR="../results-measurements" if (grep JENT_RANDOM_MEMACCESS ../../../jitterentropy.h | head -n 1 | grep -q define) then for bits in 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 do export CFLAGS="-DJENT_MEMORY_BITS=$bits" ./invoke_testing.sh mv $OUTDIR $OUTDIR-random_memaccess-${bits}bits done else for memsize in 32768 65536 131072 262144 524288 1048576 2097152 4194304 8388608 16777216 33554432 67108864 134217728 268435456 536870912 do for blocks in 64 128 256 512 1024 2048 4096 8192 16384 do for blocksize in 32 64 128 256 512 1024 2048 4096 8192 16384 do export CFLAGS="-DJENT_MEMORY_BLOCKS=$blocks -DJENT_MEMORY_BLOCKSIZE=$blocksize -DJENT_MEMORY_SIZE=$memsize" ./invoke_testing.sh mv $OUTDIR $OUTDIR-${blocks}blocks-${blocksize}blocksize-${memsize}bytes done done done fi jitterentropy-library-3.6.3/tests/raw-entropy/recording_userspace/invoke_testing.sh000077500000000000000000000034731500137124500311620ustar00rootroot00000000000000#!/bin/bash # Directory where to store the measurements OUTDIR="../results-measurements" # Maximum number of entries to be extracted from the original file NUM_EVENTS=1000000 # Number of restart tests NUM_EVENTS_RESTART=1000 NUM_RESTART=1000 NONIID_RESTART_DATA="jent-raw-noise-restart" NONIID_DATA="jent-raw-noise" IID_DATA="jent-conditioned.data" # Define the maximum memory size # 0 -> use default # 1 -> JENT_MAX_MEMSIZE_32kB # ... # 15 -> JENT_MAX_MEMSIZE_512MB MAX_MEMORY_SIZE=0 # If this variable is set to any value, the timer-less entropy source # is forced and tested FORCE_NOTIME_NOISE_SOURCE="" initialization() { if [ ! -d $OUTDIR ] then mkdir $OUTDIR if [ $? -ne 0 ] then echo "Creation of $OUTDIR failed" exit 1 fi fi trap "make -s -f Makefile.rng clean; make -s -f Makefile.hashtime clean; exit" 0 1 2 3 15 } lfsroutput() { echo "Obtaining $NUM_EVENTS blocks of output from Jitter RNG" make -s -f Makefile.rng local cmdopts="--max-mem $MAX_MEMORY_SIZE" if [ -n "$FORCE_NOTIME_NOISE_SOURCE" ] then cmdopts="$cmdopts --disable-internal-timer" fi ./jitterentropy-rng $NUM_EVENTS $cmdopts > $OUTDIR/$IID_DATA make -s -f Makefile.rng clean } raw_entropy_restart() { echo "Obtaining $NUM_RESTART raw entropy measurement with $NUM_EVENTS_RESTART restarts from Jitter RNG" make -s -f Makefile.hashtime ./jitterentropy-hashtime $NUM_EVENTS_RESTART $NUM_RESTART $OUTDIR/$NONIID_RESTART_DATA $MAX_MEMORY_SIZE $FORCE_NOTIME_NOISE_SOURCE make -s -f Makefile.hashtime clean } raw_entropy() { echo "Obtaining $NUM_EVENTS raw entropy measurement from Jitter RNG" make -s -f Makefile.hashtime ./jitterentropy-hashtime $NUM_EVENTS 1 $OUTDIR/$NONIID_DATA $MAX_MEMORY_SIZE $FORCE_NOTIME_NOISE_SOURCE make -s -f Makefile.hashtime clean } initialization #lfsroutput raw_entropy raw_entropy_restart jitterentropy-library-3.6.3/tests/raw-entropy/recording_userspace/jitterentropy000077700000000000000000000000001500137124500312672../../../ustar00rootroot00000000000000jitterentropy-library-3.6.3/tests/raw-entropy/recording_userspace/jitterentropy-foldtime.c000066400000000000000000000037061500137124500324610ustar00rootroot00000000000000/* * Copyright (C) 2019 - 2025, Stephan Mueller * * License: see LICENSE file in root directory * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH * DAMAGE. */ #include #include #include #include "jitterentropy.h" #ifndef CONFIG_CRYPTO_CPU_JITTERENTROPY_STAT #error This program is meaningless without CONFIG_CRYPTO_CPU_JITTERENTROPY_STAT #endif int main(int argc, char * argv[]) { #ifdef ROUNDS size_t size = 0; struct rand_data *ec; ec = jent_entropy_collector_alloc(0, 0); if(!ec) return 1; while(size < ROUNDS) #else while(1) #endif { __u64 duration = 0; __u64 duration_min = 0; /* When enabling the for loops, you effectively get a cache * and TLB flush -- but tests show that flushing the cache * does not change the results, considering that you want to * remove the outliers from the dataset before processing it * as you do not want to have measurements based interferred * by interrupts, etc. */ /* int i = 0; for(i=0; i<1000; i++) */ /* mb(); */ duration = jent_fold_var_stat(ec, 0); /* mb(); */ /* for(i=0; i<1000; i++) */ duration_min = jent_fold_var_stat(ec, 1); /* mb(); */ printf("%llu %llu\n", duration, duration_min); #ifdef ROUNDS size++; #endif } return 0; } jitterentropy-library-3.6.3/tests/raw-entropy/recording_userspace/jitterentropy-hashtime.c000066400000000000000000000167401500137124500324620ustar00rootroot00000000000000/* * Copyright (C) 2019 - 2025, Stephan Mueller * * License: see LICENSE file in root directory * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH * DAMAGE. */ #include #include #include #include #include #include #include #include "jitterentropy-sha3.c" #include "jitterentropy-gcd.c" #include "jitterentropy-health.c" #include "jitterentropy-noise.c" #include "jitterentropy-timer.c" #include "jitterentropy-base.c" #ifndef REPORT_COUNTER_TICKS #define REPORT_COUNTER_TICKS 1 #endif /*************************************************************************** * Statistical test logic not compiled for regular operation ***************************************************************************/ static int jent_one_test(const char *pathname, unsigned long rounds, unsigned int flags, int report_counter_ticks) { unsigned long size = 0; struct rand_data *ec = NULL; uint64_t *duration; #ifdef JENT_CONF_DISABLE_LOOP_SHUFFLE #ifdef JENT_TEST_BINARY_OUTPUT size_t recordsWritten; #endif #else struct rand_data *ec_min = NULL; uint64_t *duration_min; #endif FILE *out = NULL; int ret = 0; unsigned int health_test_result; duration = calloc(rounds, sizeof(uint64_t)); if (!duration) return 1; #ifndef JENT_CONF_DISABLE_LOOP_SHUFFLE duration_min = calloc(rounds, sizeof(uint64_t)); if (!duration_min) { free(duration); return 1; } #endif printf("Processing %s\n", pathname); out = fopen(pathname, "w"); if (!out) { ret = 1; goto out; } ret = jent_entropy_init(); if (ret) { printf("The initialization failed with error code %d\n", ret); goto out; } ec = jent_entropy_collector_alloc(0, flags); if (!ec) { ret = 1; goto out; } #ifndef JENT_CONF_DISABLE_LOOP_SHUFFLE ec_min = jent_entropy_collector_alloc(0, flags); if (!ec_min) { ret = 1; goto out; } #endif if (!report_counter_ticks) { /* * For this analysis, we want the raw values, not values that * have had common factors removed. */ ec->jent_common_timer_gcd = 1; #ifndef JENT_CONF_DISABLE_LOOP_SHUFFLE ec_min->jent_common_timer_gcd = 1; #endif } if (ec->enable_notime) { jent_notime_settick(ec); #ifndef JENT_CONF_DISABLE_LOOP_SHUFFLE jent_notime_settick(ec_min); #endif } /* Enable full SP800-90B health test handling */ ec->fips_enabled = 1; #ifndef JENT_CONF_DISABLE_LOOP_SHUFFLE ec_min->fips_enabled = 1; #endif #ifdef JENT_RANDOM_MEMACCESS /* Print the size of the memory region. */ printf("Memory size: %" PRIu32 "\n", ec->memmask + 1); #endif /* Prime the test */ jent_measure_jitter(ec, 0, NULL); for (size = 0; size < rounds; size++) { /* Disregard stuck indicator */ jent_measure_jitter(ec, 0, &duration[size]); } #ifndef JENT_CONF_DISABLE_LOOP_SHUFFLE jent_measure_jitter(ec_min, 0, NULL); for (size = 0; size < rounds; size++) { /* Disregard stuck indicator */ jent_measure_jitter(ec_min, 1, &duration_min[size]); } #endif #ifdef JENT_CONF_DISABLE_LOOP_SHUFFLE #ifdef JENT_TEST_BINARY_OUTPUT recordsWritten = fwrite(duration, sizeof(uint64_t), rounds, out); if(recordsWritten != rounds) fprintf(stderr, "Can't output data.\n"); #else for (size = 0; size < rounds; size++) fprintf(out, "%" PRIu64 "\n", duration[size]); #endif #else for (size = 0; size < rounds; size++) fprintf(out, "%" PRIu64 " %" PRIu64 "\n", duration[size], duration_min[size]); #endif if ((health_test_result = jent_health_failure(ec))) { printf("The main context encountered the following health testing failure(s):"); if (health_test_result & JENT_RCT_FAILURE) printf(" RCT"); if (health_test_result & JENT_APT_FAILURE) printf(" APT"); if (health_test_result & JENT_LAG_FAILURE) printf(" Lag"); printf("\n"); } #ifndef JENT_CONF_DISABLE_LOOP_SHUFFLE if ((health_test_result = jent_health_failure(ec_min))) { printf("The minimum context encountered the following health testing failure(s):"); if (health_test_result & JENT_RCT_FAILURE) printf(" RCT"); if (health_test_result & JENT_APT_FAILURE) printf(" APT"); if (health_test_result & JENT_LAG_FAILURE) printf(" Lag"); printf("\n"); } #endif out: free(duration); #ifndef JENT_CONF_DISABLE_LOOP_SHUFFLE free(duration_min); #endif if (flags & JENT_FORCE_INTERNAL_TIMER) { if (ec) jent_notime_unsettick(ec); #ifndef JENT_CONF_DISABLE_LOOP_SHUFFLE if (ec_min) jent_notime_unsettick(ec_min); #endif } if (out) fclose(out); if (ec) jent_entropy_collector_free(ec); #ifndef JENT_CONF_DISABLE_LOOP_SHUFFLE if (ec_min) jent_entropy_collector_free(ec_min); #endif return ret; } /* * Invoke the application with * argv[1]: number of raw entropy measurements to be obtained for one * entropy collector instance. * argv[2]: number of test repetitions with a new entropy estimator * allocated for each round - this satisfies the restart tests * defined in SP800-90B section 3.1.4.3 and FIPS IG 7.18. * argv[3]: File name of the output data */ int main(int argc, char * argv[]) { unsigned long i, rounds, repeats; unsigned int flags = 0; int ret; char pathname[4096]; if (argc != 4 && argc != 5 && argc != 6) { printf("%s \n", argv[0]); return 1; } rounds = strtoul(argv[1], NULL, 10); if (rounds >= UINT_MAX) return 1; repeats = strtoul(argv[2], NULL, 10); if (repeats >= UINT_MAX) return 1; if (argc >= 5) { unsigned long val = strtoul(argv[4], NULL, 10); switch (val) { case 0: /* Allow to set no option */ break; case 1: flags |= JENT_MAX_MEMSIZE_32kB; break; case 2: flags |= JENT_MAX_MEMSIZE_64kB; break; case 3: flags |= JENT_MAX_MEMSIZE_128kB; break; case 4: flags |= JENT_MAX_MEMSIZE_256kB; break; case 5: flags |= JENT_MAX_MEMSIZE_512kB; break; case 6: flags |= JENT_MAX_MEMSIZE_1MB; break; case 7: flags |= JENT_MAX_MEMSIZE_2MB; break; case 8: flags |= JENT_MAX_MEMSIZE_4MB; break; case 9: flags |= JENT_MAX_MEMSIZE_8MB; break; case 10: flags |= JENT_MAX_MEMSIZE_16MB; break; case 11: flags |= JENT_MAX_MEMSIZE_32MB; break; case 12: flags |= JENT_MAX_MEMSIZE_64MB; break; case 13: flags |= JENT_MAX_MEMSIZE_128MB; break; case 14: flags |= JENT_MAX_MEMSIZE_256MB; break; case 15: flags |= JENT_MAX_MEMSIZE_512MB; break; default: printf("Unknown maximum memory value\n"); return 1; } } if (argc == 6) flags |= JENT_FORCE_INTERNAL_TIMER; for (i = 1; i <= repeats; i++) { #if defined(JENT_TEST_BINARY_OUTPUT) && defined(JENT_CONF_DISABLE_LOOP_SHUFFLE) snprintf(pathname, sizeof(pathname), "%s-%.4lu-u64.bin", argv[3], i); #else snprintf(pathname, sizeof(pathname), "%s-%.4lu.data", argv[3], i); #endif ret = jent_one_test(pathname, rounds, flags, REPORT_COUNTER_TICKS); if (ret) return ret; } return 0; } jitterentropy-library-3.6.3/tests/raw-entropy/recording_userspace/jitterentropy-lfsrtime.c000066400000000000000000000065561500137124500325110ustar00rootroot00000000000000/* * Copyright (C) 2019 - 2025, Stephan Mueller * * License: see LICENSE file in root directory * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH * DAMAGE. */ #include #include #include #include #include #include #include "jitterentropy-base.c" /*************************************************************************** * Statistical test logic not compiled for regular operation ***************************************************************************/ /* * Statistical test: return the time duration for the folding operation. If min * is set, perform the given number of LFSR ops. Otherwise, allow the * loop count shuffling to define the number of LFSR ops. */ static uint64_t jent_lfsr_var_stat(struct rand_data *ec, unsigned int min) { uint64_t time = 0; uint64_t time2 = 0; jent_get_nstime(&time); jent_memaccess(ec, min); jent_stuck(ec, time); jent_lfsr_time(ec, time, min, 0); jent_get_nstime(&time2); return ((time2 - time)); } static int jent_one_test(const char *pathname, unsigned long rounds) { unsigned long size = 0; struct rand_data *ec = NULL; FILE *out = NULL; int ret = 0; printf("Processing %s\n", pathname); out = fopen(pathname, "w"); if (!out) { ret = 1; goto out; } ec = jent_entropy_collector_alloc(0, 0); if(!ec) { ret = 1; goto out; } /* Enable full SP800-90B health test handling */ ec->fips_enabled = 1; for (size = 0; size < rounds; size++) { uint64_t duration = 0; uint64_t duration_min = 0; duration = jent_lfsr_var_stat(ec, 0); duration_min = jent_lfsr_var_stat(ec, 1); fprintf(out, "%lu %lu\n", duration, duration_min); } out: if (out) fclose(out); if (ec) jent_entropy_collector_free(ec); return ret; } /* * Invoke the application with * argv[1]: number of raw entropy measurements to be obtained for one * entropy collector instance. * argv[2]: number of test repetitions with a new entropy estimator * allocated for each round - this satisfies the restart tests * defined in SP800-90B section 3.1.4.3 and FIPS IG 7.18. * argv[3]: File name of the output data */ int main(int argc, char * argv[]) { unsigned long i, rounds, repeats; int ret; char pathname[4096]; if (argc != 4) { printf("%s \n", argv[0]); return 1; } rounds = strtoul(argv[1], NULL, 10); if (rounds >= UINT_MAX) return 1; repeats = strtoul(argv[2], NULL, 10); if (repeats >= UINT_MAX) return 1; for (i = 1; i <= repeats; i++) { snprintf(pathname, sizeof(pathname), "%s-%.4lu.data", argv[3], i); ret = jent_one_test(pathname, rounds); if (ret) return ret; } return 0; } jitterentropy-library-3.6.3/tests/raw-entropy/recording_userspace/jitterentropy-osr.c000066400000000000000000000250531500137124500314600ustar00rootroot00000000000000/* * Copyright (C) 2019 - 2025, Stephan Mueller * * License: see LICENSE file in root directory * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH * DAMAGE. */ #include #include #include #include #include #include #include #include #include "jitterentropy.h" /* We use a linear interpolation to estimate where the value is going to be. * The way these variable are named, this is technically the inverse function * for the resulting line, as we are trying to get the expected osr for a * provided time. * * Recall that point-point form for a line is * y - y1 = ((y2 - y1)/(x2 - x1))*(x - x1) * which is valid for non-vertical lines (i.e., so long as x1 != x2) * We actually want the functional inverse of this, so solving for x, we get * (y - y1) * ((x2 - x1) / (y2 - y1)) + x1 = x * This is valid so long as y2 != y1. * This functional inverse is the form that we use here. */ double linearInverse(double y, double x1, double y1, double x2, double y2) { assert(fabs(y1-y2)>=DBL_EPSILON); return (y-y1)*((x2-x1)/(y2-y1)) + x1; } /* Returns the number of nanoseconds per output for the selected flags and osr. */ uint64_t jent_output_time(unsigned int rounds, unsigned int osr, unsigned int flags) { struct rand_data *ec_nostir; struct timespec start, finish; uint64_t runtime; int ret; ret = jent_entropy_init_ex(osr, flags); if (ret) { fprintf(stderr, "The initialization failed with error code %d\n", ret); return ret; } ec_nostir = jent_entropy_collector_alloc(osr, flags); clock_gettime(CLOCK_REALTIME, &start); if (!ec_nostir) { fprintf(stderr, "Jitter RNG handle cannot be allocated\n"); return 1; } for (unsigned long size = 0; size < rounds; size++) { char tmp[32]; if (0 > jent_read_entropy_safe(&ec_nostir, tmp, sizeof(tmp))) { fprintf(stderr, "FIPS 140-2 continuous test failed\n"); return 1; } } clock_gettime(CLOCK_REALTIME, &finish); runtime = ((uint64_t)finish.tv_sec * UINT64_C(1000000000) + (uint64_t)finish.tv_nsec) - ((uint64_t)start.tv_sec * UINT64_C(1000000000) + (uint64_t)start.tv_nsec); jent_entropy_collector_free(ec_nostir); return runtime / (uint64_t)rounds; } int main(int argc, char * argv[]) { unsigned long rounds; unsigned int flags = 0; char *endtimeparam; double timeBoundIn; uint64_t timeBound; unsigned int maxBound, minBound, firstLinearGuess, secondLinearGuess; uint64_t minTime, maxTime, firstLinearTime, secondLinearTime; if (argc < 2) { fprintf(stderr, "%s [--force-fips|--disable-memory-access|--disable-internal-timer|--force-internal-timer|--max-mem ]\n", argv[0]); return 1; } rounds = strtoul(argv[1], NULL, 10); if ((rounds >= UINT_MAX) || (rounds == 0)) return 1; argc--; argv++; timeBoundIn = strtod(argv[1], &endtimeparam); if ((timeBoundIn <= 0.0) || (*endtimeparam != '\0')) return 1; /* The time upper bound, expressed as an integer number of nanoseconds. */ timeBound = (uint64_t)floor(timeBoundIn * 1000000000.0); argc--; argv++; while (argc > 1) { if (!strncmp(argv[1], "--force-fips", 12)) flags |= JENT_FORCE_FIPS; else if (!strncmp(argv[1], "--disable-memory-access", 23)) flags |= JENT_DISABLE_MEMORY_ACCESS; else if (!strncmp(argv[1], "--disable-internal-timer", 24)) flags |= JENT_DISABLE_INTERNAL_TIMER; else if (!strncmp(argv[1], "--force-internal-timer", 22)) flags |= JENT_FORCE_INTERNAL_TIMER; else if (!strncmp(argv[1], "--max-mem", 9)) { unsigned long val; argc--; argv++; if (argc <= 1) { fprintf(stderr, "Maximum memory value missing.\n"); return 1; } val = strtoul(argv[1], NULL, 10); switch (val) { case 0: /* Allow to set no option */ break; case 1: flags |= JENT_MAX_MEMSIZE_32kB; break; case 2: flags |= JENT_MAX_MEMSIZE_64kB; break; case 3: flags |= JENT_MAX_MEMSIZE_128kB; break; case 4: flags |= JENT_MAX_MEMSIZE_256kB; break; case 5: flags |= JENT_MAX_MEMSIZE_512kB; break; case 6: flags |= JENT_MAX_MEMSIZE_1MB; break; case 7: flags |= JENT_MAX_MEMSIZE_2MB; break; case 8: flags |= JENT_MAX_MEMSIZE_4MB; break; case 9: flags |= JENT_MAX_MEMSIZE_8MB; break; case 10: flags |= JENT_MAX_MEMSIZE_16MB; break; case 11: flags |= JENT_MAX_MEMSIZE_32MB; break; case 12: flags |= JENT_MAX_MEMSIZE_64MB; break; case 13: flags |= JENT_MAX_MEMSIZE_128MB; break; case 14: flags |= JENT_MAX_MEMSIZE_256MB; break; case 15: flags |= JENT_MAX_MEMSIZE_512MB; break; default: fprintf(stderr, "Unknown maximum memory value\n"); return 1; } } else { fprintf(stderr, "Unknown option %s\n", argv[1]); return 1; } argc--; argv++; } /* We don't start with a maxBound. */ maxBound = 0; maxTime = 0; /* Verify the first invariant: generation using minBound occurs in less than or equal time than the targeted time. */ minBound = JENT_MIN_OSR; if((minTime = jent_output_time(rounds, minBound, flags)) > timeBound) { fprintf(stderr, "Minimum osr %u exceeds the target time. Invariant not met.\n", minBound); return 1; } else fprintf(stderr, "A minimum was found: osr upper bound is >= %u.\n", minBound); /* If there were no constant value in the linear expression, then we could estimate a cutoff * using only this timing. We imagine that there is a fixed cost, so simple division overestimates * the time cost per osr, and so this produces a likely underestimate. */ firstLinearGuess = (unsigned int)(timeBound / (1U + minTime / minBound)); fprintf(stderr, "The initial linear estimate is osr=%u\n", firstLinearGuess); firstLinearTime = jent_output_time(rounds, firstLinearGuess, flags); /* We now have two points (minBound, minTime) and (firstLinearGuess, firstLinearTime), so we can * perform a full linear interpolation. * We are presently looking for an overestimate, so let's round up here. */ secondLinearGuess = (unsigned int)ceil(linearInverse((double)timeBound, (double)minBound, (double)minTime, (double)firstLinearGuess, (double)firstLinearTime)); fprintf(stderr, "Linear interpolation suggests a cutoff of %u\n", secondLinearGuess); /* These estimates were done in two related ways, but they could have produced the same value. * Looking at the timing of two identical guesses isn't helpful, so adjust the result in this case.*/ if(secondLinearGuess == firstLinearGuess) { secondLinearGuess++; } secondLinearTime = jent_output_time(rounds, secondLinearGuess, flags); /* We now expect that secondLinearGuess > firstLinearGuess but weird things could have occurred. * They can't be equal, by the above adjustment. * Exchange them if they don't have the expected relationship. */ if(secondLinearGuess < firstLinearGuess) { uint64_t tmpTime; unsigned int tmpGuess; tmpGuess = firstLinearGuess; tmpTime = firstLinearTime; firstLinearGuess = secondLinearGuess; firstLinearTime = secondLinearTime; secondLinearGuess = tmpGuess; secondLinearTime = tmpTime; } /* Now secondLinearGuess > firstLinearGuess, and the time values should have a similar relationship. */ assert(secondLinearTime > firstLinearTime); /* Use the linear interpolation guesses as bounds where possible. */ if(firstLinearTime > timeBound) { /* Here, we have timeBound < firstLinearTime < secondLinearTime. * In this case, the linear interpolations didn't yield a minBound * so we'll proceed with the initial minBound. */ maxBound = firstLinearGuess; maxTime = firstLinearTime; } else if(secondLinearTime > timeBound) { /* Here, we have firstLinearTime <= timeBound < secondLinearTime. * so the linear interpolations provide both a minBound and maxBound. */ minBound = firstLinearGuess; minTime = firstLinearTime; maxBound = secondLinearGuess; maxTime = secondLinearTime; } else { /* here, we have know that firstLinearTime < secondLinearTime <= timeBound */ /* so linear interpolation didn't supply a maxBound, and will have to look for it. */ minBound = secondLinearGuess; minTime = secondLinearTime; } /* If we don't yet have a maxBound, find one. This will also adjust minBound up as the search goes.*/ if(maxBound == 0) { maxBound = minBound*2; fprintf(stderr, "Trying to find a maximum: %u", maxBound); /* Locate the maxBound */ while((maxTime = jent_output_time(rounds, maxBound, flags)) <= timeBound) { minBound = maxBound; minTime = maxTime; maxBound = maxBound * 2; fprintf(stderr, " %u", maxBound); assert(maxBound > minBound); } fprintf(stderr, ".\nMaximum found: osr upper bound is < %u.\n", maxBound); } fprintf(stderr, "Desired osr upper bound is in [%u, %u)\n", minBound, maxBound); assert(maxBound > minBound); assert(maxTime > minTime); assert(maxTime > timeBound); assert(minTime <= timeBound); /* All invariants are now verified: * maxBound > minBound * maxTime > timeBound >= minTime * * We now perform a binary search (if necessary). */ while(maxBound - minBound > 1) { unsigned int curosr; uint64_t curTime; /* Calculate (minBound + maxBound)/2 without risk of overflow. */ curosr = minBound + (maxBound - minBound) / 2; assert(curosr > minBound); assert(curosr < maxBound); fprintf(stderr, "Trying osr=%u. ", curosr); curTime = jent_output_time(rounds, curosr, flags); assert(curTime > minTime); assert(curTime < maxTime); if(curTime <= timeBound) { fprintf(stderr, "Timing is less than or equal to the target time. "); minBound = curosr; minTime = curTime; } else { fprintf(stderr, "Timing is greater than the target time. "); maxBound = curosr; maxTime = curTime; } fprintf(stderr, "Desired osr upper bound is in [%u, %u)\n", minBound, maxBound); assert(maxBound > minBound); assert(maxTime > minTime); assert(maxTime > timeBound); assert(minTime <= timeBound); } printf("%u\n", minBound); return 0; } jitterentropy-library-3.6.3/tests/raw-entropy/recording_userspace/jitterentropy-rng.c000066400000000000000000000076531500137124500314510ustar00rootroot00000000000000/* * Copyright (C) 2019 - 2025, Stephan Mueller * * License: see LICENSE file in root directory * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH * DAMAGE. */ #include #include #include #include #include "jitterentropy.h" int main(int argc, char * argv[]) { unsigned long size, rounds; int ret = 0; unsigned int flags = 0, osr = 0; struct rand_data *ec_nostir; if (argc < 2) { printf("%s [--force-fips|--disable-memory-access|--disable-internal-timer|--force-internal-timer|--osr |--max-mem ]\n", argv[0]); return 1; } rounds = strtoul(argv[1], NULL, 10); if (rounds >= UINT_MAX) return 1; argc--; argv++; while (argc > 1) { if (!strncmp(argv[1], "--force-fips", 12)) flags |= JENT_FORCE_FIPS; else if (!strncmp(argv[1], "--disable-memory-access", 23)) flags |= JENT_DISABLE_MEMORY_ACCESS; else if (!strncmp(argv[1], "--disable-internal-timer", 24)) flags |= JENT_DISABLE_INTERNAL_TIMER; else if (!strncmp(argv[1], "--force-internal-timer", 22)) flags |= JENT_FORCE_INTERNAL_TIMER; else if (!strncmp(argv[1], "--osr", 5)) { unsigned long val; argc--; argv++; if (argc <= 1) { printf("OSR value missing\n"); return 1; } val = strtoul(argv[1], NULL, 10); if (val >= UINT_MAX) return 1; osr = (unsigned int)val; } else if (!strncmp(argv[1], "--max-mem", 9)) { unsigned long val; argc--; argv++; if (argc <= 1) { printf("Maximum memory value missing\n"); return 1; } val = strtoul(argv[1], NULL, 10); switch (val) { case 0: /* Allow to set no option */ break; case 1: flags |= JENT_MAX_MEMSIZE_32kB; break; case 2: flags |= JENT_MAX_MEMSIZE_64kB; break; case 3: flags |= JENT_MAX_MEMSIZE_128kB; break; case 4: flags |= JENT_MAX_MEMSIZE_256kB; break; case 5: flags |= JENT_MAX_MEMSIZE_512kB; break; case 6: flags |= JENT_MAX_MEMSIZE_1MB; break; case 7: flags |= JENT_MAX_MEMSIZE_2MB; break; case 8: flags |= JENT_MAX_MEMSIZE_4MB; break; case 9: flags |= JENT_MAX_MEMSIZE_8MB; break; case 10: flags |= JENT_MAX_MEMSIZE_16MB; break; case 11: flags |= JENT_MAX_MEMSIZE_32MB; break; case 12: flags |= JENT_MAX_MEMSIZE_64MB; break; case 13: flags |= JENT_MAX_MEMSIZE_128MB; break; case 14: flags |= JENT_MAX_MEMSIZE_256MB; break; case 15: flags |= JENT_MAX_MEMSIZE_512MB; break; default: printf("Unknown maximum memory value\n"); return 1; } } else { printf("Unknown option %s\n", argv[1]); return 1; } argc--; argv++; } ret = jent_entropy_init_ex(osr, flags); if (ret) { printf("The initialization failed with error code %d\n", ret); return ret; } ec_nostir = jent_entropy_collector_alloc(osr, flags); if (!ec_nostir) { printf("Jitter RNG handle cannot be allocated\n"); return 1; } for (size = 0; size < rounds; size++) { char tmp[32]; if (0 > jent_read_entropy_safe(&ec_nostir, tmp, sizeof(tmp))) { fprintf(stderr, "FIPS 140-2 continuous test failed\n"); return 1; } fwrite(&tmp, sizeof(tmp), 1, stdout); } jent_entropy_collector_free(ec_nostir); return 0; } jitterentropy-library-3.6.3/tests/raw-entropy/validation-restart-kernel/000077500000000000000000000000001500137124500266305ustar00rootroot00000000000000jitterentropy-library-3.6.3/tests/raw-entropy/validation-restart-kernel/Makefile000066400000000000000000000014061500137124500302710ustar00rootroot00000000000000# Compile Noise Source as user space application CC ?= gcc override CFLAGS +=-pedantic -Wall -Wextra -O2 program_NAME := extractlsb #program_C_SRCS := $(wildcard *.c) program_C_SRCS := extractlsb.c program_C_OBJS := ${program_C_SRCS:.c=.o} program_OBJS := $(program_C_OBJS) program_INCLUDE_DIRS := program_LIBRARY_DIRS := program_LIBRARIES := CPPFLAGS += $(foreach includedir,$(program_INCLUDE_DIRS),-I$(includedir)) LDFLAGS += $(foreach librarydir,$(program_LIBRARY_DIRS),-L$(librarydir)) LDFLAGS += $(foreach library,$(program_LIBRARIES),-l$(library)) .PHONY: all clean distclean all: $(program_NAME) $(program_NAME): $(program_OBJS) $(CC) $(program_OBJS) -o $(program_NAME) $(LDFLAGS) clean: @- $(RM) $(program_NAME) @- $(RM) $(program_OBJS) distclean: clean jitterentropy-library-3.6.3/tests/raw-entropy/validation-restart-kernel/README.md000066400000000000000000000051251500137124500301120ustar00rootroot00000000000000# Validation of Raw Entropy Data Restart Test This validation tool processes the restart raw entropy data compliant to SP800-90B section 3.1.4. Each restart must be recorded in a single file where each raw entropy value is stored on one line. ## Prerequisites To execute the testing, you need: * NIST SP800-90B tool from: https://github.com/usnistgov/SP800-90B_EntropyAssessment * Obtain the sample data recorded on the target platforms * Configure processdata.sh with proper parameter values ### Parameters of processdata.sh ENTROPYDATA_DIR: Location of the sample data files (with .data extension) RESULTS_DIR: Location for the interim data bit streams and results. LOGFILE: Name of the log file. The default is $RESULTS_DIR/processdata.log. EATOOL: Path of the program used from the Entropy Assessment restart tool (usually, ea_restart). BUILD_EXTRACT: Indicates whether the script will build the extractlsb program. The default is "yes". MASK_LIST: Indicates the extraction method from each sample item. You can indicate one or more methods; the script will generate one bit stream data file for each extraction method. See below for a more detailed explanation. SAMPLES: the number of samples (time deltas) that will be extracted from the data. The default is 1000, as specified in SP800-90B. RESTARTS: the number of test runs to be concatenated. The default is 1000, as specified in SP 800-90B Each test run should be stored in a distinct file, from jent_raw_noise_restart.00000.data to jent_raw_noise_restart.00999.data. ## Conclusion The conclusion you have to draw is the following: To generate a 256 bit block, the Jitter RNG obtains 256 time deltas (one time delta per bit at least, unless the Jitter RNG performs oversampling). So, if you obtain a result that the minimum entropy is more than 1 bit of entropy (per time delta), the one block of 64 data bits is believed to have (close to) 64 bits of entropy. Otherwise it will have relatively less entropy. Please note that the minimum collision entropy value for 8 bits may be smaller than the 4 bit values due to the inclusion of leading zeros. This, however is a data processing problem that should be considered when drawing conclusions. One can see the effect of these leading zeros by compressing the 4 bit and 8 bit data streams. Whereas the 4 bit data stream may not be compressable, the 8 bit data stream may be compressed This may also occur when the least significant bits in the time delta do not change. You need to refine the extraction method to reach to the right calculation. [1] https://github.com/usnistgov/SP800-90B_EntropyAssessment jitterentropy-library-3.6.3/tests/raw-entropy/validation-restart-kernel/extractlsb.c000066400000000000000000000113061500137124500311500ustar00rootroot00000000000000/* * Copyright (C) 2019 - 2025, Stephan Mueller * * License: see LICENSE file in root directory * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH * DAMAGE. */ /* * The tool extracts the 4 or 8 LSB of the high-res time stamp and * concatenates them to form a binary data stream. * */ #include #include #include #include #include #include #include #include #define BITS_PER_SAMPLE 64 /* Extract bits from sample based on significant bit mask */ static unsigned char extract(uint64_t sample, uint64_t mask) { unsigned char byte = 0; int i, j = 0; for (i = 0; i < BITS_PER_SAMPLE && mask; i++) { if (mask & 1) { byte |= (sample & 1) << j; j++; } mask >>= 1; sample >>= 1; } return byte; } /* Convert mask in hexadecimal format to binary */ static int hextolong(char *p_strmask, uint64_t *p_mask) { uint64_t mask = 0; int count = 0; while (*p_strmask) { count++; mask <<= 4; if ((*p_strmask >= '0') && (*p_strmask <= '9')) mask |= *p_strmask - '0'; else if ((*p_strmask >= 'A') && (*p_strmask <= 'F')) mask |= *p_strmask - 'A' + 10; else if ((*p_strmask >= '0') && (*p_strmask <= '9')) mask |= *p_strmask - 'a' + 10; else return -1; p_strmask++; } if (count > 16) return -1; *p_mask = mask; return 0; } /* Count the number of bits on */ static int bitcount(uint64_t mask) { int i, j = 0; for (i = 0; i < BITS_PER_SAMPLE && mask; i++) { if (mask & 1) { j++; } mask >>= 1; } return j; } /* Print 64 bits of long word masking with '-' those not matching value */ static char *printbits(uint64_t sample, int value) { static char buf[BITS_PER_SAMPLE + 9]; char *p_buf = buf + sizeof(buf) - 1; int i; *p_buf-- = '\0'; for (i = 0; i < BITS_PER_SAMPLE; i++) { if (i % 8 == 0) *p_buf-- = ' '; if ((sample & 1) ^ value) *p_buf = '-'; else *p_buf = '0' + value; p_buf--; sample >>= 1; } return buf; } int main(int argc, char *argv[]) { FILE *f = NULL; char buf[64]; int outfd = -1; uint32_t count; uint32_t i = 0; int prev_timestamp_set = 0; uint64_t prev_timestamp = 0; uint64_t mask; uint64_t unchanged0s, unchanged1s; int rc; if (argc != 5) { printf("Usage: %s inputfile outfile samples mask\n", argv[0]); return 1; } f = fopen(argv[1], "r"); if (!f) { printf("File %s cannot be opened for read\n", argv[1]); return 1; } outfd = open(argv[2], O_CREAT|O_WRONLY|O_APPEND, 0777); if (outfd < 0) { printf("File %s cannot be opened for write\n", argv[2]); fclose(f); return 1; } count = strtoul(argv[3], NULL, 10); rc = hextolong(argv[4], &mask); if (rc) { printf("Mask value is incorrect [%s], use up to 16 hexadecimal characters\n", argv[5]); fclose(f); close(outfd); return 1; } if (bitcount(mask) > 8) { printf("SP800-90B tool only supports up to 8 bits. Check the mask value\n"); fclose(f); close(outfd); return 1; } unchanged0s = 0; unchanged1s = ~0; while (fgets(buf, sizeof(buf), f)) { uint64_t timestamp, delta; unsigned char extracted; // Ignore empty lines. if (buf[0] == '\0' || buf[0] == '\n' || buf[0] == '\r') { continue; } timestamp = strtoul(buf, NULL, 10); if (!prev_timestamp_set) { prev_timestamp = timestamp; prev_timestamp_set = 1; continue; } delta = timestamp - prev_timestamp; prev_timestamp = timestamp; unchanged0s |= delta; unchanged1s &= delta; extracted = extract(delta, mask); write(outfd, &extracted, sizeof(extracted)); i += 1; if (i == count) break; } if (i < count) { printf("Attempted to extract %d samples from %s but only got %d samples\n", count, argv[0], i); fclose(f); close(outfd); return 1; } printf("Processed %d samples from %s with mask [0x%016llx] significant bits [%d]\n", i, argv[0], (unsigned long long)mask, bitcount(mask)); printf("Constant 0s in sample: \n%s\n", printbits(unchanged0s, 0)); printf("Constant 1s in sample: \n%s\n", printbits(unchanged1s, 1)); fclose(f); close(outfd); return 0; } jitterentropy-library-3.6.3/tests/raw-entropy/validation-restart-kernel/processdata.sh000066400000000000000000000074311500137124500315010ustar00rootroot00000000000000#!/bin/bash # # Process the entropy data ############################################################ # Configuration values # ############################################################ # point to the directory that contains the results from the entropy collection ENTROPYDATA_DIR=${ENTROPYDATA_DIR:-"../results-measurements"} # this is where the resulting data and the entropy analysis will be stored RESULTS_DIR=${RESULTS_DIR:-"../results-analysis-restart"} # location of log file LOGFILE="$RESULTS_DIR/processdata.log" # point to the min entropy tool EATOOL="../SP800-90B_EntropyAssessment/cpp/ea_restart" # specify if you want to compile the extractlsb program in this script BUILD_EXTRACT=${BUILD_EXTRACT:-"yes"} # specify the list of significant bits and length that you want to analize. # Indicate first the mask in hexa format and then the number of # bits separated by a colon. # The tool generates one set of var and single data files, and the EA results # for each element. # The mask can have a maximum of 8 bits on, the EA tool only manages samples # up to one byte. # List of masks usually analyzed (4 and 8 LSB) MASK_LIST="0F:4 FF:8" # List used for ARM Cortext A9 and A7 processors #MASK_LIST="FF:4,8 7F8:4,8" # Number of samples to be extracted from the original file SAMPLES=1000 # Number of test runs to be concatenated RESTARTS=1000 ############################################################ # Code only after this line -- do not change # ############################################################ ############################# # Preparation ############################# EXTRACT="extractlsb" CFILE="extractlsb.c" if [ ! -d $ENTROPYDATA_DIR ] then echo "ERROR: Directory with raw entropy data $ENTROPYDATA_DIR is missing" exit 1 fi if [ ! -d $RESULTS_DIR ] then mkdir $RESULTS_DIR if [ $? -ne 0 ] then echo "ERROR: Directory for results $RESULTS_DIR could not be created" exit 1 fi fi if [ ! -f $EATOOL ] then echo "ERROR: Path of Entropy Data tool $EATOOL is missing" exit 1 fi rm -f $RESULTS_DIR/*.txt $RESULTS_DIR/*.data $RESULTS_DIR/*.log trap "if [ "$BUILD_EXTRACT" = "yes" ]; then make clean; fi" 0 1 2 3 15 if [ "$BUILD_EXTRACT" = "yes" ] then echo "Building $EXTRACT ..." make clean make fi if [ ! -x $EXTRACT ] then echo "ERROR: Cannot execute $EXTRACT program" exit 1 fi ############################# # Actual data processing ############################# # # Step 1: Concatenate all individual restart files into single file and convert # for item in $MASK_LIST do mask=${item%:*} echo "Converting recorded entropy data into different bit output with mask $mask..." | tee -a $LOGFILE out_file=$RESULTS_DIR/raw_noise_restart_all.${mask}bitout.data rm -f $out_file for i in `seq -f "%05g" 0 $(($RESTARTS-1))` do in_file=$ENTROPYDATA_DIR/jent_raw_noise_restart.$i.data if [ ! -f $in_file ] then echo "ERROR: File $in_file not found" exit 1 fi echo "Converting recorded entropy data $in_file into different bit output with mask $mask" >> $LOGFILE ./$EXTRACT $in_file $out_file $SAMPLES $mask >> $LOGFILE 2>&1 done done echo "" | tee -a $LOGFILE echo "Extraction finished. Now analyzing entropy for noise source ..." | tee -a $LOGFILE echo "" | tee -a $LOGFILE # # Step 2: Perform SP800-90B analysis # for item in $MASK_LIST do mask=${item%:*} bits_field=${item#*:} bits_list=`echo $bits_field | sed -e "s/,/ /g"` in_file=$RESULTS_DIR/raw_noise_restart_all.${mask}bitout.data for bits in $bits_list do out_file=$RESULTS_DIR/raw_noise_restart_all.minentropy_${mask}_${bits}bits.txt if [ ! -f $out_file ] then echo "Analyzing entropy for $out_file ${bits}-bit..." | tee -a $LOGFILE $EATOOL -n -v $in_file ${bits} 1.0 > $out_file else echo "File $out_file already generated" fi done done jitterentropy-library-3.6.3/tests/raw-entropy/validation-restart/000077500000000000000000000000001500137124500253525ustar00rootroot00000000000000jitterentropy-library-3.6.3/tests/raw-entropy/validation-restart/Makefile000066400000000000000000000014111500137124500270070ustar00rootroot00000000000000# Compile Noise Source as user space application CC ?= gcc override CFLAGS +=-pedantic -Wall -Wextra -O2 program_NAME := extractlsb #program_C_SRCS := $(wildcard *.c) program_C_SRCS := extractlsb.c program_C_OBJS := ${program_C_SRCS:.c=.o} program_OBJS := $(program_C_OBJS) program_INCLUDE_DIRS := program_LIBRARY_DIRS := program_LIBRARIES := rt CPPFLAGS += $(foreach includedir,$(program_INCLUDE_DIRS),-I$(includedir)) LDFLAGS += $(foreach librarydir,$(program_LIBRARY_DIRS),-L$(librarydir)) LDFLAGS += $(foreach library,$(program_LIBRARIES),-l$(library)) .PHONY: all clean distclean all: $(program_NAME) $(program_NAME): $(program_OBJS) $(CC) $(program_OBJS) -o $(program_NAME) $(LDFLAGS) clean: @- $(RM) $(program_NAME) @- $(RM) $(program_OBJS) distclean: clean jitterentropy-library-3.6.3/tests/raw-entropy/validation-restart/README.md000066400000000000000000000052251500137124500266350ustar00rootroot00000000000000# Validation of Raw Entropy Data Restart Test This validation tool processes the restart raw entropy data compliant to SP800-90B section 3.1.4. Each restart must be recorded in a single file where each raw entropy value is stored on one line. ## Prerequisites To execute the testing, you need: * NIST SP800-90B tool from: https://github.com/usnistgov/SP800-90B_EntropyAssessment * Obtain the sample data recorded on the target platforms * Configure processdata.sh with proper parameter values ### Parameters of processdata.sh ENTROPYDATA_DIR: Location of the sample data files (with .data extension) RESULTS_DIR: Location for the interim data bit streams (var and single), and results. LOGFILE: Name of the log file. The default is $RESULTS_DIR/processdata.log. EATOOL: Path of the program used from the Entropy Assessment restart tool (usually, ea_restart). BUILD_EXTRACT: Indicates whether the script will build the extractlsb program. The default is "yes". MASK_LIST: Indicates the extraction method from each sample item. You can indicate one or more methods; the script will generate one bit stream data file set (var and single) for each extraction method. See below for a more detailed explanation. MAX_EVENTS: the size of the sample that will be extracted from the sample data. The default is 100000 (a 1% of the size of the sample file specified in the ROUNDS define macro). Notice that the minimum value suggested by SP800-90B is 1000000, so you'll have to increase the default value (notice that this severely impacts in the performance and memory requirements of the python tool). ## Conclusion The conclusion you have to draw is the following: To generate a 256 bit block, the Jitter RNG obtains 256 time deltas (one time delta per bit at least, unless the Jitter RNG performs oversampling). So, if you obtain a result that the minimum entropy is more than 1 bit of entropy (per time delta), the one block of 64 data bits is believed to have (close to) 64 bits of entropy. Otherwise it will have relatively less entropy. Please note that the minimum collision entropy value for 8 bits may be smaller than the 4 bit values due to the inclusion of leading zeros. This, however is a data processing problem that should be considered when drawing conclusions. One can see the effect of these leading zeros by compressing the 4 bit and 8 bit data streams. Whereas the 4 bit data stream may not be compressable, the 8 bit data stream may be compressed This may also occur when the least significant bits in the time delta do not change. You need to refine the extraction method to reach to the right calculation. [1] https://github.com/usnistgov/SP800-90B_EntropyAssessment jitterentropy-library-3.6.3/tests/raw-entropy/validation-restart/analyze_options.sh000077500000000000000000000047641500137124500311420ustar00rootroot00000000000000#!/bin/bash # # Tool to validaets the test results for various Jitter RNG memory settings # # This tool is only needed if you have insufficient entropy. See ../README.md # for details # RESULT="../results-restart-multi" ENT_DIR="../results-measurements" RES_DIR="../results-analysis-restart" NUM_CPU=1 USED_CPUS=0 echo -e "Number of blocks\tBlocksize\tmin entropy" > $RESULT trap "make clean" 0 1 2 3 15 make clean make crunch_numbers() { local source=$1 local target=$2 if [ $USED_CPUS -eq $NUM_CPU ] then # wait for all wait USED_CPUS=0 fi if [ ! -d $target ] then USED_CPUS=$(($USED_CPUS+1)) ( BUILD_EXTRACT="no" ENTROPYDATA_DIR=$source RESULTS_DIR=$target ./processdata.sh ) & fi } linearmem_written=0 calc() { local crunch=$1 for memsize in 32768 65536 131072 262144 524288 1048576 2097152 4194304 8388608 16777216 33554432 67108864 134217728 268435456 536870912 do for blocks in 64 128 256 512 1024 2048 4096 8192 16384 do for blocksize in 32 64 128 256 512 1024 2048 4096 8192 16384 do local target="$RES_DIR-${blocks}blocks-${blocksize}blocksize-${memsize}bytes" local source="$ENT_DIR-${blocks}blocks-${blocksize}blocksize-${memsize}bytes" if [ ! -d "$source" ] then continue fi if [ $linearmem_written -eq 0 ] then echo -e "Max memory size\tNumber of blocks\tBlocksize\tmin entropy" > $RESULT linearmem_written=1 fi if [ $crunch -eq 0 ] then ent=$(grep min $target/jent-raw-noise-restart-consolidated.minentropy_FF_8bits.var.txt | cut -d ":" -f 2) echo -e "$memsize\t$blocks\t$blocksize\t$ent" >> $RESULT else crunch_numbers $source $target fi done done done } randmem_written=0 calc_randmem() { local crunch=$1 for bits in 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 do local target="$RES_DIR-random_memaccess-${bits}bits-${memsize}bytes" local source="$ENT_DIR-random_memaccess-${bits}bits-${memsize}bytes" if [ ! -d "$source" ] then continue fi if [ $randmem_written -eq 0 ] then echo -e "Number of bits\tmin entropy" > $RESULT randmem_written=1 fi if [ $crunch -eq 0 ] then ent=$(grep min $target/jent-raw-noise-restart-consolidated.minentropy_FF_8bits.var.txt | cut -d ":" -f 2) echo -e "$bits\t$ent" >> $RESULT else crunch_numbers $source $target fi done } if [ -f /proc/cpuinfo ] then NUM_CPU=$(cat /proc/cpuinfo | grep processor | tail -n1 | cut -d":" -f 2) NUM_CPU=$(($NUM_CPU+1)) fi calc_randmem 1 wait calc_randmem 0 calc 1 wait calc 0 jitterentropy-library-3.6.3/tests/raw-entropy/validation-restart/extractlsb.c000066400000000000000000000120661500137124500276760ustar00rootroot00000000000000/* * Copyright (C) 2019 - 2025, Stephan Mueller * * License: see LICENSE file in root directory * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH * DAMAGE. */ /* * The tool extracts the 4 or 8 LSB of the high-res time stamp and * concatenates them to form a binary data stream. * */ #include #include #include #include #include #include #include #include #define BITS_PER_SAMPLE 64 /* Extract bits from sample based on significant bit mask */ static unsigned char extract(uint64_t sample, uint64_t mask) { unsigned char byte = 0; int i, j = 0; for (i = 0; i < BITS_PER_SAMPLE && mask; i++) { if (mask & 1) { byte |= (sample & 1) << j; j++; } mask >>= 1; sample >>= 1; } return (byte); } /* Convert mask in hexadecimal format to binary */ static int hextolong(char *p_strmask, uint64_t *p_mask) { uint64_t mask = 0; int count = 0; while (*p_strmask) { count++; mask <<= 4; if ((*p_strmask >= '0') && (*p_strmask <= '9')) mask |= *p_strmask - '0'; else if ((*p_strmask >= 'A') && (*p_strmask <= 'F')) mask |= *p_strmask - 'A' + 10; else if ((*p_strmask >= '0') && (*p_strmask <= '9')) mask |= *p_strmask - 'a' + 10; else return -1; p_strmask++; } if (count > 16) return(-1); *p_mask = mask; return(0); } /* Count the number of bits on */ static int bitcount(uint64_t mask) { int i, j = 0; for (i = 0; i < BITS_PER_SAMPLE && mask; i++) { if (mask & 1) { j++; } mask >>= 1; } return (j); } /* Print 64 bits of long word masking with '-' those not matching value */ static char *printbits(uint64_t sample, int value) { static char buf[BITS_PER_SAMPLE + 9]; char *p_buf = buf + sizeof(buf) - 1; int i; *p_buf-- = '\0'; for (i = 0; i < BITS_PER_SAMPLE; i++) { if (i % 8 == 0) *p_buf-- = ' '; if ((sample & 1) ^ value) *p_buf = '-'; else *p_buf = '0' + value; p_buf--; sample >>= 1; } return buf; } int main(int argc, char *argv[]) { FILE *f = NULL; char buf[64]; int varfd = -1; int singlefd = -1; uint32_t count; uint32_t i = 0; uint64_t mask; uint64_t var_unchanged0s, var_unchanged1s; uint64_t single_unchanged0s, single_unchanged1s; int rc; if (argc != 6) { printf("Usage: %s inputfile varoutfile singleoutfile maxevents mask\n", argv[0]); return 1; } f = fopen(argv[1], "r"); if (!f) { printf("File %s cannot be opened for read\n", argv[1]); return 1; } varfd = open(argv[2], O_CREAT|O_WRONLY|O_EXCL, 0777); if (varfd < 0) { printf("File %s cannot be opened for write\n", argv[2]); fclose(f); return 1; } singlefd = open(argv[3], O_CREAT|O_WRONLY|O_EXCL, 0777); if (singlefd < 0) { printf("File %s cannot be opened for write\n", argv[3]); fclose(f); close(varfd); return 1; } count = strtoul(argv[4], NULL, 10); rc = hextolong(argv[5], &mask); if (rc) { printf("Mask value is incorrect [%s], use up to 16 hexadecimal characters", argv[5]); return 1; } if (bitcount(mask) > 8) { printf("SP800-90B tool only supports up to 8 bits. Check the mask value"); return 1; } var_unchanged0s = 0; var_unchanged1s = ~0; single_unchanged0s = 0; single_unchanged1s = ~0; while (fgets(buf, sizeof(buf), f)) { uint64_t sample; unsigned char var, single; char *saveptr = NULL; char *res = NULL; i++; res = strtok_r(buf, " ", &saveptr); if (!res) { printf("strtok_r error (%s)\n", buf); return 1; } sample = strtoul(res, NULL, 10); var_unchanged0s |= sample; var_unchanged1s &= sample; var = extract(sample, mask); write(varfd, &var, sizeof(var)); res = strtok_r(NULL, " ", &saveptr); if (res) { sample = strtoul(res, NULL, 10); single_unchanged0s |= sample; single_unchanged1s &= sample; single = extract(sample, mask); write(singlefd, &single, sizeof(single)); } if (i >= count) break; } printf("Processed %d items from %s samples with mask [0x%016llx] significant bits [%d]\n", i, argv[0], (unsigned long long)mask, bitcount(mask)); printf("Constant 0s in var sample: \n%s\n", printbits(var_unchanged0s, 0)); printf("Constant 1s in var sample: \n%s\n", printbits(var_unchanged1s, 1)); printf("Constant 0s in single sample: \n%s\n", printbits(single_unchanged0s, 0)); printf("Constant 1s in single sample: \n%s\n", printbits(single_unchanged1s, 1)); fclose(f); close(varfd); close(singlefd); return 0; } jitterentropy-library-3.6.3/tests/raw-entropy/validation-restart/processdata.sh000077500000000000000000000103471500137124500302260ustar00rootroot00000000000000#!/bin/bash # # Process the entropy data ############################################################ # Configuration values # ############################################################ # point to the directory that contains the results from the entropy collection ENTROPYDATA_DIR=${ENTROPYDATA_DIR:-"../results-measurements"} # this is where the resulting data and the entropy analysis will be stored RESULTS_DIR=${RESULTS_DIR:-"../results-analysis-restart"} # location of log file LOGFILE="$RESULTS_DIR/processdata.log" # point to the min entropy tool EATOOL="../../SP800-90B_EntropyAssessment/cpp/ea_restart" # specify if you want to compile the extractlsb program in this script BUILD_EXTRACT=${BUILD_EXTRACT:-"yes"} # specify the list of significant bits and length that you want to analize. # Indicate first the mask in hexa format and then the number of # bits separated by a colon. # The tool generates one set of var and single data files, and the EA results # for each element. # The mask can have a maximum of 8 bits on, the EA tool only manages samples # up to one byte. # List of masks usually analyzed (4 and 8 LSB) MASK_LIST="0F:4 FF:8" # List used for ARM Cortext A9 and A7 processors #MASK_LIST="FF:4,8 7F8:4,8" # Maximum number of entries to be extracted from the original file MAX_EVENTS=1000000 ############################################################ # Code only after this line -- do not change # ############################################################ ############################# # Preparation ############################# INPUT="$ENTROPYDATA_DIR/jent-raw-noise-restart*.data" INPUTCONSOLIDATED="$RESULTS_DIR/jent-raw-noise-restart-consolidated.data" EXTRACT="extractlsb" CFILE="extractlsb.c" if [ ! -d $ENTROPYDATA_DIR ] then echo "Directory with raw entropy data $ENTROPYDATA_DIR is missing" exit 1 fi if [ ! -d $RESULTS_DIR ] then mkdir $RESULTS_DIR if [ $? -ne 0 ] then echo "Directory for results $RESULTS_DIR cannot be created" exit 1 fi fi if [ ! -f $EA_TOOL ] then echo "ERROR: Path of Entropy Data tool $EA_TOOL is missing" exit 1 fi trap "if [ "$BUILD_EXTRACT" = "yes" ]; then make clean; fi" 0 1 2 3 15 rm -f $EXEC if [ "$BUILD_EXTRACT" = "yes" ] then echo "Building $EXTRACT ..." make clean make fi if [ ! -x $EXTRACT ] then echo "ERROR: Cannot execute $EXTRACT program" exit 1 fi ############################# # Actual data processing ############################# # # Step 1: Concatenate all individual restart files into single file # rm -f $INPUTCONSOLIDATED for i in $INPUT do echo "Process recorded entropy data $i" cat $i >> $INPUTCONSOLIDATED done # # Step 2: extract data # for file in $INPUTCONSOLIDATED do filepath=$RESULTS_DIR/`basename ${file%%.data}` echo "Converting recorded entropy data $file into different bit output" | tee -a $LOGFILE for item in $MASK_LIST do mask=${item%:*} bits=${item#*:} ./$EXTRACT $file $filepath.${mask}bitout.var.data $filepath.${mask}bitout.single.data $MAX_EVENTS $mask 2>&1 | tee -a $LOGFILE done done # # Step 3: Calculate SP800-90B # # Just like in step 2, we calculate the entropy column-wise # echo "" | tee -a $LOGFILE echo "Extraction finished. Now analyzing entropy for noise source ..." | tee -a $LOGFILE echo "" | tee -a $LOGFILE for file in $INPUTCONSOLIDATED do filepath=$RESULTS_DIR/`basename ${file%%.data}` for item in $MASK_LIST do mask=${item%:*} bits_field=${item#*:} bits_list=`echo $bits_field | sed -e "s/,/ /g"` infilesingle=$filepath.${mask}bitout.single.data infilevar=$filepath.${mask}bitout.var.data for bits in $bits_list do outfile=${filepath}.minentropy_${mask}_${bits}bits.single.txt inprocess_file=$outfile if [ ! -f $outfile ] then echo "Analyzing entropy for $infilesingle ${bits}-bit single" | tee -a $LOGFILE $EATOOL -n -v $infilesingle ${bits} 0.333 > $outfile else echo "File $outfile already generated" fi outfile=${filepath}.minentropy_${mask}_${bits}bits.var.txt inprocess_file=$outfile if [ ! -f $outfile ] then echo "Analyzing entropy for $infilevar ${bits}-bit var" | tee -a $LOGFILE $EATOOL -n -v $infilevar ${bits} 0.333 > $outfile else echo "File $outfile already generated" fi done done done jitterentropy-library-3.6.3/tests/raw-entropy/validation-runtime-kernel/000077500000000000000000000000001500137124500266275ustar00rootroot00000000000000jitterentropy-library-3.6.3/tests/raw-entropy/validation-runtime-kernel/Makefile000066400000000000000000000014061500137124500302700ustar00rootroot00000000000000# Compile Noise Source as user space application CC ?= gcc override CFLAGS +=-pedantic -Wall -Wextra -O2 program_NAME := extractlsb #program_C_SRCS := $(wildcard *.c) program_C_SRCS := extractlsb.c program_C_OBJS := ${program_C_SRCS:.c=.o} program_OBJS := $(program_C_OBJS) program_INCLUDE_DIRS := program_LIBRARY_DIRS := program_LIBRARIES := CPPFLAGS += $(foreach includedir,$(program_INCLUDE_DIRS),-I$(includedir)) LDFLAGS += $(foreach librarydir,$(program_LIBRARY_DIRS),-L$(librarydir)) LDFLAGS += $(foreach library,$(program_LIBRARIES),-l$(library)) .PHONY: all clean distclean all: $(program_NAME) $(program_NAME): $(program_OBJS) $(CC) $(program_OBJS) -o $(program_NAME) $(LDFLAGS) clean: @- $(RM) $(program_NAME) @- $(RM) $(program_OBJS) distclean: clean jitterentropy-library-3.6.3/tests/raw-entropy/validation-runtime-kernel/README.md000066400000000000000000000233761500137124500301210ustar00rootroot00000000000000# Validation of Raw Entropy Data - Kernel This tool is used to calculate the minimum entropy values compliant to SP800-90B for the gathered data. The validation operation of the raw entropy data is invoked with the processdata.sh script. The sampling data from the recording operation must be post-processed. This is because you need to determine which part of the sample elements contain the high-resolution part of the time delta provided by the Jitter RNG. Usually, this occurs in the 4 to 8 least significant bits of the sample element, but it may vary depending on the processor. The first step is performed by the extractlsb program, which reads the input data, extracts the significant bits from each sample item (using a mask that you provide) and outputs it to a bit stream file. In the second step, the binary data streams are processed with the SP800-90B entropy assessment tool, which calculates the min entropy. The resulting minimum entropy for each data stream is provided in the *.minentropy file. The log file contains a summary of the steps performed and the output of the extractlsb program. ## Prerequisites To execute the testing, you need: * NIST SP800-90B tool from: https://github.com/usnistgov/SP800-90B_EntropyAssessment * Obtain the sample data recorded on the target platforms * Configure processdata.sh with proper parameter values ### Parameters of processdata.sh ENTROPYDATA_DIR: Location of the sample data files (with .data extension) RESULTS_DIR: Location for the interim data bit streams and results. LOGFILE: Name of the log file. The default is $RESULTS_DIR/processdata.log. EATOOL: Path of the python program used from the Entropy Assessment tool (usually, ea_noniid). BUILD_EXTRACT: Indicates whether the script will build the extractlsb program. The default is "yes". MASK_LIST: Indicates the extraction method from each sample item. You can indicate one or more methods; the script will generate one bit stream data file set for each extraction method. See below for a more detailed explanation. SAMPLES: the number of samples (time deltas) that will be extracted from the data. The default is 1000000, as specified in SP800-90B. ### Extraction method The kernel patch extracts raw time stamps. They are converted into time deltas by `extractlsb.c` to obtain the time deltas uses to insert into the entropy pool of the Jitter RNG. Although the samples elements collected from the JitterRNG (time deltas) have a size 64 bits, the entropy will likely be provided on the high resolution part, which is usually the least significant bits. Also, the python script that performs the SP800-90B entropy analysis has two limitations: * although the SP800-90B standard allows alphabets of any size, the script only processes alphabets up to 8 bits. * the script expects each sample to be contained in one byte. Therefore, if you want to use only the 4 LSB of each sample item, you'll need to generate one byte per each 4-bit symbol. You need to analyze the sample and determine which bit positions provide the high-resolution time deltas that will feed the entropy analysis. Usually, you can assume that the high-resolution time delta is represented in the least significant 4 or 8 bits. So you specify the MASK_LIST parameter as follows: MASK_LIST="0F:4 FF:8" This parameter value means the following: * There will be two extractions methods for each data set. * The first method takes the 4 LSB from each sample item, generates one byte per sample item, and uses a 4-bit alphabet for analyzing entropy. * The second method takes the 8 LSB from each sample item, generates one byte per item, and uses an 8-bit alphabet for analyzing entropy. The parameter is a list of extraction methods. Each extraction method is represented by two fields separated by a colon: * A mask in hexadecimal format, that indicates which bits are significant. If the bit is on in a given position, this bit will be considered to form the final byte. Otherwise, it'll be discarded. For instance, a mask of "F8" means that the 3 LSB will be discarded, and the bits 4 to 8 will be used; a mask of "7F8", means that the 3 LSB will be discarded, and bits 4 to 10 will be used. The bit values are shifted so all bit positions in the final byte are used. * The second value is the alphabet size in bits. This is redundant but required to avoid complex calculations in bash. You can start with the default values, and then refine your extraction methods if necessary. You may find that the LSB of the samples do not provide entropy, then use a different mask to discard them. The output of the extractlsb program can be used to detect this scenarios. The program shows a summary of the extraction, indicating the bit positions that have not changed in any of the samples. For example, this is the output of the extraction program. Processed 1000000 items from ./extractlsb samples with mask [0x00000000000000ff] significant bits [8] Constant 0s in sample: 00000000 00000000 00000000 00000000 --000-00 0---0--- -------- -----000 Constant 1s in sample: -------- -------- -------- -------- -------- -------- -------- -------- You can see here that the 3 LSB of the samples always show zeroes (the minus means that this position is variable). There you can easily determine which positions you should consider. In this particular case, you should use a mask of "78:4" and "7F8:8" to analyze the samples with 4-bit and 8-bit alphabets, discarding the 3 LSB. ## Conclusion The conclusion you have to draw is the following: To generate a 64 bit block, the Jitter RNG obtains 64 time deltas (one time delta per bit at least, unless the Jitter RNG performs oversampling). So, if you obtain a result that the minimum entropy is more than 1 bit of entropy (per time delta), the one block of 64 data bits is believed to have (close to) 64 bits of entropy. Otherwise it will have relatively less entropy. Please note that the minimum collision entropy value for 8 bits may be smaller than the 4 bit values due to the inclusion of leading zeros. This, however is a data processing problem that should be considered when drawing conclusions. One can see the effect of these leading zeros by compressing the 4 bit and 8 bit data streams. Whereas the 4 bit data stream may not be compressable, the 8 bit data stream may be compressed This may also occur when the least significant bits in the time delta do not change. You need to refine the extraction method to reach to the right calculation. # Example Assessment of Results The file foldtime.O0 contains test results for the non-optimized binary code that is the basis for the Jitter RNG. To understand what it shows, we have to understand what the Jitter RNG really does: it simply measures the execution time of a fixed code fragment. The test does the same, i.e. it measures what the Jitter RNG would measure. Each time delta is simply recorded. Each time delta is expected to contribute entropy to the entropy pool. But how much? We can use the SP800-90B tool set provided by NIST at [1]. This tool, however, can only process input data with a window size of a few bits at most. Thus, we take the 4 LSB of each time delta, hoping that they contain already sufficient entropy. Using the tool [1], we get the following output: Number of Binary Symbols: 4000000 Symbol alphabet consists of 16 unique symbols Running non-IID tests... Running Most Common Value Estimate... Most Common Value Estimate (bit string) = 0.997853 / 1 bit(s) Running Entropic Statistic Estimates (bit strings only)... Collision Test Estimate (bit string) = 0.933346 / 1 bit(s) Markov Test Estimate (bit string) = 0.999810 / 1 bit(s) Compression Test Estimate (bit string) = 0.749885 / 1 bit(s) Running Tuple Estimates... T-Tuple Test Estimate (bit string) = 0.927240 / 1 bit(s) LRS Test Estimate (bit string) = 0.997939 / 1 bit(s) Running Predictor Estimates... Multi Most Common in Window (MultiMCW) Prediction Test Estimate (bit string) = 0.998260 / 1 bit(s) Lag Prediction Test Estimate (bit string) = 0.998753 / 1 bit(s) Multi Markov Model with Counting (MultiMMC) Prediction Test Estimate (bit string) = 0.998283 / 1 bit(s) LZ78Y Prediction Test Estimate (bit string) = 0.999020 / 1 bit(s) h': 0.749885 The last line is the key: it contains the minimum entropy in one bit of the 4 bit snapshot - we have 0.749885 bits of entropy per data bit - as we analyzed 4 bits of each time delta, we get 4 * 0.749885 = 2.99954 bits of entropy per four bit time delta - assuming the worst case that all other bits in the time delta have no entropy, we have 2.99954 bits of entropy per time delta - the Jitter RNG gathers 64 time deltas for returning 64 bits of random data and it uses an LFSR with a primitive and irreducible polynomial which is entropy preserving. Thus, the Jitter RNG collected 64 * 2.99954 = 191.97056 bits of entropy for its 64 bit output. - as the Jitter RNG maintains a 64 bit entropy pool, its entropy content cannot be larger than the pool itself. Thus, the entropy content in the pool after collecting 64 time deltas is max(64 bits, 191.97056 bits) = 64 bits This implies that the Jitter RNG data has (close to) 64 bits of entropy per data bit. Bottom line: When the Jitter RNG injects 64 bits of data into the Linux /dev/ random via the IOCTL, it is appropriate that the entropy estimator increases by 64 bits. Bottom line: From my perspective, I see no issue in using the Jitter RNG as a noise source in your environments. Note, applying the Shannon-Entropy formula to the data, we will get much higher entropy values. Note II: This assessment complies with the entropy assessments to be done for a NIST FIP 140-2 validation compliant to FIPS 140-2 IG 7.15 [1] https://github.com/usnistgov/SP800-90B_EntropyAssessment jitterentropy-library-3.6.3/tests/raw-entropy/validation-runtime-kernel/extractlsb.c000066400000000000000000000113041500137124500311450ustar00rootroot00000000000000/* * Copyright (C) 2019 - 2025, Stephan Mueller * * License: see LICENSE file in root directory * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH * DAMAGE. */ /* * The tool extracts the 4 or 8 LSB of the high-res time stamp and * concatenates them to form a binary data stream. * */ #include #include #include #include #include #include #include #include #define BITS_PER_SAMPLE 64 /* Extract bits from sample based on significant bit mask */ static unsigned char extract(uint64_t sample, uint64_t mask) { unsigned char byte = 0; int i, j = 0; for (i = 0; i < BITS_PER_SAMPLE && mask; i++) { if (mask & 1) { byte |= (sample & 1) << j; j++; } mask >>= 1; sample >>= 1; } return byte; } /* Convert mask in hexadecimal format to binary */ static int hextolong(char *p_strmask, uint64_t *p_mask) { uint64_t mask = 0; int count = 0; while (*p_strmask) { count++; mask <<= 4; if ((*p_strmask >= '0') && (*p_strmask <= '9')) mask |= *p_strmask - '0'; else if ((*p_strmask >= 'A') && (*p_strmask <= 'F')) mask |= *p_strmask - 'A' + 10; else if ((*p_strmask >= '0') && (*p_strmask <= '9')) mask |= *p_strmask - 'a' + 10; else return -1; p_strmask++; } if (count > 16) return -1; *p_mask = mask; return 0; } /* Count the number of bits on */ static int bitcount(uint64_t mask) { int i, j = 0; for (i = 0; i < BITS_PER_SAMPLE && mask; i++) { if (mask & 1) { j++; } mask >>= 1; } return j; } /* Print 64 bits of long word masking with '-' those not matching value */ static char *printbits(uint64_t sample, int value) { static char buf[BITS_PER_SAMPLE + 9]; char *p_buf = buf + sizeof(buf) - 1; int i; *p_buf-- = '\0'; for (i = 0; i < BITS_PER_SAMPLE; i++) { if (i % 8 == 0) *p_buf-- = ' '; if ((sample & 1) ^ value) *p_buf = '-'; else *p_buf = '0' + value; p_buf--; sample >>= 1; } return buf; } int main(int argc, char *argv[]) { FILE *f = NULL; char buf[64]; int outfd = -1; uint32_t count; uint32_t i = 0; int prev_timestamp_set = 0; uint64_t prev_timestamp = 0; uint64_t mask; uint64_t unchanged0s, unchanged1s; int rc; if (argc != 5) { printf("Usage: %s inputfile outfile samples mask\n", argv[0]); return 1; } f = fopen(argv[1], "r"); if (!f) { printf("File %s cannot be opened for read\n", argv[1]); return 1; } outfd = open(argv[2], O_CREAT|O_WRONLY|O_EXCL, 0777); if (outfd < 0) { printf("File %s cannot be opened for write\n", argv[2]); fclose(f); return 1; } count = strtoul(argv[3], NULL, 10); rc = hextolong(argv[4], &mask); if (rc) { printf("Mask value is incorrect [%s], use up to 16 hexadecimal characters\n", argv[5]); fclose(f); close(outfd); return 1; } if (bitcount(mask) > 8) { printf("SP800-90B tool only supports up to 8 bits. Check the mask value\n"); fclose(f); close(outfd); return 1; } unchanged0s = 0; unchanged1s = ~0; while (fgets(buf, sizeof(buf), f)) { uint64_t timestamp, delta; unsigned char extracted; // Ignore empty lines. if (buf[0] == '\0' || buf[0] == '\n' || buf[0] == '\r') { continue; } timestamp = strtoul(buf, NULL, 10); if (!prev_timestamp_set) { prev_timestamp = timestamp; prev_timestamp_set = 1; continue; } delta = timestamp - prev_timestamp; prev_timestamp = timestamp; unchanged0s |= delta; unchanged1s &= delta; extracted = extract(delta, mask); write(outfd, &extracted, sizeof(extracted)); i += 1; if (i == count) break; } if (i < count) { printf("Attempted to extract %d samples from %s but only got %d samples\n", count, argv[0], i); fclose(f); close(outfd); return 1; } printf("Processed %d samples from %s with mask [0x%016llx] significant bits [%d]\n", i, argv[0], (unsigned long long)mask, bitcount(mask)); printf("Constant 0s in sample: \n%s\n", printbits(unchanged0s, 0)); printf("Constant 1s in sample: \n%s\n", printbits(unchanged1s, 1)); fclose(f); close(outfd); return 0; } jitterentropy-library-3.6.3/tests/raw-entropy/validation-runtime-kernel/processdata.sh000077500000000000000000000071131500137124500315000ustar00rootroot00000000000000#!/bin/bash # # Process the entropy data ############################################################ # Configuration values # ############################################################ # point to the directory that contains the results from the entropy collection ENTROPYDATA_DIR=${ENTROPYDATA_DIR:-"../results-measurements"} # this is where the resulting data and the entropy analysis will be stored RESULTS_DIR=${RESULTS_DIR:-"../results-analysis-runtime"} # location of log file LOGFILE="$RESULTS_DIR/processdata.log" # point to the min entropy tool EATOOL="../SP800-90B_EntropyAssessment/cpp/ea_non_iid" # specify if you want to compile the extractlsb program in this script BUILD_EXTRACT=${BUILD_EXTRACT:-"yes"} # specify the list of significant bits and length that you want to analize. # Indicate first the mask in hexa format and then the number of # bits separated by a colon. # The tool generates one set of var and single data files, and the EA results # for each element. # The mask can have a maximum of 8 bits on, the EA tool only manages samples # up to one byte. # List of masks usually analyzed (4 and 8 LSB) MASK_LIST="0F:4 FF:8" # List used for ARM Cortext A9 and A7 processors #MASK_LIST="FF:4,8 7F8:4,8" # Number of samples to be extracted from the original file SAMPLES=1000000 ############################################################ # Code only after this line -- do not change # ############################################################ ############################# # Preparation ############################# EXTRACT="extractlsb" CFILE="extractlsb.c" if [ ! -d $ENTROPYDATA_DIR ] then echo "ERROR: Directory with raw entropy data $ENTROPYDATA_DIR is missing" exit 1 fi if [ ! -d $RESULTS_DIR ] then mkdir $RESULTS_DIR if [ $? -ne 0 ] then echo "ERROR: Directory for results $RESULTS_DIR could not be created" exit 1 fi fi if [ ! -f $EATOOL ] then echo "ERROR: Path of Entropy Data tool $EATOOL is missing" exit 1 fi rm -f $RESULTS_DIR/*.txt $RESULTS_DIR/*.data $RESULTS_DIR/*.log trap "if [ "$BUILD_EXTRACT" = "yes" ]; then make clean; fi" 0 1 2 3 15 if [ "$BUILD_EXTRACT" = "yes" ] then echo "Building $EXTRACT ..." make clean make fi if [ ! -x $EXTRACT ] then echo "ERROR: Cannot execute $EXTRACT program" exit 1 fi ############################# # Actual data processing ############################# # # Step 1: Convert input file # for item in $MASK_LIST do mask=${item%:*} echo "Converting recorded entropy data into different bit output with mask $mask..." | tee -a $LOGFILE out_file=$RESULTS_DIR/raw_noise.${mask}bitout.data rm -f $out_file in_file=$ENTROPYDATA_DIR/jent_raw_noise.data if [ ! -f $in_file ] then echo "ERROR: File $in_file not found" exit 1 fi echo "Converting recorded entropy data $in_file into different bit output with mask $mask" >> $LOGFILE ./$EXTRACT $in_file $out_file $SAMPLES $mask >> $LOGFILE 2>&1 done echo "" | tee -a $LOGFILE echo "Extraction finished. Now analyzing entropy for noise source ..." | tee -a $LOGFILE echo "" | tee -a $LOGFILE # # Step 2: Perform SP800-90B analysis # for item in $MASK_LIST do mask=${item%:*} bits_field=${item#*:} bits_list=`echo $bits_field | sed -e "s/,/ /g"` in_file=$RESULTS_DIR/raw_noise.${mask}bitout.data for bits in $bits_list do out_file=$RESULTS_DIR/raw_noise.minentropy_${mask}_${bits}bits.txt if [ ! -f $out_file ] then echo "Analyzing entropy for $out_file ${bits}-bit..." | tee -a $LOGFILE $EATOOL $in_file ${bits} -i -a -v > $out_file else echo "File $out_file already generated" fi done done jitterentropy-library-3.6.3/tests/raw-entropy/validation-runtime/000077500000000000000000000000001500137124500253515ustar00rootroot00000000000000jitterentropy-library-3.6.3/tests/raw-entropy/validation-runtime/Makefile000066400000000000000000000014111500137124500270060ustar00rootroot00000000000000# Compile Noise Source as user space application CC ?= gcc override CFLAGS +=-pedantic -Wall -Wextra -O2 program_NAME := extractlsb #program_C_SRCS := $(wildcard *.c) program_C_SRCS := extractlsb.c program_C_OBJS := ${program_C_SRCS:.c=.o} program_OBJS := $(program_C_OBJS) program_INCLUDE_DIRS := program_LIBRARY_DIRS := program_LIBRARIES := rt CPPFLAGS += $(foreach includedir,$(program_INCLUDE_DIRS),-I$(includedir)) LDFLAGS += $(foreach librarydir,$(program_LIBRARY_DIRS),-L$(librarydir)) LDFLAGS += $(foreach library,$(program_LIBRARIES),-l$(library)) .PHONY: all clean distclean all: $(program_NAME) $(program_NAME): $(program_OBJS) $(CC) $(program_OBJS) -o $(program_NAME) $(LDFLAGS) clean: @- $(RM) $(program_NAME) @- $(RM) $(program_OBJS) distclean: clean jitterentropy-library-3.6.3/tests/raw-entropy/validation-runtime/README.md000066400000000000000000000242201500137124500266300ustar00rootroot00000000000000# Validation of Raw Entropy Data This tool is used to calculate the minimum entropy values compliant to SP800-90B for the gathered data. The validation operation of the raw entropy data is invoked with the processdata.sh script. The sampling data from the recording operation must be post-processed. This is because you need to determine which part of the sample elements contain the high-resolution part of the time delta provided by the Jitter RNG. Usually, this occurs in the 4 to 8 least significant bits of the sample element, but it may vary depending on the processor. The first step is performed by the extractlsb program, which reads the input data, extracts the significant bits from each sample item (using a mask that you provide) and split it in two bit stream files, one containing the var sample, and the other the single sample. In the second step, the binary data streams are processed with the SP800-90B entropy assessment tool, which calculates the min entropy. The resulting minimum entropy for each data stream is provided in the *.minentropy file. The log file contains a summary of the steps performed and the output of the extractlsb program. ## Prerequisites To execute the testing, you need: * NIST SP800-90B tool from: https://github.com/usnistgov/SP800-90B_EntropyAssessment * Obtain the sample data recorded on the target platforms * Configure processdata.sh with proper parameter values ### Parameters of processdata.sh ENTROPYDATA_DIR: Location of the sample data files (with .data extension) RESULTS_DIR: Location for the interim data bit streams (var and single), and results. LOGFILE: Name of the log file. The default is $RESULTS_DIR/processdata.log. EATOOL: Path of the python program used from the Entropy Assessment tool (usually, noniid_main.py). BUILD_EXTRACT: Indicates whether the script will build the extractlsb program. The default is "yes". MASK_LIST: Indicates the extraction method from each sample item. You can indicate one or more methods; the script will generate one bit stream data file set (var and single) for each extraction method. See below for a more detailed explanation. MAX_EVENTS: the size of the sample that will be extracted from the sample data. The default is 100000 (a 1% of the size of the sample file specified in the ROUNDS define macro). Notice that the minimum value suggested by SP800-90B is 1000000, so you'll have to increase the default value (notice that this severily impacts in the performance and memory requirements of the python tool). ### Extraction method Although the samples elements collected from the JitterRNG (time deltas) have a size 64 bits, the entropy will likely be provided on the high resolution part, which is usually the least significant bits. Also, the python script that performs the SP800-90B entropy analysis has two limitations: * although the SP800-90B standard allows alphabets of any size, the script only processes alphabets up to 8 bits. * the script expects each sample to be contained in one byte. Therefore, if you want to use only the 4 LSB of each sample item, you'll need to generate one byte per each 4-bit symbol. You need to analyze the sample and determine which bit positions provide the high-resolution time deltas that will feed the entropy analysis. Usually, you can assume that the high-resolution time delta is represented in the least significant 4 or 8 bits. So you specify the MASK_LIST parameter as follows: MASK_LIST="0F:4 FF:8" This parameter value means the following: * There will be two extractions methods for each data set. * The first method takes the 4 LSB from each sample item, generates one byte per sample item, and uses a 4-bit alphabet for analyzing entropy. * The second method takes the 8 LSB from each sample item, generates one byte per item, and uses an 8-bit alphabet for analyzing entropy. The parameter is a list of extraction methods. Each extraction method is represented by two fields separated by a colon: * A mask in hexadecimal format, that indicates which bits are significant. If the bit is on in a given position, this bit will be considered to form the final byte. Otherwise, it'll be discarded. For instance, a mask of "F8" means that the 3 LSB will be discarded, and the bits 4 to 8 will be used; a mask of "7F8", means that the 3 LSB will be discarded, and bits 4 to 10 will be used. The bit values are shifted so all bit positions in the final byte are used. * The second value is the alphabet size in bits. This is redundant but required to avoid complex calculations in bash. You can start with the default values, and then refine your extraction methods if necessary. You may find that the LSB of the samples do not provide entropy, then use a different mask to discard them. The output of the extractlsb program can be used to detect this scenarios. The program shows a summary of the extraction, indicating the bit positions that have not changed in any of the samples. For example, this is the output of the extraction program. Processed 1000000 items from ./extractlsb samples with mask [0x00000000000000ff] significant bits [8] Constant 0s in var sample: 00000000 00000000 00000000 00000000 --000-00 0---0--- -------- -----000 Constant 1s in var sample: -------- -------- -------- -------- -------- -------- -------- -------- Constant 0s in single sample: 00000000 00000000 00000000 00000000 --000-00 0--00--- -------- -----000 Constant 1s in single sample: -------- -------- -------- -------- -------- -------- -------- -------- You can see here that the 3 LSB of both samples (var and single) always show zeroes (the minus means that this position is variable). There you can easily determine which positions you should consider. In this particular case, you should use a mask of "78:4" and "7F8:8" to analyze the samples with 4-bit and 8-bit alphabets, discarding the 3 LSB. ## Conclusion The conclusion you have to draw is the following: To generate a 64 bit block, the Jitter RNG obtains 64 time deltas (one time delta per bit at least, unless the Jitter RNG performs oversampling). So, if you obtain a result that the minimum entropy is more than 1 bit of entropy (per time delta), the one block of 64 data bits is believed to have (close to) 64 bits of entropy. Otherwise it will have relatively less entropy. Please note that the minimum collision entropy value for 8 bits may be smaller than the 4 bit values due to the inclusion of leading zeros. This, however is a data processing problem that should be considered when drawing conclusions. One can see the effect of these leading zeros by compressing the 4 bit and 8 bit data streams. Whereas the 4 bit data stream may not be compressable, the 8 bit data stream may be compressed This may also occur when the least significant bits in the time delta do not change. You need to refine the extraction method to reach to the right calculation. # Example Assessment of Results The file foldtime.O0 contains test results for the non-optimized binary code that is the basis for the Jitter RNG. To understand what it shows, we have to understand what the Jitter RNG really does: it simply measures the execution time of a fixed code fragment. The test does the same, i.e. it measures what the Jitter RNG would measure. Each time delta is simply recorded. Each time delta is expected to contribute entropy to the entropy pool. But how much? We can use the SP800-90B tool set provided by NIST at [1]. This tool, however, can only process input data with a window size of a few bits at most. Thus, we take the 4 LSB of each time delta, hoping that they contain already sufficient entropy. Using the tool [1], we get the following output: Number of Binary Symbols: 4000000 Symbol alphabet consists of 16 unique symbols Running non-IID tests... Running Most Common Value Estimate... Most Common Value Estimate (bit string) = 0.997853 / 1 bit(s) Running Entropic Statistic Estimates (bit strings only)... Collision Test Estimate (bit string) = 0.933346 / 1 bit(s) Markov Test Estimate (bit string) = 0.999810 / 1 bit(s) Compression Test Estimate (bit string) = 0.749885 / 1 bit(s) Running Tuple Estimates... T-Tuple Test Estimate (bit string) = 0.927240 / 1 bit(s) LRS Test Estimate (bit string) = 0.997939 / 1 bit(s) Running Predictor Estimates... Multi Most Common in Window (MultiMCW) Prediction Test Estimate (bit string) = 0.998260 / 1 bit(s) Lag Prediction Test Estimate (bit string) = 0.998753 / 1 bit(s) Multi Markov Model with Counting (MultiMMC) Prediction Test Estimate (bit string) = 0.998283 / 1 bit(s) LZ78Y Prediction Test Estimate (bit string) = 0.999020 / 1 bit(s) h': 0.749885 The last line is the key: it contains the minimum entropy in one bit of the 4 bit snapshot - we have 0.749885 bits of entropy per data bit - as we analyzed 4 bits of each time delta, we get 4 * 0.749885 = 2.99954 bits of entropy per four bit time delta - assuming the worst case that all other bits in the time delta have no entropy, we have 2.99954 bits of entropy per time delta - the Jitter RNG gathers 64 time deltas for returning 64 bits of random data and it uses an LFSR with a primitive and irreducible polynomial which is entropy preserving. Thus, the Jitter RNG collected 64 * 2.99954 = 191.97056 bits of entropy for its 64 bit output. - as the Jitter RNG maintains a 64 bit entropy pool, its entropy content cannot be larger than the pool itself. Thus, the entropy content in the pool after collecting 64 time deltas is max(64 bits, 191.97056 bits) = 64 bits This implies that the Jitter RNG data has (close to) 64 bits of entropy per data bit. Bottom line: When the Jitter RNG injects 64 bits of data into the Linux /dev/ random via the IOCTL, it is appropriate that the entropy estimator increases by 64 bits. Bottom line: From my perspective, I see no issue in using the Jitter RNG as a noise source in your environments. Note, applying the Shannon-Entropy formula to the data, we will get much higher entropy values. Note II: This assessment complies with the entropy assessments to be done for a NIST FIP 140-2 validation compliant to FIPS 140-2 IG 7.15 [1] https://github.com/usnistgov/SP800-90B_EntropyAssessment jitterentropy-library-3.6.3/tests/raw-entropy/validation-runtime/analyze_options.sh000077500000000000000000000045651500137124500311400ustar00rootroot00000000000000#!/bin/bash # # Tool to validate the test results for various Jitter RNG memory settings # # This tool is only needed if you have insufficient entropy. See ../README.md # for details # RESULT="../results-runtime-multi" ENT_DIR="../results-measurements" RES_DIR="../results-analysis-runtime" NUM_CPU=1 USED_CPUS=0 trap "make clean" 0 1 2 3 15 make clean make crunch_numbers() { local source=$1 local target=$2 if [ $USED_CPUS -eq $NUM_CPU ] then # wait for all wait USED_CPUS=0 fi if [ ! -d $target ] then USED_CPUS=$(($USED_CPUS+1)) ( BUILD_EXTRACT="no" ENTROPYDATA_DIR=$source RESULTS_DIR=$target ./processdata.sh ) & fi } linearmem_written=0 calc() { local crunch=$1 for memsize in 32768 65536 131072 262144 524288 1048576 2097152 4194304 8388608 16777216 33554432 67108864 134217728 268435456 536870912 do for blocks in 64 128 256 512 1024 2048 4096 8192 16384 do for blocksize in 32 64 128 256 512 1024 2048 4096 8192 16384 do local target="$RES_DIR-${blocks}blocks-${blocksize}blocksize-${memsize}bytes" local source="$ENT_DIR-${blocks}blocks-${blocksize}blocksize-${memsize}bytes" if [ ! -d "$source" ] then continue fi if [ $linearmem_written -eq 0 ] then echo -e "Max memory size\tNumber of blocks\tBlocksize\tmin entropy" > $RESULT linearmem_written=1 fi if [ $crunch -eq 0 ] then ent=$(grep min $target/jent-raw-noise-0001.minentropy_FF_8bits.var.txt | cut -d ":" -f 2) echo -e "$memsize\t$blocks\t$blocksize\t$ent" >> $RESULT else crunch_numbers $source $target fi done done done } randmem_written=0 calc_randmem() { local crunch=$1 for bits in 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 do local target="$RES_DIR-random_memaccess-${bits}bits" local source="$ENT_DIR-random_memaccess-${bits}bits" if [ ! -d "$source" ] then continue fi if [ $randmem_written -eq 0 ] then echo -e "Number of bits\tmin entropy" > $RESULT randmem_written=1 fi if [ $crunch -eq 0 ] then ent=$(grep min $target/jent-raw-noise-0001.minentropy_FF_8bits.var.txt | cut -d ":" -f 2) echo -e "$bits\t$ent" >> $RESULT else crunch_numbers $source $target fi done } if [ -f /proc/cpuinfo ] then NUM_CPU=$(cat /proc/cpuinfo | grep processor | tail -n1 | cut -d":" -f 2) NUM_CPU=$(($NUM_CPU+1)) fi calc_randmem 1 wait calc_randmem 0 calc 1 wait calc 0 jitterentropy-library-3.6.3/tests/raw-entropy/validation-runtime/draw_graph_analyze_options.r000066400000000000000000000020231500137124500331450ustar00rootroot00000000000000# Plot data from IRQ duration table # # 1. create results-runtime-multi with analyze_options.sh: # # $ cat results-runtime-multi # Number of bits min entropy # 10 0.406505 # 11 0.445082 # 12 0.402972 # 13 0.459021 # 14 0.436911 # 15 0.578995 # 16 0.643272 # 17 0.573532 # 18 0.627915 # 19 0.503923 # 20 0.720609 # 21 1.871527 # 22 2.491569 # 23 2.481533 # 24 2.493987 # 25 2.491303 # 26 2.495017 # # 2. Generate plot: Rscript --vanilla draw_graph_analyze_options.r results-runtime-multi # args <- commandArgs(trailingOnly = TRUE) if (length(args) != 1) { stop("Invoke with ") } file <- args[1] data <- read.csv(file=file, header=TRUE, sep="\t") pdf("memory_access_times.pdf", width=8, height=5, pointsize=10) # print software plot(data[,1], data[,2], type="b", col="red", main="Memory Access Time Variations", pch=19, xlab="Memory size in powers of 2", ylab="SP800-90B Min Entropy", ylim=c(min(data[,2]), max(data[,2]))) jitterentropy-library-3.6.3/tests/raw-entropy/validation-runtime/extractlsb.c000066400000000000000000000120551500137124500276730ustar00rootroot00000000000000/* * Copyright (C) 2019 - 2025, Stephan Mueller * * License: see LICENSE file in root directory * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH * DAMAGE. */ /* * The tool extracts the 4 or 8 LSB of the high-res time stamp and * concatenates them to form a binary data stream. * */ #include #include #include #include #include #include #include #include #define BITS_PER_SAMPLE 64 /* Extract bits from sample based on significant bit mask */ static unsigned char extract(uint64_t sample, uint64_t mask) { unsigned char byte = 0; int i, j = 0; for (i = 0; i < BITS_PER_SAMPLE && mask; i++) { if (mask & 1) { byte |= (sample & 1) << j; j++; } mask >>= 1; sample >>= 1; } return (byte); } /* Convert mask in hexadecimal format to binary */ static int hextolong(char *p_strmask, uint64_t *p_mask) { uint64_t mask = 0; int count = 0; while (*p_strmask) { count++; mask <<= 4; if ((*p_strmask >= '0') && (*p_strmask <= '9')) mask |= *p_strmask - '0'; else if ((*p_strmask >= 'A') && (*p_strmask <= 'F')) mask |= *p_strmask - 'A' + 10; else if ((*p_strmask >= '0') && (*p_strmask <= '9')) mask |= *p_strmask - 'a' + 10; else return -1; p_strmask++; } if (count > 16) return(-1); *p_mask = mask; return(0); } /* Count the number of bits on */ static int bitcount(uint64_t mask) { int i, j = 0; for (i = 0; i < BITS_PER_SAMPLE && mask; i++) { if (mask & 1) { j++; } mask >>= 1; } return (j); } /* Print 64 bits of long word masking with '-' those not matching value */ static char *printbits(uint64_t sample, int value) { static char buf[BITS_PER_SAMPLE + 9]; char *p_buf = buf + sizeof(buf) - 1; int i; *p_buf-- = '\0'; for (i = 0; i < BITS_PER_SAMPLE; i++) { if (i % 8 == 0) *p_buf-- = ' '; if ((sample & 1) ^ value) *p_buf = '-'; else *p_buf = '0' + value; p_buf--; sample >>= 1; } return buf; } int main(int argc, char *argv[]) { FILE *f = NULL; char buf[64]; int varfd = -1; int singlefd = -1; uint32_t count; uint32_t i = 0; uint64_t mask; uint64_t var_unchanged0s, var_unchanged1s; uint64_t single_unchanged0s, single_unchanged1s; int rc; if (argc != 6) { printf("Usage: %s inputfile varoutfile singleoutfile maxevents mask\n", argv[0]); return 1; } f = fopen(argv[1], "r"); if (!f) { printf("File %s cannot be opened for read\n", argv[1]); return 1; } varfd = open(argv[2], O_CREAT|O_WRONLY|O_EXCL, 0777); if (varfd < 0) { printf("File %s cannot be opened for write\n", argv[2]); fclose(f); return 1; } singlefd = open(argv[3], O_CREAT|O_WRONLY|O_EXCL, 0777); if (singlefd < 0) { printf("File %s cannot be opened for write\n", argv[3]); fclose(f); close(varfd); return 1; } count = strtoul(argv[4], NULL, 10); rc = hextolong(argv[5], &mask); if (rc) { printf("Mask value is incorrect [%s], use up to 16 hexadecimal characters", argv[5]); return 1; } if (bitcount(mask) > 8) { printf("SP800-90B tool only supports up to 8 bits. Check the mask value"); return 1; } var_unchanged0s = 0; var_unchanged1s = ~0; single_unchanged0s = 0; single_unchanged1s = ~0; while (fgets(buf, sizeof(buf), f)) { uint64_t sample; unsigned char var, single; char *saveptr = NULL; char *res = NULL; i++; res = strtok_r(buf, " ", &saveptr); if (!res) { printf("strtok_r error\n"); return 1; } sample = strtoul(res, NULL, 10); var_unchanged0s |= sample; var_unchanged1s &= sample; var = extract(sample, mask); write(varfd, &var, sizeof(var)); res = strtok_r(NULL, " ", &saveptr); if (!res) { sample = strtoul(res, NULL, 10); single_unchanged0s |= sample; single_unchanged1s &= sample; single = extract(sample, mask); write(singlefd, &single, sizeof(single)); } if (i >= count) break; } printf("Processed %d items from %s samples with mask [0x%016llx] significant bits [%d]\n", i, argv[0], (unsigned long long)mask, bitcount(mask)); printf("Constant 0s in var sample: \n%s\n", printbits(var_unchanged0s, 0)); printf("Constant 1s in var sample: \n%s\n", printbits(var_unchanged1s, 1)); printf("Constant 0s in single sample: \n%s\n", printbits(single_unchanged0s, 0)); printf("Constant 1s in single sample: \n%s\n", printbits(single_unchanged1s, 1)); fclose(f); close(varfd); close(singlefd); return 0; } jitterentropy-library-3.6.3/tests/raw-entropy/validation-runtime/processdata.sh000077500000000000000000000076651500137124500302360ustar00rootroot00000000000000#!/bin/bash # # Process the entropy data ############################################################ # Configuration values # ############################################################ # point to the directory that contains the results from the entropy collection ENTROPYDATA_DIR=${ENTROPYDATA_DIR:-"../results-measurements"} NONIID_DATA="jent-raw-noise-0001.data" # this is where the resulting data and the entropy analysis will be stored RESULTS_DIR=${RESULTS_DIR:-"../results-analysis-runtime"} # location of log file LOGFILE="$RESULTS_DIR/processdata.log" # point to the min entropy tool EATOOL_NONIID="../../SP800-90B_EntropyAssessment/cpp/ea_non_iid" # specify if you want to compile the extractlsb program in this script BUILD_EXTRACT=${BUILD_EXTRACT:-"yes"} # specify the list of significant bits and length that you want to analize. # Indicate first the mask in hexa format and then the number of # bits separated by a colon. # The tool generates one set of var and single data files, and the EA results # for each element. # The mask can have a maximum of 8 bits on, the EA tool only manages samples # up to one byte. # List of masks usually analyzed (4 and 8 LSB) MASK_LIST="0F:4 FF:8" # List used for ARM Cortext A9 and A7 processors #MASK_LIST="FF:4,8 7F8:4,8" # Maximum number of entries to be extracted from the original file MAX_EVENTS=1000000 ############################################################ # Code only after this line -- do not change # ############################################################ EXTRACT="extractlsb" CFILE="extractlsb.c" if [ ! -d $ENTROPYDATA_DIR ] then echo "ERROR: Directory with raw entropy data $ENTROPYDATA_DIR is missing" exit 1 fi if [ ! -d $RESULTS_DIR ] then mkdir $RESULTS_DIR if [ $? -ne 0 ] then echo "ERROR: Directory with raw entropy data $RESULTS_DIR could not be created" exit 1 fi fi if [ ! -f $EA_TOOL ] then echo "ERROR: Path of Entropy Data tool $EA_TOOL is missing" exit 1 fi rm -f $RESULTS_DIR/*.txt $RESULTS_DIR/*.data $RESULTS_DIR/*.log trap "if [ "$BUILD_EXTRACT" = "yes" ]; then make clean; fi" 0 1 2 3 15 if [ "$BUILD_EXTRACT" = "yes" ] then echo "Building $EXTRACT ..." make clean make fi if [ ! -x $EXTRACT ] then echo "ERROR: Cannot execute $EXTRACT program" exit 1 fi for file in $ENTROPYDATA_DIR/$NONIID_DATA do filepath=$RESULTS_DIR/`basename ${file%%.data}` echo "Converting recorded entropy data $file into different bit output" | tee -a $LOGFILE for item in $MASK_LIST do mask=${item%:*} bits=${item#*:} ./$EXTRACT $file $filepath.${mask}bitout.var.data $filepath.${mask}bitout.single.data $MAX_EVENTS $mask 2>&1 | tee -a $LOGFILE done done echo "" | tee -a $LOGFILE echo "Extraction finished. Now analyzing entropy for noise source ..." | tee -a $LOGFILE echo "" | tee -a $LOGFILE for file in $ENTROPYDATA_DIR/$NONIID_DATA do filepath=$RESULTS_DIR/`basename ${file%%.data}` for item in $MASK_LIST do mask=${item%:*} bits_field=${item#*:} bits_list=`echo $bits_field | sed -e "s/,/ /g"` infilesingle=$filepath.${mask}bitout.single.data infilevar=$filepath.${mask}bitout.var.data for bits in $bits_list do outfile=${filepath}.minentropy_${mask}_${bits}bits.single.txt inprocess_file=$outfile if [ ! -f $outfile ] then echo "Analyzing entropy for $infilesingle ${bits}-bit single" | tee -a $LOGFILE #python -u $EATOOL_NONIID -v $infilesingle $bits > $outfile $EATOOL_NONIID -i -a -v $infilesingle ${bits} > $outfile else echo "File $outfile already generated" fi outfile=${filepath}.minentropy_${mask}_${bits}bits.var.txt inprocess_file=$outfile if [ ! -f $outfile ] then echo "Analyzing entropy for $infilevar ${bits}-bit single" | tee -a $LOGFILE #python -u $EATOOL_NONIID -v $infilevar $bits > $outfile $EATOOL_NONIID -i -a -v $infilevar ${bits} > $outfile else echo "File $outfile already generated" fi done done done