pax_global_header00006660000000000000000000000064151763542230014522gustar00rootroot0000000000000052 comment=b94ef60f888ad442641a25c4599e24296bde4959 jitterentropy-rngd-1.3.1/000077500000000000000000000000001517635422300153765ustar00rootroot00000000000000jitterentropy-rngd-1.3.1/.github/000077500000000000000000000000001517635422300167365ustar00rootroot00000000000000jitterentropy-rngd-1.3.1/.github/workflows/000077500000000000000000000000001517635422300207735ustar00rootroot00000000000000jitterentropy-rngd-1.3.1/.github/workflows/docker-build-image.yml000066400000000000000000000004731517635422300251460ustar00rootroot00000000000000name: Docker CI on: push: branches: [ "master" ] pull_request: branches: [ "master" ] jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 - name: Build the Docker image run: docker build . --file Dockerfile --tag smuellerdd/jitterentropy-rngd:$(date +%s) jitterentropy-rngd-1.3.1/.github/workflows/docker-publish.yml000066400000000000000000000071751517635422300244430ustar00rootroot00000000000000name: Docker # This workflow uses actions that are not certified by GitHub. # They are provided by a third-party and are governed by # separate terms of service, privacy policy, and support # documentation. on: workflow_dispatch: push: branches: [ "master" ] # Publish semver tags as releases. tags: [ 'v*.*.*' ] pull_request: branches: [ "master" ] env: # Use docker.io for Docker Hub if empty REGISTRY: ghcr.io jobs: build: runs-on: ubuntu-latest permissions: contents: read packages: write # This is used to complete the identity challenge # with sigstore/fulcio when running outside of PRs. id-token: write steps: - name: Setup environment shell: bash run: | printf >> "${GITHUB_ENV}" -- '%s=%s\n' \ 'IMAGE_NAME' "${GITHUB_REPOSITORY@L}" - name: Checkout repository uses: actions/checkout@v6 # Install the cosign tool except on PR # https://github.com/sigstore/cosign-installer - name: Install cosign if: github.event_name != 'pull_request' uses: sigstore/cosign-installer@v3 # Add support for more platforms with QEMU # https://github.com/docker/setup-qemu-action - name: Set up QEMU uses: docker/setup-qemu-action@v3 # Set up BuildKit Docker container builder to be able to build # multi-platform images and export cache # https://github.com/docker/setup-buildx-action - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 # Login against a Docker registry except on PR # https://github.com/docker/login-action - name: Log into registry ${{ env.REGISTRY }} if: github.event_name != 'pull_request' uses: docker/login-action@v3 with: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} # Extract metadata (tags, labels) for Docker # https://github.com/docker/metadata-action - name: Extract Docker metadata id: meta uses: docker/metadata-action@v5 with: images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} # Build and push Docker image with Buildx (don't push on PR) # https://github.com/docker/build-push-action - name: Build and push Docker image id: build-and-push uses: docker/build-push-action@v6 with: context: . platforms: linux/arm64,linux/amd64 pull: true push: ${{ github.event_name != 'pull_request' }} tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} cache-from: type=gha cache-to: type=gha,mode=max # Sign the resulting Docker image digest except on PRs. # This will only write to the public Rekor transparency log when the Docker # repository is public to avoid leaking data. If you would like to publish # transparency data even for private images, pass --force to cosign below. # https://github.com/sigstore/cosign - name: Sign the published Docker image if: ${{ github.event_name != 'pull_request' }} env: # https://docs.github.com/en/actions/security-guides/security-hardening-for-github-actions#using-an-intermediate-environment-variable TAGS: ${{ steps.meta.outputs.tags }} DIGEST: ${{ steps.build-and-push.outputs.digest }} # This step uses the identity token to provision an ephemeral certificate # against the sigstore community Fulcio instance. run: echo "${TAGS}" | xargs -I {} cosign sign --yes {}@${DIGEST} jitterentropy-rngd-1.3.1/CHANGES.md000066400000000000000000000070631517635422300167760ustar00rootroot000000000000001.3.1: * Fix incomplete merger with Jitter RNG 3.7.0 library 1.3.0: * enhancement: use Jitter RNG library 3.7.0 * enhancement: inject data into Linux RNG where the Linux RNG operates as AIS 20/31 DRT.1 tree 1.2.8: * enhancement: use Jitter RNG library 3.4.1 1.2.7: * enhancement: use Jitter RNG library 3.4.0 1.2.6: * enhancement: use Jitter RNG library 3.3.1 1.2.5: * enhancement: use Jitter RNG library 3.3.0 * enhancement: add --flags command line option to allow specifying the integer value used as flags field to allocate the Jitter RNG - see jitterentropy(3) for details * enhancement: add --osr command line option 1.2.4: * enhancement: use Jitter RNG library 3.2.0 1.2.3: * enhancement: use Jitter RNG library 3.1.0 1.2.2: * enhancement: Add SP800-90B compliant entropy injection * fix: proper use of the RNDRESEEDCRNG IOCTL which otherwise causes an endless loop due to kernel change 11a0b5e0ec8c13bef06f7414f9e914506140d5cb * enhancement: Catch runtime FIPS health failures * enhancement: use Jitter RNG library 3.0.2 1.2.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 * disable RNDRESEEDCRNG on kernels < 4.17 as suggested by Warszawski, Diego * Use Jitter RNG library 3.0.1 1.2.0: * Due to the removal of the blocking pool in kernel 5.6, it is becoming very unlikely that the user space rngd is ever triggered by the kernel. Thus, the jitterentropy-rngd now injects entropy every 10 minutes unconditionally. * Use the RNDRESEEDCRNG ioctl after injecting entropy to guarantee that the new entropy is immediately forwarded to the ChaCha20 DRNG. Otherwise the ChaCha20 DRNG will not benefit from the new entropy up to 5 minutes after the injection of the entropy. * Use Jitter RNG library 3.0.0 1.1.0: * avert crash during shutdown when the kernel sends a SIGALRM while the Jitter RNG is deallocated * Fix: unsafe signal handling by Gerald Lledo * import jitterentropy library 2.2.0 to make rngd fully SP800-90B compliant 1.0.8: * Fix incomplete jitterentropy core 2.1.1 import 1.0.7: * Inlcude jitterentropy core 2.1.1 1.0.6: * Include jitterentropy core 2.0.1 * Compile jitterentropy core without optimizations using GCC pragmas instead of -O0 as suggested by Paul Wouters * Change CFLAGS and LDFLAGS from += to ?= to allow smooth integration with build environment as suggested by Paul Wouters * Version information now can obtained as unprivileged user. 1.0.5: * inject 32 bytes of entropy into /dev/random before daemonizing as suggested by Pascal de Bruijn * add jitterentropy-rngd.1 man page as suggested by Pascal de Bruijn * small changes to systemd unit file suggested by Pascal de Bruijn 1.0.4: * inject only 32 bytes of entropy of entropy instead of 256 bytes * apply oversampling factor -- i.e. obtain OVERSAMPLINGFACTOR bytes more from Jitter RNG than required for the 32 bytes of entropic data * do not install sig_alarm handler if the LRNG is present * Use Jitter RNG logic v2.0.0 1.0.3: * Ensure that the memset on the buffer holding entropy is always performed. 1.0.2: * change jitterentropy.service: move RNGd startup up the boot ladder to allow all cryptographic services to benefit from a RNGd-updated /dev/?random 1.0.1: * mark function jentrng_versionstring static (thanks to Kevin Fowler) * use errno with strerror (thanks to Kevin Fowler) * compile with -pedanic and make appropriate code changes 1.0.0: * start new numbering schema jitterentropy-rngd-1.3.1/COPYING000066400000000000000000000033651517635422300164400ustar00rootroot00000000000000Copyright (C) 2017 - 2026, 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-rngd-1.3.1/COPYING.bsd000066400000000000000000000025461517635422300172070ustar00rootroot00000000000000Redistribution 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-rngd-1.3.1/COPYING.gplv2000066400000000000000000000431331517635422300174660ustar00rootroot00000000000000 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-rngd-1.3.1/Dockerfile000066400000000000000000000003761517635422300173760ustar00rootroot00000000000000FROM alpine RUN apk add --no-cache gcc libc-dev linux-headers make WORKDIR /source COPY lib/ lib/ COPY *.c *.h Makefile ./ RUN make FROM alpine COPY --from=0 /source/jitterentropy-rngd /usr/bin ENTRYPOINT ["/usr/bin/jitterentropy-rngd"] CMD ["-v"] jitterentropy-rngd-1.3.1/Makefile000066400000000000000000000046441517635422300170460ustar00rootroot00000000000000# Compile Noise Source as user space application CC ?= $(CROSS_COMPILE)gcc STRIP ?= $(CROSS_COMPILE)strip CFLAGS ?=-Wextra -Wall -pedantic -fwrapv --param ssp-buffer-size=4 -fvisibility=hidden -fPIE -Wcast-align -Wmissing-field-initializers -Wshadow -Wswitch-enum -O0 LDFLAGS ?=-Wl,-z,relro,-z,now -pie 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 # Change as necessary DESTDIR := INSTALL ?= install PREFIX := /usr/local UNITDIR ?= $(shell pkg-config --variable=systemdsystemunitdir systemd 2>/dev/null || echo /usr/lib/systemd/system) NAME := jitterentropy-rngd C_SRCS := $(sort $(wildcard lib/*.c)) C_SRCS += jitterentropy-rngd.c C_OBJS := ${C_SRCS:.c=.o} OBJS := $(C_OBJS) INCLUDE_DIRS := . lib/ 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)) analyze_srcs = $(filter %.c, $(sort $(C_SRCS))) analyze_plists = $(analyze_srcs:%.c=%.plist) .PHONY: all scan clean distclean all: $(NAME) $(NAME): $(OBJS) # scan-build --use-analyzer=/usr/bin/clang $(CC) $(OBJS) -o $(NAME) $(LDFLAGS) $(CC) $(OBJS) -o $(NAME) $(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 strip: $(NAME) $(STRIP) --strip-unneeded $(NAME) install: strip $(INSTALL) -D -m 0755 $(NAME) $(DESTDIR)$(PREFIX)/sbin/$(NAME) $(INSTALL) -D -m 0644 $(NAME).1 $(DESTDIR)$(PREFIX)/share/man/man1/$(NAME).1 gzip -9 $(DESTDIR)$(PREFIX)/share/man/man1/$(NAME).1 sed "s|@PATH@|$(PREFIX)/sbin|" jitterentropy.service.in > jitterentropy.service $(INSTALL) -D -m 0644 jitterentropy.service $(DESTDIR)$(UNITDIR)/jitterentropy.service clean: @- $(RM) $(NAME) @- $(RM) $(OBJS) @- $(RM) jitterentropy.service @- $(RM) $(analyze_plists) distclean: clean jitterentropy-rngd-1.3.1/README.md000066400000000000000000000053571517635422300166670ustar00rootroot00000000000000Jitter RNG Daemon ================= Using the Jitter RNG core, the rngd provides an entropy source that feeds into the Linux /dev/random device if its entropy runs low. It updates the /dev/random entropy estimator such that the newly provided entropy unblocks /dev/random. The seeding of /dev/random also ensures that /dev/urandom benefits from entropy. Especially during boot time, when the entropy of Linux is low, the Jitter RNGd provides a source of sufficient entropy. By using the SP800-90B-compliant Jitter RNG core library, the RNGd itself is now fully SP800-90B compliant. Build Instructions ================== To generate the shared library `make` followed by `make install`. Usage ===== See jitterentropy --help or see the man page jitterentropy-rngd.1. Systemd Unit File ================= A systemd unit file is provided with jitterentropy.service which can be copied to /etc/systemd/system and enabled with the command `systemctl enable jitterentropy`. The unit file ensures that the Jitter RNGd is started as one of the first daemons during the user space start process. This shall guarantee that any cryptographic daemons, like sshd or a web server, benefits from a seeded /dev/random and /dev/urandom device at the time they start up. Docker [![Docker CI](https://github.com/smuellerDD/jitterentropy-rngd/actions/workflows/docker-build-image.yml/badge.svg?event=push)](https://github.com/smuellerDD/jitterentropy-rngd/actions/workflows/docker-build-image.yml) ====== Run using `docker compose`: ```sh docker compose up -d ``` Manual steps: 1. Build an image from the latest source code. ```sh docker build -t smuellerdd/jitterentropy-rngd \ 'https://github.com/smuellerDD/jitterentropy-rngd.git' ``` 2. Create and run a container using the newly built image. ```sh docker run -d --name=rngd --restart=always \ --cap-add=SYS_ADMIN --cap-drop=ALL \ --network=none smuellerdd/jitterentropy-rngd ``` 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-rngd-1.3.1/docker-compose.yaml000066400000000000000000000004021517635422300211700ustar00rootroot00000000000000name: jitterentropy services: rngd: build: context: https://github.com/smuellerDD/jitterentropy-rngd.git cap_add: - SYS_ADMIN cap_drop: - ALL network_mode: none restart: always jitterentropy-rngd-1.3.1/jitterentropy-base-user.h000066400000000000000000000414511517635422300223620ustar00rootroot00000000000000/* * Non-physical true random number generator based on timing jitter. * * Copyright Stephan Mueller , 2013 - 2026 * * 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 #ifdef LIBGCRYPT #include #endif #ifdef OPENSSL #include #include #endif #if defined(AWSLC) #include #endif #if defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__) #include #endif #ifdef __MACH__ #include #include #include #include #include #endif #ifdef __APPLE__ #include #endif /* Override this, if you want to allocate more than 2 MB of secure memory */ #ifndef JENT_SECURE_MEMORY_SIZE_MAX #define JENT_SECURE_MEMORY_SIZE_MAX 2097152 #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 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; read_real_time(&aixtime, TIMEBASE_SZ); time_base_to_time(&aixtime, TIMEBASE_SZ); tmp = (uint64_t)aixtime.tb_high * 1000000000UL; tmp += (uint64_t)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_memset_secure(void *s, size_t n) { #if (defined(AWSLC) || defined(OPENSSL)) OPENSSL_cleanse(s, n); #else memset(s, 0, n); __asm__ __volatile__("" : : "r" (s) : "memory"); #endif } static inline void *jent_zalloc(size_t len) { #define JENT_BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)])) #define JENT_IS_POWER_OF_2(n) (JENT_BUILD_BUG_ON((n & (n - 1)) != 0)) void *tmp = NULL; #ifdef LIBGCRYPT /* Set the maximum usable locked memory to 2 MiB at fist call. * * You may have to adapt or delete this, if you * also use libgcrypt at other places in your software! */ if (!gcry_control (GCRYCTL_INITIALIZATION_FINISHED_P)) { gcry_control(GCRYCTL_INIT_SECMEM, JENT_SECURE_MEMORY_SIZE_MAX, 0); gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0); } /* 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(AWSLC) tmp = OPENSSL_malloc(len); #elif defined(OPENSSL) /* We only call secure malloc initialization here, * if not already done. The 2 MiB max. reserved here * are sufficient for jitterentropy but probably * too small for a whole application doing crypto * operations with OpenSSL. * * Both min and max value must be power of 2. * min must be smaller than max. * * May preallocate more before making the first * call into jitterentropy!*/ JENT_IS_POWER_OF_2(JENT_SECURE_MEMORY_SIZE_MAX); if (CRYPTO_secure_malloc_initialized() || CRYPTO_secure_malloc_init(JENT_SECURE_MEMORY_SIZE_MAX, 32)) { tmp = OPENSSL_secure_malloc(len); } #define CONFIG_CRYPTO_CPU_JITTERENTROPY_SECURE_MEMORY /* If secure memory was not available, OpenSSL * falls back to "normal" memory. So double check. */ if (tmp && !CRYPTO_secure_allocated(tmp)) { OPENSSL_secure_free(tmp); tmp = NULL; } #elif defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__) tmp = malloc(len); if (!tmp) return NULL; /* * prevent paging out of the memory state to swap space * if this fails, check the current memory lock limits * and capabilities (e.g. RLIMIT_MEMLOCK and CAP_IPC_LOCK) */ #ifndef JENT_CONF_RELAX_MLOCK #define CONFIG_CRYPTO_CPU_JITTERENTROPY_SECURE_MEMORY if (mlock(tmp, len)) { #else /* * use this only for CI or restricted containers if not possible * otherwise */ if (mlock(tmp, len) && errno != EPERM && errno != EAGAIN) { #endif free(tmp); return NULL; } #else /* LIBGCRYPT */ /* 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) jent_memset_secure(tmp, len); return tmp; #undef JENT_IS_POWER_OF_2 #undef JENT_BUILD_BUG_ON } static inline void jent_zfree(void *ptr, size_t len) { #ifdef LIBGCRYPT /* gcry_free automatically wipes memory allocated with * gcry_(x)malloc_secure */ (void) 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_secure_free(ptr); #elif defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__) /* while memory returned to the OS is automatically unlocked, * it is not known how long libc keeps this memory cached * internally therefore its more robust to nevertheless * unlock here. */ munlock(ptr, len); jent_memset_secure(ptr, len); free(ptr); #else jent_memset_secure(ptr, len); free(ptr); #endif /* LIBGCRYPT */ } static inline int jent_fips_enabled(void) { #ifdef LIBGCRYPT return gcry_fips_mode_active(); #elif defined(AWSLC) return FIPS_mode(); #elif defined(OPENSSL) return EVP_default_properties_is_fips_enabled(NULL); #else #define FIPS_MODE_SWITCH_FILE "/proc/sys/crypto/fips_enabled" char buf[2] = "0"; int fd = 0; ssize_t rlen; if ((fd = open(FIPS_MODE_SWITCH_FILE, O_RDONLY)) >= 0) { do { rlen = read(fd, buf, sizeof(buf)); } while (rlen < 0 && errno == EINTR); close(fd); if (rlen <= 0) return 0; } if (buf[0] == '1') return 1; else return 0; #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_sysconf(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_sysconf(long *l1, long *l2, long *l3) { *l1 = 0; *l2 = 0; *l3 = 0; } # endif static inline void jent_get_cachesize_sysfs(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; ssize_t rlen; /* Iterate over all caches */ for (i = 0; i < 4; i++) { unsigned int shift = 0; char *ext, *endptr; /* * 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; do { rlen = read(fd, buf, sizeof(buf)); } while (rlen < 0 && errno == EINTR); close(fd); if (rlen <= 0) continue; 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; do { rlen = read(fd, buf, sizeof(buf)); } while (rlen < 0 && errno == EINTR); close(fd); if (rlen <= 0) continue; 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'; } } errno = 0; val = strtol(buf, &endptr, 10); if (errno != 0 || endptr == buf || val <= 0 || 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 #ifdef __APPLE__ static inline void jent_get_cachesize_sysconf(long *l1, long *l2, long *l3) { size_t size; size = sizeof(*l1); if (sysctlbyname("hw.l1dcachesize", l1, &size, NULL, 0) != 0) { *l1 = 0; } size = sizeof(*l2); if (sysctlbyname("hw.l2cachesize", l2, &size, NULL, 0) != 0) { *l2 = 0; } size = sizeof(*l3); if (sysctlbyname("hw.l3cachesize", l3, &size, NULL, 0) != 0) { *l3 = 0; } } #endif #if defined(__linux__) || defined(__APPLE__) static inline uint32_t jent_cache_size_to_memory(long l1, long l2, long l3, int all_caches) { uint32_t cache_size = 0; /* Cache size reported by system */ if (l1 > 0) cache_size += (uint32_t)l1; if (all_caches) { 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); return cache_size; } static inline uint32_t jent_cache_size_roundup(int all_caches) { uint32_t cache_size = 0; long l1 = 0, l2 = 0, l3 = 0; jent_get_cachesize_sysconf(&l1, &l2, &l3); cache_size = jent_cache_size_to_memory(l1, l2, l3, all_caches); #ifdef __linux__ if (cache_size == 0) { jent_get_cachesize_sysfs(&l1, &l2, &l3); cache_size = jent_cache_size_to_memory(l1, l2, l3, all_caches); if (cache_size == 0) return 0; } #endif /* * Make the output_size the smallest power of 2 strictly * greater than cache_size. */ cache_size++; return cache_size; } #else /* __linux__ || __APPLE__ */ static inline uint32_t jent_cache_size_roundup(int all_caches) { (void)all_caches; return 0; } #endif /* __linux__ || __APPLE__ */ 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-rngd-1.3.1/jitterentropy-rngd.1000066400000000000000000000104471517635422300213400ustar00rootroot00000000000000.\" Copyright (c) 2017 - 2026 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-RNGD 1 2017-02-11 .SH NAME jitterentropy-rngd \- CPU Jitter Random Number Generator Daemon .SH SYNOPSIS .B jitterentropy-rngd [\fI\,OPTION\/\fR] .SH DESCRIPTION The .I jitterentropy-rngd application provides a source of good entropy by collecting CPU execution time jitter. The collected entropy is injected into the Linux kernel .IR /dev/random device using the .IR RNDADDENTROPY ioctl described in \fBrandom\fR(4). .LP 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 works equally well in virtualized environments as well as on bare-metal provided a high-resolution timer is made available with the .BR clock_gettime () function. The currently used timer can be checked by reading the file .IR /sys/devices/system/clocksource/clocksource0/current_clocksource . If the clock source shall be changed, one of the available clock sources listed in the file .IR /sys/devices/system/clocksource/clocksource0/available_clocksource can be written into the mentioned .IR current_clocksource file and the kernel immediately changes the use clock. .LP The CPU Jitter Random Number Generator unconditionally injects 256 bits of entropy into the Linux kernel during startup time before it daemonizes. Thus, when the invocation of the .IR jitterentropy-rngd returns, the Linux kernel is seeded with at least 256 bits of entropy. The reader should consider that the Linux kernel performs a schedule operation during the injection of data which implies that immediately after starting the .IR jitterentropy-rngd the kernel may still complain about insufficient entropy available for .IR /dev/urandom . .LP In addition, the .IR jitterentropy-rngd injects 256 bits of entropy every 10 minutes unconditionally irrespective whether the kernel has sufficient entropy or not. .LP The following options are supported when invoking .IR jitterentropy-rngd : .TP \fB\-v\fR, \fB\-\-verbose\fR enable a verbose operation of the daemon. Using this option multiple times increases the verbosity. Using this option implies that the .IR jitterentropy-rngd will not daemonize. .TP \fB\-p\fR, \fB\-\-pid\fR [\fI\,FILE\/\fR] triggers the creation of a PID file at the given location. .TP \fB\-h\fR, \fB\-\-help\fR displays the help text .TP \fB\-\-version\fR returns the version number of the .IR jitterentropy-rngd . .TP \fB\-s\fR, \fB\-\-sp800-90b\fR triggers a specific seeding strategy of the kernel /dev/random device to insert entropy that ensures the ChaCha20 DRNG behind /dev/random receives 256 bits of entropy as defined by SP800-90B. .TP \fB\-f\fR, \fB\-\-flags\fR [\fI\,FLAGS\/\fR] allows specifying the flags value documented with .IR jitterentropy(3) when allocating the Jitter RNG. .TP \fB\-o\fR, \fB\-\-osr\fR [\fI\,OSR\/\fR] allows specifying the oversampling rate (OSR) as documented with .IR jitterentropy(3) when allocating the Jitter RNG. .TP \fB\-\-status\fR returns the Jitter RNG status output from the .IR jitterentropy(3) libbrary API of .IR jent_status . To make sure this output is helpful, all other parameters should be also set identically to the runtime invocation of the daemon. .PP .SH NOTES The .IR jitterentropy-rngd does not perform write operations on any file system object. Thus, it can be executed on a fully read-only mounted file system. .LP The random bit stream generated by .IR jitterentropy-rngd is considered to hold full entropy. .PP .SH SEE ALSO \fBrandom\fR(4) \fBclock_gettime\fR(2) jitterentropy-rngd-1.3.1/jitterentropy-rngd.c000066400000000000000000000616171517635422300214270ustar00rootroot00000000000000/* * Non-physical true random number generator based on timing jitter. * * Copyright Stephan Mueller , 2014 - 2026 * * 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. */ #include #include #include #include #include #include #include #include #include #include #include #define _GNU_SOURCE #include #include #include #include #include #include #include "jitterentropy.h" #define MAJVERSION 1 /* 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 3 /* API compatible, ABI may change, functional * enhancements only, consumer can be left unchanged if * enhancements are not considered */ #define PATCHLEVEL 1 /* API / ABI compatible, no functional changes, no * enhancements, bug fixes only */ static int Verbosity = 0; static int force_sp80090b = 0; static int status = 0; struct kernel_rng { int fd; struct rand_data *ec; struct rand_pool_info *rpi; const char *dev; }; static struct kernel_rng Random = { /*.fd = */ -1, /*.ec = */ NULL, /*.rpi = */ NULL, /*.dev = */ "/dev/random" }; /* * handler for /dev/urandom not needed as used IOCTL alters input_pool static struct kernel_rng Urandom = { .fd = 0, .ec = NULL, .rpi = NULL, .dev = "/dev/urandom" }; */ static int Pidfile_fd = -1; /* "/var/run/jitterentropy-rngd.pid" */ static char *Pidfile = NULL; static int Entropy_avail_fd = -1; static int Entropy_thresh_fd = -1; static unsigned int jent_flags = 0; static unsigned int jent_osr = 1; #define ENTROPYBYTES 32 #define OVERSAMPLINGFACTOR 2 /* * After (force reseed wakeups), the installed alarm handler will unconditionally * trigger a reseed irrespective of the seed level in two phases. This ensures * that new seed is added after every (force reseed wakeups) * (alarm period). * PHASE1: 120(force reseed wakeups) * 5(alarm period) == 600s * PHASE2: 12(force reseed wakeups) * 50(alarm period) == 600s */ #define FORCE_RESEED_WAKEUPS_PHASE1 120 #define ALARM_PERIOD_PHASE1 5 #define FORCE_RESEED_WAKEUPS_PHASE2 12 #define ALARM_PERIOD_PHASE2 50 #define ENTROPYAVAIL "/proc/sys/kernel/random/entropy_avail" #define ENTROPYTHRESH "/proc/sys/kernel/random/write_wakeup_threshold" #define LRNG_FILE "/proc/lrng_type" static void install_alarm(unsigned int secs); static void dealloc(void); static void dealloc_rng(struct kernel_rng *rng); static unsigned long kern_maj = ULONG_MAX, kern_minor, kern_patchlevel; static void jentrng_versionstring(char *buf, size_t buflen) { snprintf(buf, buflen, "jitterentropy-rngd %d.%d.%d", MAJVERSION, MINVERSION, PATCHLEVEL); } /* Is the LRNG present instead of the legacy /dev/random? */ static int lrng_present(void) { struct stat buf; static int lrng_present = -1; if (lrng_present < 0) { int ret = stat(LRNG_FILE, &buf); if (ret == -1 && errno == ENOENT) lrng_present = 0; else lrng_present = 1; } return lrng_present; } static int get_kernver(void) { struct utsname kernel; char *saveptr = NULL; char *res = NULL; if (kern_maj != ULONG_MAX) return 0; if (uname(&kernel)) return -errno; /* 5.11.2 */ res = strtok_r(kernel.release, ".", &saveptr); if (!res) { printf("Could not parse kernel version"); return -EFAULT; } kern_maj = strtoul(res, NULL, 10); res = strtok_r(NULL, ".", &saveptr); if (!res) { printf("Could not parse kernel version"); return -EFAULT; } kern_minor = strtoul(res, NULL, 10); res = strtok_r(NULL, ".", &saveptr); if (!res) { printf("Could not parse kernel version"); return -EFAULT; } kern_patchlevel = strtoul(res, NULL, 10); return 0; } /* return true if kernel is greater or equal to given values, otherwise false */ static int kernver_ge(unsigned int maj, unsigned int minor, unsigned int patchlevel) { if (get_kernver()) return 0; if (maj < kern_maj) return 1; if (maj == kern_maj) { if (minor < kern_minor) return 1; if (minor == kern_minor) { if (patchlevel <= kern_patchlevel) return 1; } } return 0; } static void usage(void) { unsigned int ver = jent_version(); char version[30]; memset(version, 0, 30); jentrng_versionstring(version, sizeof(version)); fprintf(stderr, "\njitterentropy rngd feeding entropy to input_pool of Linux RNG\n"); fprintf(stderr, "Version %s\n\n", version); fprintf(stderr, "Reported numeric version number of jent library %u\n\n", ver); fprintf(stderr, "Usage:\n"); fprintf(stderr, "\t-h --help\tThis help information\n"); fprintf(stderr, "\t --version\tPrint version\n"); fprintf(stderr, "\t-v --verbose\tVerbose logging, multiple options increase verbosity\n"); fprintf(stderr, "\t\t\tVerbose logging implies running in foreground\n"); fprintf(stderr, "\t-p --pid\tWrite daemon PID to file\n"); fprintf(stderr, "\t-s --sp800-90b\tForce SP800-90B compliance\n"); fprintf(stderr, "\t-f --flags\tInteger with flags used to allocate Jitter RNG\n"); fprintf(stderr, "\t-o --osr\tInteger with OSR used to allocate Jitter RNG\n"); fprintf(stderr, "\t --status\tStatus information of the Jitter RNG - invoke with\n"); fprintf(stderr, "\t \tsame flags as used for runtime\n"); fprintf(stderr, "\nLRNG presence %sdetected\n", lrng_present() ? "" : "not "); exit(1); } static void parse_opts(int argc, char *argv[]) { int c = 0; char version[30]; while (1) { int opt_index = 0; static struct option opts[] = { {"verbose", 0, 0, 0}, {"pid", 1, 0, 0}, {"help", 0, 0, 0}, {"version", 0, 0, 0}, {"sp800-90b", 0, 0, 0}, {"flags", 1, 0, 0}, {"osr", 1, 0, 0}, {"status", 0, 0, 0}, {0, 0, 0, 0} }; c = getopt_long(argc, argv, "svp:hf:o:", opts, &opt_index); if (-1 == c) break; switch (c) { case 0: switch (opt_index) { /* verbose */ case 0: Verbosity++; break; /* pid */ case 1: Pidfile = optarg; break; /* help */ case 2: usage(); break; /* version */ case 3: jentrng_versionstring(version, sizeof(version)); fprintf(stderr, "Version %s\n", version); fprintf(stderr, "Version Jitterentropy Core %u\n", jent_version()); exit(0); break; /* sp800-90b */ case 4: force_sp80090b = 1; break; /* flags */ case 5: { unsigned long val = strtoul(optarg, NULL, 10); if (val > UINT_MAX) usage(); jent_flags = (unsigned int)val; break; } /* osr */ case 6: { unsigned long val = strtoul(optarg, NULL, 10); if (val > UINT_MAX) usage(); jent_osr = (unsigned int)val; break; } /* status */ case 7: status = 1; break; default: usage(); } break; case 'v': Verbosity++; break; case 'p': Pidfile = optarg; break; case 'h': usage(); break; case 's': force_sp80090b = 1; break; case 'f': { unsigned long val = strtoul(optarg, NULL, 10); if (val > UINT_MAX) usage(); jent_flags = (unsigned int)val; break; } case 'o': { unsigned long val = strtoul(optarg, NULL, 10); if (val > UINT_MAX) usage(); jent_osr = (unsigned int)val; break; } default: usage(); } } } #define LOG_DEBUG 3 #define LOG_VERBOSE 2 #define LOG_WARN 1 #define LOG_ERR 0 static void dolog(int severity, const char *fmt, ...) { va_list args; char msg[1024]; char sev[10]; if (severity <= Verbosity) { va_start(args, fmt); vsnprintf(msg, sizeof(msg), fmt, args); va_end(args); switch (severity) { case LOG_DEBUG: snprintf(sev, sizeof(sev), "Debug"); break; case LOG_VERBOSE: snprintf(sev, sizeof(sev), "Verbose"); break; case LOG_WARN: snprintf(sev, sizeof(sev), "Warning"); break; case LOG_ERR: snprintf(sev, sizeof(sev), "Error"); break; default: snprintf(sev, sizeof(sev), "Unknown"); } printf("jitterentropy-rngd - %s: %s\n", sev, msg); } if (LOG_ERR == severity) { dealloc(); exit(1); } } static inline void memset_secure(void *s, int c, size_t n) { memset(s, c, n); __asm__ __volatile__("" : : "r" (s) : "memory"); } /******************************************************************* * entropy handler functions *******************************************************************/ static ssize_t write_random(struct kernel_rng *rng, char *buf, size_t len, size_t entropy_bytes, int force_reseed) { ssize_t written = 0; int ret; if (len > SSIZE_MAX) return -EOVERFLOW; /* value is in bits */ rng->rpi->entropy_count = (entropy_bytes * 8); rng->rpi->buf_size = len; memcpy(rng->rpi->buf, buf, len); ret = ioctl(rng->fd, RNDADDENTROPY, rng->rpi); if (0 > ret) { int errsv = errno; dolog(LOG_WARN, "Error injecting entropy: %s", strerror(errsv)); return -errsv; } else { dolog(LOG_DEBUG, "Injected %u bytes with an entropy count of %u bytes of entropy", len, entropy_bytes); written = len; } rng->rpi->entropy_count = 0; rng->rpi->buf_size = 0; memset(rng->rpi->buf, 0, len); #if LINUX_VERSION_CODE >= KERNEL_VERSION(4,17,0) /* * The LRNG does not require this IOCTL as the reseed is automatically * triggered. */ if (force_reseed && kernver_ge(4, 17, 0) && !lrng_present()) { if (ioctl(rng->fd, RNDRESEEDCRNG) < 0) { if (errno == EINVAL) goto out; dolog(LOG_WARN, "Error triggering a reseed of the kernel DRNG: %s", strerror(errno)); } else { dolog(LOG_DEBUG, "Reseeding of kernel DRNG triggered"); } } #endif out: return written; } /* * Inject the data 90B-compliant considering the minimum n_out of 80 bits * of the folded SHA-1 operation reading the input_pool. * * The following seeding strategy is applied to ensure SP800-90B compliance: * * - If the LRNG is present, 90B compliance is always given and no special * handling is needed. * * - If the default /dev/random implementation is provided and the kernel offers * the RNDRESEEDCRNG, use it after injecting 80 bits of entropy to feed * the entropy into the ChaCha20 DRNG. In this case, the caller should use * the getrandom(2) system call or /dev/urandom to get SP800-90B compliant * data. * * - Kernels without the RNDRESEEDCRNG will never offer SP800-90B compliant * data via /dev/urandom or getrandom(2). Those should always use /dev/random. * In this case, the Jitter-RNG will feed only 80 bit chunks into the kernel. * This means that after /dev/random consumed 80 bits, new data is requested * from the Jitter-RNG. */ #define SHA1_FOLD_OUTPUT_SIZE 10 static ssize_t write_random_90B(struct kernel_rng *rng, char *buf, size_t len, size_t entropy_bytes, int force_reseed) { size_t written = 0, ptr; if (!force_reseed) return write_random(rng, buf, len, entropy_bytes, force_reseed); if (len > SSIZE_MAX) return -EOVERFLOW; for (ptr = 0; ptr < len; ptr += SHA1_FOLD_OUTPUT_SIZE) { size_t todo = len - ptr, ent; ssize_t out; if (todo > SHA1_FOLD_OUTPUT_SIZE) todo = SHA1_FOLD_OUTPUT_SIZE; ent = todo; if (ent > entropy_bytes) ent = entropy_bytes; entropy_bytes -= ent; out = write_random(rng, buf + ptr, todo, ent, force_reseed); if (out < 0) return out; written += out; } return written; } static ssize_t read_jent(struct kernel_rng *rng, char *buf, size_t buflen) { ssize_t ret; /* *jent_read_entropy_safe implies a changing H_submitter which is not * allowed in SP800-90B. */ if (force_sp80090b) ret = jent_read_entropy(rng->ec, buf, buflen); else ret = jent_read_entropy_safe(&rng->ec, buf, buflen); if (ret >= 0) return ret; dolog(LOG_WARN, "Cannot read entropy"); return -EFAULT; } static ssize_t gather_entropy(struct kernel_rng *rng, int init) { sigset_t blocking_set, previous_set; #define ENTBLOCKSIZE (ENTROPYBYTES * OVERSAMPLINGFACTOR) /* * Maximum numbers of blocks is determined by numbers of reseed IOCTLs: if * the reseed IOCTL is used, we call ceil(256 / 80) numbers of IOCTLs. As * each IOCTL may drain the entropy pool by 256 bits, we need to ensure that * after the numbers of IOCTLs, we finally inject more blocks than the numbers * of IOCTLs into the input_pool. Otherwise the entropy estimator will never * rise and we encounter an endless loop. */ #define ENTBLOCKS (4 + 2 + 1) char buf[(ENTBLOCKSIZE * ENTBLOCKS)]; ssize_t buflen = ENTBLOCKSIZE; ssize_t ret = 0; sigemptyset(&previous_set); sigemptyset(&blocking_set); sigaddset(&blocking_set, SIGALRM); sigprocmask(SIG_BLOCK, &blocking_set, &previous_set); if (lrng_present()) { /* * The LRNG operates fully 90B compliant, no special handling * is necessary. */ if (read_jent(rng, buf, buflen) < 0) return 0; dolog(LOG_DEBUG, "LRNG: Inject %u bits of data with %u bits of entropy into Blake2S state", buflen << 3, buflen << 3); /* * Write the entropy, LRNG seeds automatically - the Jitter RNG * provides full entropy so, we tell the Linux RNG the amount of * entropy. */ ret = write_random(rng, buf, buflen, buflen, 0); } else if (kernver_ge(5, 18, 0)) { /* * AIS 20/31 DRT.1, no special handling is necessary. */ if (read_jent(rng, buf, buflen) < 0) return 0; dolog(LOG_DEBUG, "Linux kernel >= 5.18: Inject %u bits of data with %u bits of entropy into Blake2S state", buflen << 3, buflen << 3); /* * Write the entropy and trigger reseed - the Jitter RNG provides * full entropy so, we tell the Linux RNG the amount of entropy. */ ret = write_random(rng, buf, buflen, buflen, 1); } else if (kernver_ge(4, 17, 0)) { unsigned int numblocks = 1, i; if (force_sp80090b || init) { numblocks = ENTBLOCKS; buflen *= numblocks; } /* * Generate twice the entropy data, once for the input_pool * and once for ChaCha20. */ if (read_jent(rng, buf, buflen) < 0) return 0; dolog(LOG_DEBUG, "Linux kernel >= 4.17: Inject entropy into %s", force_sp80090b ? "ChaCha20 DRNG" : "input pool"); ret = write_random_90B(rng, buf, ENTBLOCKSIZE, ENTROPYBYTES, force_sp80090b || init); numblocks--; for (i = 0; i < numblocks; i++) { dolog(LOG_DEBUG, "Inject entropy into input_pool"); ret += write_random_90B(rng, buf + ENTBLOCKSIZE * i, ENTBLOCKSIZE, ENTROPYBYTES, 0); } } else { if (force_sp80090b) buflen = SHA1_FOLD_OUTPUT_SIZE; if (read_jent(rng, buf, buflen) < 0) return 0; dolog(LOG_DEBUG, "Fallback case: Inject %u bits of data with %u bits of entropy into Blake2S state", buflen << 3, (buflen / OVERSAMPLINGFACTOR) << 3); ret = write_random_90B(rng, buf, buflen, buflen / OVERSAMPLINGFACTOR, 0); } if (ret >= 0 && buflen != ret) { dolog(LOG_WARN, "Injected %lu bytes into %s, expected %d", ret, rng->dev, buflen); ret = 0; } memset_secure(buf, 0, buflen); sigprocmask(SIG_SETMASK, &previous_set, NULL); return ret; } static int read_entropy_value(int fd) { ssize_t data = 0; char buf[5]; int entropy = 0; data = read(fd, buf, sizeof(buf)); lseek(fd, 0, SEEK_SET); if (0 > data) { dolog(LOG_WARN, "Error reading data from entropy fd: %s", strerror(errno)); return 0; } if (0 == data) { dolog(LOG_WARN, "Could not read data from entropy fd"); return 0; } entropy = atoi(buf); if (0 > entropy || 4096 < entropy) { dolog(LOG_WARN, "Entropy read from entropy fd (%d) is outsize of range", entropy); return 0; } return entropy; } /******************************************************************* * Signal handling functions *******************************************************************/ static void dealloc(void); static int alloc(void); /* * Wakeup and check entropy_avail -- this covers the drain of entropy * from the nonblocking_pool via get_random_bytes */ static void sig_entropy_avail(int sig) { int entropy = 0, thresh = 0; ssize_t written = 0; static unsigned int force_reseed = FORCE_RESEED_WAKEUPS_PHASE1; static unsigned int alarm_period = ALARM_PERIOD_PHASE1; (void)sig; dolog(LOG_VERBOSE, "Wakeup call for alarm on %s", ENTROPYAVAIL); if (--force_reseed == 0) { force_reseed = FORCE_RESEED_WAKEUPS_PHASE2; alarm_period = ALARM_PERIOD_PHASE2; dolog(LOG_DEBUG, "Force reseed", entropy); do { if (written < 0) { dolog(LOG_DEBUG, "Re-initializing rngd\n"); dealloc(); if (alloc() < 0) goto out; } written = gather_entropy(&Random, 0); } while (written < 0); dolog(LOG_VERBOSE, "%zd bytes written to /dev/random", written); goto out; } entropy = read_entropy_value(Entropy_avail_fd); thresh = read_entropy_value(Entropy_thresh_fd); if (0 == entropy || 0 == thresh) goto out; if (entropy >= thresh) { dolog(LOG_DEBUG, "Sufficient entropy %d available", entropy); goto out; } dolog(LOG_DEBUG, "Insufficient entropy %d available (threshold %d)", entropy, thresh); do { if (written < 0) { dolog(LOG_DEBUG, "Re-initializing rngd\n"); dealloc(); if (alloc() < 0) goto out; } written = gather_entropy(&Random, 0); } while (written < 0); dolog(LOG_VERBOSE, "%zd bytes written to /dev/random", written); out: install_alarm(alarm_period); return; } /* terminate the daemon cleanly */ static void sig_term(int sig) { (void)sig; dolog(LOG_DEBUG, "Shutting down cleanly\n"); /* Prevent the kernel from interfering with the shutdown */ signal(SIGALRM, SIG_IGN); /* If we got another termination signal, just get killed */ signal(SIGHUP, SIG_DFL); signal(SIGINT, SIG_DFL); signal(SIGQUIT, SIG_DFL); signal(SIGTERM, SIG_DFL); dealloc(); exit(0); } /* * Wakeup on insufficient entropy on /dev/random */ static void select_fd(void) { fd_set fds; int ret = 0; ssize_t written = 0; while (1) { FD_ZERO(&fds); dolog(LOG_DEBUG, "Polling /dev/random"); FD_SET(Random.fd, &fds); /* only /dev/random implements polling */ ret = select((Random.fd + 1), NULL, &fds, NULL, NULL); if (-1 == ret && EINTR != errno) dolog(LOG_ERR, "Select returned with error %s", strerror(errno)); if (0 <= ret) { dolog(LOG_VERBOSE, "Wakeup call for select on /dev/random"); do { if (written < 0) { dolog(LOG_DEBUG, "Re-initializing rngd\n"); dealloc(); if (alloc() < 0) continue; } written = gather_entropy(&Random, 0); } while (written < 0); dolog(LOG_VERBOSE, "%zd bytes written to /dev/random", written); } } } static void install_alarm(unsigned int secs) { if (lrng_present()) return; dolog(LOG_DEBUG, "Install alarm signal handler"); signal(SIGALRM, sig_entropy_avail); alarm(secs); } static void install_term(void) { dolog(LOG_DEBUG, "Install termination signal handler"); signal(SIGHUP, sig_term); signal(SIGINT, sig_term); signal(SIGQUIT, sig_term); signal(SIGTERM, sig_term); } /******************************************************************* * allocation functions *******************************************************************/ static void dealloc_rng(struct kernel_rng *rng) { if (NULL != rng->ec) { jent_entropy_collector_free(rng->ec); rng->ec = NULL; } if (NULL != rng->rpi) { memset(rng->rpi, 0,(sizeof(struct rand_pool_info) + (ENTROPYBYTES * OVERSAMPLINGFACTOR * sizeof(char)))); free(rng->rpi); rng->rpi = NULL; } if (-1 != rng->fd) { close(rng->fd); rng->fd = -1; } } static void dealloc(void) { dealloc_rng(&Random); if (-1 != Entropy_avail_fd) { close(Entropy_avail_fd); Entropy_avail_fd = -1; } if (-1 != Entropy_thresh_fd) { close(Entropy_thresh_fd); Entropy_thresh_fd = -1; } if (-1 != Pidfile_fd) { close(Pidfile_fd); Pidfile_fd = -1; if (NULL != Pidfile) unlink(Pidfile); } } static int alloc_rng(struct kernel_rng *rng) { rng->ec = jent_entropy_collector_alloc(jent_osr, jent_flags); if (!rng->ec) { dolog(LOG_ERR, "Allocation of entropy collector failed"); return -EAGAIN; } if (status) { char buf[2500]; int ret = jent_status(rng->ec, buf, sizeof(buf)); if (ret) return ret; fprintf(stderr, "%s\n", buf); return -EAGAIN; } rng->rpi = malloc((sizeof(struct rand_pool_info) + (ENTROPYBYTES * OVERSAMPLINGFACTOR * sizeof(char)))); if (!rng->rpi) { dolog(LOG_ERR, "Cannot allocate memory for random bytes"); dealloc_rng(rng); return -ENOMEM; } rng->fd = open(rng->dev, O_WRONLY); if (-1 == rng->fd) { int errsv = errno; dolog(LOG_ERR, "Open of %s failed: %s", rng->dev, strerror(errno)); dealloc_rng(rng); return -errsv; } return 0; } static int alloc(void) { int ret = 0; size_t written = 0; ret = jent_entropy_init_ex(jent_osr, jent_flags); if (ret) { dolog(LOG_ERR, "The initialization of CPU Jitter RNG failed with error code %d\n", ret); return ret; } ret = alloc_rng(&Random); if (ret) return ret; Entropy_avail_fd = open(ENTROPYAVAIL, O_RDONLY); if (-1 == Entropy_avail_fd) { int errsv = errno; dolog(LOG_ERR, "Open of %s failed: %s", ENTROPYAVAIL, strerror(errno)); dealloc(); return -errsv; } Entropy_thresh_fd = open(ENTROPYTHRESH, O_RDONLY); if (-1 == Entropy_thresh_fd) { int errsv = errno; dolog(LOG_ERR, "Open of %s failed: %s", ENTROPYTHRESH, strerror(errno)); dealloc(); return -errsv; } written = gather_entropy(&Random, 1); dolog(LOG_VERBOSE, "%lu bytes written to /dev/random", written); return 0; } static void create_pid_file(const char *pid_file) { char pid_str[12]; /* max. integer length + '\n' + null */ /* Ensure only one copy */ Pidfile_fd = open(pid_file, O_RDWR|O_CREAT|O_EXCL, S_IRUSR|S_IWUSR); if (Pidfile_fd == -1) dolog(LOG_ERR, "Cannot open pid file\n"); if (lockf(Pidfile_fd, F_TLOCK, 0) == -1) { if (errno == EAGAIN || errno == EACCES) { dolog(LOG_ERR, "PID file already locked\n"); exit(1); } else dolog(LOG_ERR, "Cannot lock pid file\n"); } if (ftruncate(Pidfile_fd, 0) == -1) { dolog(LOG_ERR, "Cannot truncate pid file\n"); exit(1); } /* write our pid to the pid file */ snprintf(pid_str, sizeof(pid_str), "%d\n", getpid()); if (write(Pidfile_fd, pid_str, strlen(pid_str)) != (ssize_t)strlen(pid_str)) { dolog(LOG_ERR, "Cannot write to pid file\n"); exit(1); } } static void daemonize(void) { pid_t pid; /* already a daemon */ if (1 == getppid()) return; pid = fork(); if (pid < 0) dolog(LOG_ERR, "Cannot fork to daemonize\n"); /* the parent process exits -- nothing has been allocated, nothing * needs to be freed */ if (0 < pid) exit(0); /* we are the child now */ /* new SID for the child process */ if (setsid() < 0) dolog(LOG_ERR, "Cannot obtain new SID for child\n"); /* Change the current working directory. This prevents the current * directory from being locked; hence not being able to remove it. */ if ((chdir("/")) < 0) dolog(LOG_ERR, "Cannot change directory\n"); if (Pidfile && strlen(Pidfile)) create_pid_file(Pidfile); /* Redirect standard files to /dev/null */ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-result" freopen( "/dev/null", "r", stdin); freopen( "/dev/null", "w", stdout); freopen( "/dev/null", "w", stderr); #pragma GCC diagnostic pop } int main(int argc, char *argv[]) { int ret; parse_opts(argc, argv); if (geteuid()) dolog(LOG_ERR, "Program must start as root!"); ret = alloc(); if (ret) goto out; if (0 == Verbosity) daemonize(); install_term(); install_alarm(ALARM_PERIOD_PHASE1); select_fd(); /* NOTREACHED */ out: dealloc(); return -ret; } jitterentropy-rngd-1.3.1/jitterentropy.h000066400000000000000000000314171517635422300204770ustar00rootroot00000000000000/* * Non-physical true random number generator based on timing jitter. * * Copyright Stephan Mueller , 2014 - 2026 * * 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 #if defined(_MSC_VER) || defined(__MINGW32__) #include "arch/jitterentropy-base-windows.h" #else #include "jitterentropy-base-user.h" #endif #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 7 /* * 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 0 #define JENT_VERSION (JENT_MAJVERSION * 1000000 + \ JENT_MINVERSION * 10000 + \ JENT_PATCHLEVEL * 100) /* -- BEGIN Main interface functions -- */ /* Flags that can be used to initialize the RNG */ #define JENT_DISABLE_STIR (1<<0) /* UNUSED */ #define JENT_DISABLE_UNBIAS (1<<1) /* UNUSED */ #define JENT_DISABLE_MEMORY_ACCESS (1<<2) /* Disable memory access for more entropy, saves MEMORY_SIZE RAM for entropy collector */ #define JENT_FORCE_INTERNAL_TIMER (1<<3) /* Force the use of the internal timer */ #define JENT_DISABLE_INTERNAL_TIMER (1<<4) /* Disable the potential use of the internal timer. */ #define JENT_FORCE_FIPS (1<<5) /* Force FIPS compliant mode including full SP800-90B compliance. */ #define JENT_NTG1 (1<<6) /* AIS 20/31 NTG.1 compliance */ #define JENT_CACHE_ALL (1<<7) /* Shall size of all caches be used to automatically determine the memory size for the memory access? By default it is only the L1 cache size. */ /* Flags field limiting the amount of memory to be used for memory access */ #define JENT_FLAGS_TO_MEMSIZE_SHIFT 27 #define JENT_FLAGS_TO_MAX_MEMSIZE(val) ((val) >> JENT_FLAGS_TO_MEMSIZE_SHIFT) #define JENT_MAX_MEMSIZE_TO_FLAGS(val) ((val) << JENT_FLAGS_TO_MEMSIZE_SHIFT) #define JENT_MAX_MEMSIZE_1kB JENT_MAX_MEMSIZE_TO_FLAGS(UINT32_C( 1)) #define JENT_MAX_MEMSIZE_2kB JENT_MAX_MEMSIZE_TO_FLAGS(UINT32_C( 2)) #define JENT_MAX_MEMSIZE_4kB JENT_MAX_MEMSIZE_TO_FLAGS(UINT32_C( 3)) #define JENT_MAX_MEMSIZE_8kB JENT_MAX_MEMSIZE_TO_FLAGS(UINT32_C( 4)) #define JENT_MAX_MEMSIZE_16kB JENT_MAX_MEMSIZE_TO_FLAGS(UINT32_C( 5)) #define JENT_MAX_MEMSIZE_32kB JENT_MAX_MEMSIZE_TO_FLAGS(UINT32_C( 6)) #define JENT_MAX_MEMSIZE_64kB JENT_MAX_MEMSIZE_TO_FLAGS(UINT32_C( 7)) #define JENT_MAX_MEMSIZE_128kB JENT_MAX_MEMSIZE_TO_FLAGS(UINT32_C( 8)) #define JENT_MAX_MEMSIZE_256kB JENT_MAX_MEMSIZE_TO_FLAGS(UINT32_C( 9)) #define JENT_MAX_MEMSIZE_512kB JENT_MAX_MEMSIZE_TO_FLAGS(UINT32_C(10)) #define JENT_MAX_MEMSIZE_1MB JENT_MAX_MEMSIZE_TO_FLAGS(UINT32_C(11)) #define JENT_MAX_MEMSIZE_2MB JENT_MAX_MEMSIZE_TO_FLAGS(UINT32_C(12)) #define JENT_MAX_MEMSIZE_4MB JENT_MAX_MEMSIZE_TO_FLAGS(UINT32_C(13)) #define JENT_MAX_MEMSIZE_8MB JENT_MAX_MEMSIZE_TO_FLAGS(UINT32_C(14)) #define JENT_MAX_MEMSIZE_16MB JENT_MAX_MEMSIZE_TO_FLAGS(UINT32_C(15)) #define JENT_MAX_MEMSIZE_32MB JENT_MAX_MEMSIZE_TO_FLAGS(UINT32_C(16)) #define JENT_MAX_MEMSIZE_64MB JENT_MAX_MEMSIZE_TO_FLAGS(UINT32_C(17)) #define JENT_MAX_MEMSIZE_128MB JENT_MAX_MEMSIZE_TO_FLAGS(UINT32_C(18)) #define JENT_MAX_MEMSIZE_256MB JENT_MAX_MEMSIZE_TO_FLAGS(UINT32_C(19)) #define JENT_MAX_MEMSIZE_512MB JENT_MAX_MEMSIZE_TO_FLAGS(UINT32_C(20)) #define JENT_MAX_MEMSIZE_MAX JENT_MAX_MEMSIZE_512MB #define JENT_MAX_MEMSIZE_MASK JENT_MAX_MEMSIZE_TO_FLAGS(0xffffffff) /* * We start at 1kB -> offset is log2(1024) - 1 as the flag value above is added * to this offset. */ #define JENT_MAX_MEMSIZE_OFFSET 9 /* Flags field defining the hash loop */ #define JENT_FLAGS_TO_HASHLOOP_SHIFT 24 #define JENT_HASHLOOP_TO_FLAGS(val) ((val) << JENT_FLAGS_TO_HASHLOOP_SHIFT) #define JENT_MAX_HASHLOOP_MASK JENT_HASHLOOP_TO_FLAGS(0x7) #define JENT_FLAGS_TO_HASHLOOP(val) (((val) >> JENT_FLAGS_TO_HASHLOOP_SHIFT)\ & 0x7) #define JENT_HASHLOOP_1 JENT_HASHLOOP_TO_FLAGS(UINT32_C(0)) #define JENT_HASHLOOP_2 JENT_HASHLOOP_TO_FLAGS(UINT32_C(1)) #define JENT_HASHLOOP_4 JENT_HASHLOOP_TO_FLAGS(UINT32_C(2)) #define JENT_HASHLOOP_8 JENT_HASHLOOP_TO_FLAGS(UINT32_C(3)) #define JENT_HASHLOOP_16 JENT_HASHLOOP_TO_FLAGS(UINT32_C(4)) #define JENT_HASHLOOP_32 JENT_HASHLOOP_TO_FLAGS(UINT32_C(5)) #define JENT_HASHLOOP_64 JENT_HASHLOOP_TO_FLAGS(UINT32_C(6)) #define JENT_HASHLOOP_128 JENT_HASHLOOP_TO_FLAGS(UINT32_C(7)) #define JENT_MAX_HASHLOOP JENT_HASHLOOP_128 #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 #if defined(__MINGW32__) || defined(__APPLE__) || defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__) #define JENT_PTHREAD #endif /* Forward declaration of opaque value */ struct rand_data; /* 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); /* print out human-readable status of the Jitter RNG (JSON) */ JENT_PRIVATE_STATIC int jent_status(const struct rand_data *ec, char *buf, size_t buflen); /* return secure memory support, must be done * in jitterentropy itself, as users may not define * a crypto library and so the define in jitterentropy-base-user.h * is not set for them. */ JENT_PRIVATE_STATIC int jent_secure_memory_supported(void); /** * 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 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 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 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, #ifdef JENT_PTHREAD void *(*start_routine) (void *), void *arg); #else int (*start_routine)(void *), void *arg); #endif void (*jent_notime_stop)(void *ctx); }; /* 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 -- */ JENT_PRIVATE_STATIC int jent_notime_init(void **ctx); JENT_PRIVATE_STATIC void jent_notime_fini(void *ctx); /* -- 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_RCT_MEM_FAILURE 8 /* Failure in RCT with memory 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) #define JENT_RCT_MEM_FAILURE_PERMANENT JENT_PERMANENT_FAILURE(JENT_RCT_MEM_FAILURE) /* -- END error masks for health tests -- */ #ifdef __cplusplus } #endif #endif /* _JITTERENTROPY_H */ jitterentropy-rngd-1.3.1/jitterentropy.service.in000066400000000000000000000024421517635422300223110ustar00rootroot00000000000000# Systemd configuration file # # The Jitterentropy RNGd does not depend on any other system # services. Futhermore, we want to start it as early as possible # in the boot cycle so that other services requiring # random numbers (like SSHD, TLS-based services) benefit # from a properly seeded /dev/?random [Unit] Description=Jitterentropy Gatherer Daemon DefaultDependencies=no After=local-fs.target Before=sysinit.target [Service] CapabilityBoundingSet=CAP_SYS_ADMIN DeviceAllow=/dev/null rw DeviceAllow=/dev/random rw DevicePolicy=strict ExecStart=@PATH@/jitterentropy-rngd IPAddressDeny=any LimitMEMLOCK=0 LockPersonality=yes MemoryDenyWriteExecute=yes MountFlags=private NoNewPrivileges=yes PrivateDevices=yes PrivateMounts=yes PrivateNetwork=yes PrivateTmp=yes PrivateUsers=no ProtectControlGroups=yes ProtectHome=yes ProtectKernelModules=yes ProtectKernelTunables=yes ProtectSystem=strict ReadOnlyPaths=-/ RemoveIPC=yes RestrictAddressFamilies= RestrictNamespaces=yes RestrictRealtime=yes SystemCallArchitectures=native SystemCallFilter=@system-service SystemCallFilter=~@chown @clock @cpu-emulation @debug @ipc @module @mount @obsolete @privileged @raw-io @reboot @resources @swap memfd_create mincore mlock mlockall personality UMask=0077 [Install] WantedBy=basic.target Alias=jitterentropy-rngd.service jitterentropy-rngd-1.3.1/lib/000077500000000000000000000000001517635422300161445ustar00rootroot00000000000000jitterentropy-rngd-1.3.1/lib/jitterentropy-base.c000066400000000000000000000665761517635422300221660ustar00rootroot00000000000000/* * Non-physical true random number generator based on timing jitter. * * Copyright Stephan Mueller , 2014 - 2026 * * 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; } /* * jent_secure_memory_supported() - Return if secure memory is used * * Secure memory uses guard pages, swap protection and zeroize on * free. */ JENT_PRIVATE_STATIC int jent_secure_memory_supported(void) { #ifdef CONFIG_CRYPTO_CPU_JITTERENTROPY_SECURE_MEMORY return 1; #else return 0; #endif } /*************************************************************************** * 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; } /* * 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: * * size provided by the caller, or * * cache information * (1 << JENT_CACHE_SHIFT_BITS) where by default * only L1 cache size is uzed or with JENT_CACHE_ALL all caches are used * to determine the memory size, or * * 1 << JENT_DEFAULT_MEMORY_BITS * * All is capped by JENT_MAX_MEMSIZE_MAX */ static inline unsigned int jent_update_memsize(unsigned int flags, unsigned int inc) { 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 cache size increased by the * multiplicator. */ max = jent_log2_simple(jent_cache_size_roundup( !!(flags & JENT_CACHE_ALL))); if (!max) { max = JENT_DEFAULT_MEMORY_BITS; } else { max += JENT_CACHE_SHIFT_BITS; if (!(flags & JENT_CACHE_ALL)) { /* * We increase the memory size 4-fold. This is * due to ensure that the memory access * operation mostly is caused by L1 misses and * L2 hits. */ max += 2; } } /* Adjust offset */ max = (max > JENT_MAX_MEMSIZE_OFFSET) ? max - JENT_MAX_MEMSIZE_OFFSET : 0; } else { max += inc; } 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; } static inline unsigned int jent_update_hashloop(unsigned int flags, unsigned int inc) { unsigned int global_max = JENT_FLAGS_TO_HASHLOOP(JENT_MAX_HASHLOOP); unsigned int max; max = JENT_FLAGS_TO_HASHLOOP(flags); max += inc; max = (max > global_max) ? global_max : max; /* Clear out the max size */ flags &= ~(unsigned int)JENT_MAX_HASHLOOP_MASK; /* Set the freshly calculated max size */ flags |= JENT_HASHLOOP_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. * * @param[in] ec Reference to entropy collector * @param[out] data pointer to buffer for storing random data -- buffer must * already exist * @param[in] len 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 * -9 RCT with memory failed * -10 RCT with memory permanent failure */ JENT_PRIVATE_STATIC ssize_t jent_read_entropy(struct rand_data *ec, char *data, size_t len) { /* * Maximum value representable by ssize_t. Use a portable * definition in case SSIZE_MAX is not available under strict * C standard modes. It is nevertheless available on POSIX systems. */ static const size_t ssize_max = (size_t)(((size_t)1 << (sizeof(ssize_t) * 8 - 1)) - 1); char *p = data; size_t orig_len; int ret = 0; /* check obvious misuse of API */ if (!ec || (data == NULL && len > 0)) return -1; /* * (hypothetical) edge case: clamp to ssize_t range to prevent * negative return on cast */ if (len > ssize_max) len = ssize_max; orig_len = len; 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_MEM_FAILURE_PERMANENT) ret = -10; else if (health_test_result & JENT_RCT_FAILURE) ret = -2; else if (health_test_result & JENT_APT_FAILURE) ret = -3; else if (health_test_result & JENT_RCT_MEM_FAILURE) ret = -9; 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 int jent_health_failure_reset( struct rand_data **ec, struct rand_data *(*alloc)(unsigned int osr, unsigned int flags)) { struct rand_data *new_ec; unsigned int osr, flags; /* Increment OSR */ osr = (*ec)->osr + 1; /* Remember flags value */ flags = (*ec)->flags; /* generic arbitrary cutoff to prevent running "forever" */ if (osr > JENT_MAX_OSR) return -1; /* * If the caller did not set any specific maximum value let the Jitter * RNG increase the maximum memory by one step. */ if (!(*ec)->max_mem_set) flags = jent_update_memsize(flags, 1); /* Increment hash loop count by one */ flags = jent_update_hashloop(flags, 1); /* Perform new health test with updated OSR */ while (jent_entropy_init_ex(osr, flags)) { osr++; if (osr > JENT_MAX_OSR) return -1; } new_ec = alloc(osr, flags); /* * In case of an error, leave the existing ec state untouched as a * safety measure. But it is in error state and is of not much use. */ if (!new_ec) return -1; /* Remember whether caller configured memory size */ new_ec->max_mem_set = !!(*ec)->max_mem_set; /* * Duplicate the state of the health tests to ensure the newly allocated * state will continue from the current health state. */ jent_apt_duplicate(new_ec, *ec); jent_rct_duplicate(new_ec); jent_lag_duplicate(new_ec, *ec); jent_rct_mem_duplicate(new_ec, *ec); jent_entropy_collector_free(*ec); *ec = new_ec; return 0; } 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. * * @param[in] ec Reference to entropy collector - this is a double pointer as * The entropy collector may be freed and reallocated. * @param[out] data pointer to buffer for storing random data -- buffer must * already exist * @param[in] len 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) { /* * Maximum value representable by ssize_t. Use a portable * definition in case SSIZE_MAX is not available under strict * C standard modes. It is nevertheless available on POSIX systems. */ static const size_t ssize_max = (size_t)(((size_t)1 << (sizeof(ssize_t) * 8 - 1)) - 1); char *p = data; size_t orig_len; ssize_t ret = 0; /* check obvious misuse of API */ if (!ec || (data == NULL && len > 0)) return -1; /* * (hypothetical) edge case: clamp to ssize_t range to prevent * negative return on cast */ if (len > ssize_max) len = ssize_max; orig_len = len; while (len > 0) { ret = jent_read_entropy(*ec, p, len); switch (ret) { /* Generic errors are returned immediately */ case -1: case -4: /* Permanent health errors are returned immediately */ case -6: case -7: case -8: case -10: return ret; /* Intermittent health errors */ case -2: case -3: case -5: case -9: /* * Re-allocate the entropy collector with updated * OSR, hash loop count and memory size and run * the startup sequence for NTG.1 again. * * If we fail here, the Jitter RNG returns the error. */ if (jent_health_failure_reset( ec, _jent_entropy_collector_alloc)) return ret; /* * We are not returning the intermittent errors here. * If a caller wants them, he should register a callback * with jent_set_fips_failure_callback. */ break; default: /* defensive check for uncaught errors */ if (ret >= 0) { len -= (size_t)ret; p += (size_t)ret; } else { return -1; } } } return (ssize_t)orig_len; } /*************************************************************************** * Initialization logic ***************************************************************************/ uint32_t jent_memsize(unsigned int flags) { uint32_t memsize = JENT_FLAGS_TO_MAX_MEMSIZE(flags); if (memsize == 0) { memsize = JENT_DEFAULT_MEMORY_BITS; } else { memsize = memsize + JENT_MAX_MEMSIZE_OFFSET; } memsize = UINT32_C(1) << memsize; return memsize; } unsigned int jent_hashloop_cnt(unsigned int flags) { unsigned int cnt = JENT_FLAGS_TO_HASHLOOP(flags); if (cnt == 0) cnt = JENT_HASH_LOOP_DEFAULT; else cnt = UINT32_C(1) << cnt; return cnt; } 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); /* * Reject too high OSR */ if (osr > JENT_MAX_OSR) return NULL; /* Force the self test to be run */ if (!jent_selftest_run && jent_entropy_init_ex(osr, flags)) return NULL; /* * NTG.1 requires to disable the internal timer. */ if (flags & JENT_NTG1) flags |= JENT_DISABLE_INTERNAL_TIMER; /* * 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)) { flags = jent_update_memsize(flags, 0); memsize = jent_memsize(flags); entropy_collector->mem = (unsigned char *)jent_zalloc(memsize); if (entropy_collector->mem == NULL) goto err; /* * Transform the size into a mask - it is assumed that size is * a power of 2. */ entropy_collector->memmask = memsize - 1; entropy_collector->memaccessloops = JENT_MEM_ACC_LOOP_DEFAULT; } /* Set the hash loop count */ flags = jent_update_hashloop(flags, 0); entropy_collector->hashloopcnt = jent_hashloop_cnt(flags); if (jent_sha3_alloc(&entropy_collector->hash_state)) goto err; /* * Initialize the hash state for the XDRBG */ jent_shake256_init(entropy_collector->hash_state); if ((flags & JENT_FORCE_FIPS) || jent_fips_enabled()) { /* * NIST explicitly suggested to use an identical approach * to the initialization of the conditioner as specified * for the NTG.1 compliance. */ entropy_collector->startup_state = jent_startup_memory; entropy_collector->fips_enabled = 1; } /* Set the oversampling rate */ entropy_collector->osr = osr; entropy_collector->flags = flags; /* * BSI AIS 20/31 NTG.1 requires that during startup 2 noise sources * are sampled where each independently delivers 240 bits of entropy. * This is ensured by setting the startup state such that the memory * access is treated independently from the SHA3 operation and both * must separately deliver the requested amount of entropy. * * NTG.1 implies the enabling of the FIPS mode to apply noise source * oversampling and the enabling of the health tests. */ if (flags & JENT_NTG1) { entropy_collector->startup_state = jent_startup_memory; entropy_collector->fips_enabled = 1; } /* Initialize the health tests */ jent_health_init(entropy_collector, flags & JENT_NTG1 ? jent_health_init_type_ntg1 : jent_health_init_type_common); /* 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: jent_entropy_collector_free(entropy_collector); 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; } /* * Assure, that we always have 512 bits (NTG.1 / FIPS compliance due to * startup_state is set to 2) or 256 bits (other cases) entropy in * our hash state before outputting a block by adding at least 256 bits * before first usage. 512 bits are always transferred to the next state * before the actual generation of random numbers to be returned to the * caller. The size is due to the XDRBG state variable. * * For NTG.1: already perform the startup stages guaranteeing the * invocation of 2 noise sources each delivering 240 bits of entropy * at least at this point. */ do { jent_random_data(ec); /* * Check for any kind of health error at this point including * intermittent or permanent errors. If we observed one, * re-initialize the entropy collector. */ if (jent_health_failure(ec)) { /* * Re-allocate the entropy collector with updated * OSR, hash loop count and memory size. */ if (jent_health_failure_reset( &ec, jent_entropy_collector_alloc_internal)) { jent_entropy_collector_free(ec); return NULL; } /* * The reset replaced ec with a freshly allocated * collector. That new collector has enable_notime * set but no running timer thread (the old thread * was stopped when the old collector was freed). * Restart the timer thread before re-entering the * loop, otherwise jent_get_nstime_internal will * spin forever waiting for a counter that nobody * increments. */ if (jent_notime_settick(ec)) { jent_entropy_collector_free(ec); return NULL; } /* Rerun startup sequence */ continue; } } while (ec->startup_state != jent_startup_completed); 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); if (!ec) return ec; /* * Define max_mem_set only if the external caller defined such memory. */ 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) { /* Safety measure */ jent_notime_unsettick(entropy_collector); jent_notime_disable(entropy_collector); if (entropy_collector->hash_state != NULL) { jent_sha3_dealloc(entropy_collector->hash_state); entropy_collector->hash_state = NULL; } 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; 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) { 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, ec->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); /* NOOP if notime disabled. Can be done unconditionally */ if (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; } /* * Note: This function and jent_entropy_init_ex() are NOT thread-safe. * They modify global state (GCD, self-test flag, notime configuration). * The caller must ensure that initialization is performed exactly once * before any concurrent use of the library (e.g. via pthread_once or * equivalent). */ 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-rngd-1.3.1/lib/jitterentropy-base.h000066400000000000000000000023211517635422300221450ustar00rootroot00000000000000/* * Copyright (C) 2021 - 2026, 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 #include "jitterentropy.h" #ifdef __cplusplus extern "C" { #endif int jent_time_entropy_init(unsigned int osr, unsigned int flags); uint32_t jent_memsize(unsigned int flags); unsigned int jent_hashloop_cnt(unsigned int flags); #ifdef __cplusplus } #endif #endif /* JITTERENTROPY_BASE_H */ jitterentropy-rngd-1.3.1/lib/jitterentropy-gcd.c000066400000000000000000000111221517635422300217620ustar00rootroot00000000000000/* Jitter RNG: GCD health test * * Copyright (C) 2021 - 2026, Joshua E. Hill * Copyright (C) 2021 - 2026, 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, 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-rngd-1.3.1/lib/jitterentropy-gcd.h000066400000000000000000000030071517635422300217720ustar00rootroot00000000000000/* * Copyright (C) 2021 - 2026, 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 JENT_PRIVATE_STATIC int jent_gcd_analyze(uint64_t *delta_history, size_t nelem, size_t osr); JENT_PRIVATE_STATIC uint64_t *jent_gcd_init(size_t nelem); JENT_PRIVATE_STATIC void jent_gcd_fini(uint64_t *delta_history, size_t nelem); JENT_PRIVATE_STATIC int jent_gcd_get(uint64_t *value); JENT_PRIVATE_STATIC 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-rngd-1.3.1/lib/jitterentropy-health.c000066400000000000000000000605251517635422300225050ustar00rootroot00000000000000/* Jitter RNG: Health Tests * * Copyright (C) 2021 - 2026, Joshua E. Hill * Copyright (C) 2021 - 2026, 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" #include "jitterentropy-noise.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 * * @param[in] ec 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 * * @param[in] ec Reference to entropy collector * @param[in] current_delta 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); } void jent_lag_duplicate(struct rand_data *new_ec, struct rand_data *old_ec) { unsigned int i; new_ec->lag_prediction_success_run = old_ec->lag_prediction_success_run; new_ec->lag_prediction_success_count = old_ec->lag_prediction_success_count; new_ec->lag_best_predictor = old_ec->lag_best_predictor; new_ec->lag_observations = old_ec->lag_observations; for (i = 0; i < JENT_LAG_HISTORY_SIZE; i++) { new_ec->lag_scoreboard[i] = old_ec->lag_scoreboard[i]; new_ec->lag_delta_history[i] = old_ec->lag_delta_history[i]; } } #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; } static inline void jent_lag_init(struct rand_data *ec, unsigned int osr) { (void)ec; (void)osr; } void jent_lag_duplicate(struct rand_data *new_ec, struct rand_data *old_ec) { new_ec->last_delta = old_ec->last_delta; new_ec->last_delta2 = old_ec->last_delta2; } #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 }; static void jent_apt_init(struct rand_data *ec) { /* * Establish the apt_cutoff based on the presumed entropy rate of * 1/osr. */ if (ec->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[ec->osr - 1]; ec->apt_cutoff_permanent = jent_apt_cutoff_permanent_lookup[ec->osr - 1]; } } /* * For NTG.1: 8-fold security margin * alpha for intermdiate error: 2^-30 * alpha for permanent error: 2^-60 * * Example formula for R for intermediate cutoffs: * C = 2 + qbinom(1 - 2^(-30), 511, 2^(-8/osr)) */ static const unsigned int jent_apt_cutoff_lookup_ntg1[15]= { 17, 71, 136, 191, 236, 272, 301, 325, 345, 361, 375, 388, 398, 407, 415 }; static const unsigned int jent_apt_cutoff_permanent_lookup_ntg1[15]= { 26, 92, 162, 221, 267, 303, 332, 355, 375, 390, 404, 415, 425, 433, 440 }; static void jent_apt_init_ntg1(struct rand_data *ec) { if (ec->osr >= ARRAY_SIZE(jent_apt_cutoff_lookup_ntg1)) { ec->apt_cutoff = jent_apt_cutoff_lookup_ntg1[ ARRAY_SIZE(jent_apt_cutoff_lookup_ntg1) - 1]; ec->apt_cutoff_permanent = jent_apt_cutoff_permanent_lookup_ntg1[ ARRAY_SIZE(jent_apt_cutoff_permanent_lookup_ntg1) - 1]; } else { ec->apt_cutoff = jent_apt_cutoff_lookup_ntg1[ec->osr - 1]; ec->apt_cutoff_permanent = jent_apt_cutoff_permanent_lookup_ntg1[ec->osr - 1]; } } static 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; } void jent_apt_duplicate(struct rand_data *new_ec, struct rand_data *old_ec) { if (old_ec->apt_observations) { /* APT re-initialization to intermittent error */ jent_apt_reinit(new_ec, old_ec->apt_base, 0, old_ec->apt_observations); } } /** * Reset the APT counter * * @param[in] ec 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 * * @param[in] ec Reference to entropy collector * @param[in] current_delta 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 with Memory Test * * The Jitter RNG applies the stuck test to the repetition count test with * memory as defined in a paper "Überlegungen zum Jitter-RNG" by Jonas Fiege, * Johannes Mittmann, Werner Schindler, 6. Februar 2026. This document * outlines a health test which applies the standard normal distribution. Using * the distribution, the cutoffs are calculated by applying the heuristic * entropy value (potentially adjusted by a safety factor). * * The test is defined to cover the window required non-rejected time deltas * to be generated for one output block of 256 bits of data. This window * is 321 * OSR as implemented by jent_random_data_one. * * The intermittent cutoff is defined by calculating * round(pnorm(2^(-(safety_factor)/OSR))*321*OSR) * where safety_factor is 1 for common case, 8 for the NTG.1. * * The permanent cutoff is defined by calculating * round(pnorm(2^(-(safety_factor / 2)/OSR))*321*OSR) ***************************************************************************/ /* * Recovery loop count defining the number of successful generation of * random blocks after a RCT with mem health alarm to recover from that * alarm. */ #define JENT_RCT_MEM_RECOVERY_LOOP_CNT 10 /* * RCT with memory using tau = 3 - these values effectively disables the * health test. */ static const unsigned short jent_rct_mem_cutoff_lookup[] = { 107, 214, 321, 428, 535, 642, 749, 856, 963, 1070, 1177, 1284, 1391, 1498, 1605, 1712, 1819, 1926, 2033, 2140 }; /* RCT with memory using tau = 3 */ static const unsigned short jent_rct_mem_cutoff_permanent_lookup[] = { 108, 215, 322, 429, 536, 643, 750, 857, 964, 1071, 1178, 1285, 1392, 1499, 1606, 1713, 1820, 1927, 2034, 2141 }; static void jent_rct_mem_init(struct rand_data *ec) { if (ec->osr >= ARRAY_SIZE(jent_rct_mem_cutoff_lookup)) { ec->rct_mem_cutoff = jent_rct_mem_cutoff_lookup[ ARRAY_SIZE(jent_rct_mem_cutoff_lookup) - 1]; ec->rct_mem_cutoff_permanent = jent_rct_mem_cutoff_permanent_lookup[ ARRAY_SIZE(jent_rct_mem_cutoff_permanent_lookup) - 1]; } else { ec->rct_mem_cutoff = jent_rct_mem_cutoff_lookup[ec->osr - 1]; ec->rct_mem_cutoff_permanent = jent_rct_mem_cutoff_permanent_lookup[ec->osr - 1]; } } /* * For NTG.1: 8-fold security margin using tau 4 with a significance level * pnorm(-4) yielding 3.17e-05 (roughly 2^-15) for first-order errors. Due to * the recovery loop we can afford such higher value. */ static const unsigned short jent_rct_mem_cutoff_lookup_ntg1[] = { 4, 46, 134, 255, 399, 560, 733, 856, 963, 1070, 1177, 1284, 1391, 1498, 1605, 1712, 1819, 1926, 2033, 2140 }; /* * For NTG.1: 8-fold security margin using tau 5 with a significance level of * pnorm(-5) yielding about 2^-20. */ static const unsigned short jent_rct_mem_cutoff_permanent_lookup_ntg1[] = { 5, 50, 142, 265, 410, 572, 746, 857, 964, 1071, 1178, 1285, 1392, 1499, 1606, 1713, 1820, 1927, 2034, 2141 }; static void jent_rct_mem_init_ntg1(struct rand_data *ec) { if (ec->osr >= ARRAY_SIZE(jent_rct_mem_cutoff_lookup_ntg1)) { ec->rct_mem_cutoff = jent_rct_mem_cutoff_lookup_ntg1[ ARRAY_SIZE(jent_rct_mem_cutoff_lookup_ntg1) - 1]; ec->rct_mem_cutoff_permanent = jent_rct_mem_cutoff_permanent_lookup_ntg1[ ARRAY_SIZE(jent_rct_mem_cutoff_permanent_lookup_ntg1) - 1]; } else { ec->rct_mem_cutoff = jent_rct_mem_cutoff_lookup_ntg1[ec->osr - 1]; ec->rct_mem_cutoff_permanent = jent_rct_mem_cutoff_permanent_lookup_ntg1[ec->osr - 1]; } } static void jent_rct_mem_insert(struct rand_data *ec, unsigned int stuck) { /* Start of a new window */ if (ec->rct_mem_ctr == 0) ec->rct_mem_count = 0; /* * If we are outside of a window, do not bother any more: the health * test will not be applied any more. * * We could simply return at this point if we leave the window, but then * we have a multi-modal behavior of the noise source, because if the * window is completed, a significant part of the code is not executed. * Therefore we apply a different strategy: always apply the health * test, but only set a health error if we are within the window. */ #define JENT_RCT_MEM_IN_WINDOW (ec->rct_mem_ctr < ec->rct_mem_nosr) /* * According to the specification of this health test, we only consider * every third iteration count. * * Again, we could simply return here, but that would again imply a * multi-modal behavior. Therefore, always perform the health test * and turn it into a noop. */ #define JENT_RCT_MEM_SKIP_STUCK (ec->rct_mem_ctr % 3) /* * We have a stuck value, count it */ if (stuck && JENT_RCT_MEM_IN_WINDOW && !JENT_RCT_MEM_SKIP_STUCK) ec->rct_mem_count++; /* * Apply the cut off value. */ if (ec->rct_mem_count >= ec->rct_mem_cutoff_permanent) { if (JENT_RCT_MEM_IN_WINDOW) ec->health_failure |= JENT_RCT_MEM_FAILURE_PERMANENT; } else if (ec->rct_mem_count == ec->rct_mem_cutoff) { /* * This is a "recovery loop" to recover from expected false * positives of the health test. Note, the health test cutoffs * have a significantly higher false positive rate than the * APT and RCT. Therefore, this loop generates additional * random values to see whether no health test is detected * during this loop. If no health test error is seen, then * we incurred an expected spurious false positive that we * can ignore. The random data generated by that recovery * loop is simply added to the internal state and thus is not * wasted. */ if (!ec->in_recovery) { unsigned int i; /* * Clear the RCT with mem counter to generate fresh * data. */ ec->rct_mem_count = 0; ec->in_recovery = 1; for (i = 0; i < JENT_RCT_MEM_RECOVERY_LOOP_CNT; i++) jent_random_data(ec); ec->in_recovery = 0; /* * We now leave the set health falures incurred from * the jent_random_data loop. If that loop did not * detect a failure, we have no failure at this point * either. Also, leave the rct_mem_count value as is. */ } else { if (JENT_RCT_MEM_IN_WINDOW) ec->health_failure |= JENT_RCT_MEM_FAILURE; } } /* * Count up the seen measurements if we are in the window - this * prevents also a wrap-around. */ if (JENT_RCT_MEM_IN_WINDOW) ec->rct_mem_ctr++; } void jent_rct_mem_duplicate(struct rand_data *new_ec, struct rand_data *old_ec) { new_ec->rct_mem_count = old_ec->rct_mem_cutoff; } /*************************************************************************** * 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. ***************************************************************************/ static void jent_rct_init(struct rand_data *ec, unsigned short safety) { unsigned short osr = (unsigned short)ec->osr; ec->rct_cutoff = JENT_HEALTH_RCT_INTERMITTENT_CUTOFF(osr); ec->rct_cutoff_permanent = JENT_HEALTH_RCT_PERMANENT_CUTOFF(osr); if (safety) { ec->rct_cutoff = (unsigned short) ((ec->rct_cutoff + safety - 1) / safety); ec->rct_cutoff_permanent = (unsigned short) ((ec->rct_cutoff_permanent + safety - 1) / safety); } } void jent_rct_duplicate(struct rand_data *new_ec) { /* * RCT re-initialization to intermittent error: As during a reset, * the OSR is updated and the OSR is at the same time the cutoff for * the RCT, we re-initialize the new RCT to the intermittent error * value based on the new OSR. */ new_ec->rct_count = (unsigned int)(JENT_HEALTH_RCT_INTERMITTENT_CUTOFF(new_ec->osr)); } /** * Repetition Count Test as defined in SP800-90B section 4.4.1 * * @param[in] ec Reference to entropy collector * @param[in] stuck Indicator whether the value is stuck */ static void jent_rct_insert(struct rand_data *ec, unsigned int stuck) { if (stuck) { ec->rct_count++; if (ec->rct_count >= ec->rct_cutoff_permanent) { ec->health_failure |= JENT_RCT_FAILURE_PERMANENT; } else if (ec->rct_count == ec->rct_cutoff) { ec->health_failure |= JENT_RCT_FAILURE; } } else { /* Must start at zero to reach the correct cutoff value */ 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. * * @param[in] ec Reference to entropy collector * @param[in] current_delta 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); unsigned int stuck = !current_delta || !delta2 || !delta3; /* * 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); /* RCT with stuck result */ jent_rct_insert(ec, stuck); jent_rct_mem_insert(ec, stuck); return stuck; } /** * Report any health test failures * * @param[in] ec 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 * 8 RCT with memory failure * 1<fips_enabled) return 0; if (fips_cb && ec->health_failure) { fips_cb(ec, ec->health_failure); } return ec->health_failure; } /** * Initialize the health tests * * @param[in] ec Reference to entropy collector * @param[in] inittype Startup type */ void jent_health_init(struct rand_data *ec, enum jent_health_init_type inittype) { /* Must start at zero to reach the correct cutoff value */ ec->rct_count = 0; jent_lag_init(ec, ec->osr); switch (inittype) { case jent_health_init_type_ntg1: jent_apt_init_ntg1(ec); jent_rct_init(ec, 8); jent_rct_mem_init_ntg1(ec); break; case jent_health_init_type_common: default: jent_apt_init(ec); jent_rct_init(ec, 0); jent_rct_mem_init(ec); break; } } jitterentropy-rngd-1.3.1/lib/jitterentropy-health.h000066400000000000000000000064021517635422300225040ustar00rootroot00000000000000/* * Copyright (C) 2021 - 2026, 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 the delta between two values. If the values are monotonic * increasing counters which can wrap, this caluculation implicitly * returns the absolute value of the delta all the time. */ return (next - prev); } #if 0 static inline uint64_t jent_delta_abs(uint64_t prev, uint64_t next) { /* * Return the absolute value of the delta when the values are not a * monotonic counter that may wrap. */ return (next > prev) ? (next - prev) : (prev - next); } #endif /* * 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 (see jent_health_init(), jent_rct_insert()). * 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. */ /* 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_lag_duplicate(struct rand_data *new_ec, struct rand_data *old_ec); void jent_apt_duplicate(struct rand_data *new_ec, struct rand_data *old_ec); void jent_rct_duplicate(struct rand_data *new_ec); void jent_rct_mem_duplicate(struct rand_data *new_ec, struct rand_data *old_ec); unsigned int jent_stuck(struct rand_data *ec, uint64_t current_delta); unsigned int jent_health_failure(struct rand_data *ec); enum jent_health_init_type { jent_health_init_type_common, jent_health_init_type_ntg1, }; void jent_health_init(struct rand_data *ec, enum jent_health_init_type inittype); #ifdef __cplusplus } #endif #endif /* JITTERENTROPY_HEALTH_H */ jitterentropy-rngd-1.3.1/lib/jitterentropy-internal.h000066400000000000000000000377221517635422300230640ustar00rootroot00000000000000/* * Non-physical true random number generator based on timing jitter. * * Copyright Stephan Mueller , 2014 - 2026 * * 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 BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)])) #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) #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 /*************************************************************************** * 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. */ /* * 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? */ #ifndef JENT_TEST_MEASURE_RAW_MEMORY_ACCESS #define JENT_RANDOM_MEMACCESS #else #undef JENT_RANDOM_MEMACCESS #endif /* * 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 defines the default memory buffer size for the memory access * loop. This value implies a memory size of 1 << JENT_DEFAULT_MEMORY_BITS. * * It is permissible to configure this value differently at compile time if the * observed entropy rate is too small. * * This parameter is applied if the Jitter RNG: * - is not instantiated with JENT_MAX_MEMSIZE_* flag * - cannot determine the L1 cache size during starup. */ #ifndef JENT_DEFAULT_MEMORY_BITS # define JENT_DEFAULT_MEMORY_BITS 18 #endif /* 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 /* * Memory access loop count: This value defines the default memory access loop * count. The memory access loop is one of the hearts of the Jitter RNG. The * number of loop counts has a direct impact on the entropy rate. * * It is permissible to configure this value differently at compile time if the * observed entropy rate is too small. * * NOTE: When you modify this value, you are directly altering the behavior of * the noise source. Make sure you fully understand what you do. If you want to * individually measure the memory access loop entropy rate, use the * jitterentropy-hashtime tool with the command line option of --memaccess. */ #ifndef JENT_MEM_ACC_LOOP_DEFAULT #define JENT_MEM_ACC_LOOP_DEFAULT 128 #endif /* * Memory access loop initialization count: This value defines the multiplier of * the memory access loop count during initialization phase, when the memory * access based loop is the sole entropy provider. Typically a higher iteration * count is necessary to take enough time. * * It is permissible to configure this value differently at compile time if the * observed entropy rate is too small. * * NOTE: When you modify this value, you are directly altering the behavior of * the noise source during NTG.1 initialization. * Make sure you fully understand what you do. If you want to * individually measure the hash loop entropy rate, use the * jitterentropy-hashtime tool with the command line option of --hashloop. */ #ifndef JENT_MEM_ACC_LOOP_INIT #define JENT_MEM_ACC_LOOP_INIT 3 #endif /* * Hash loop count: This value defines the default hash loop count. The hash * loop is one of the hearts of the Jitter RNG. The number of loop counts has a * direct impact on the entropy rate. * * It is permissible to configure this value differently at compile time if the * observed entropy rate is too small. * * This value is applied if the Jitter RNG: * - is not instantiated with JENT_HASHLOOP_* flag * * NOTE: When you modify this value, you are directly altering the behavior of * the noise source. Make sure you fully understand what you do. If you want to * individually measure the hash loop entropy rate, use the * jitterentropy-hashtime tool with the command line option of --hashloop. */ #ifndef JENT_HASH_LOOP_DEFAULT #define JENT_HASH_LOOP_DEFAULT 1 #endif /* * Hash loop initialization count: This value defines the multiplier of the * hash loop count during initialization phase, when the SHA-3-based loop is the * sole entropy provider. Typically a higher iteration count is necessary to * take enough time. * * It is permissible to configure this value differently at compile time if the * observed entropy rate is too small. * * NOTE: When you modify this value, you are directly altering the behavior of * the noise source during NTG.1 initialization. * Make sure you fully understand what you do. If you want to * individually measure the hash loop entropy rate, use the * jitterentropy-hashtime tool with the command line option of --hashloop. */ #ifndef JENT_HASH_LOOP_INIT #define JENT_HASH_LOOP_INIT 3 #endif /* * Oversampling rate: This value defines the default oversampling rate. The * OSR defines the global heuristic entropy rate of 1/OSR. * * It is permissible to configure this value differently at compile time. * * This value is applied if the Jitter RNG: * - is instantiated with an OSR of 0 provided to the initialization API * * During initial health tests or jent_read_entropy_safe, the RNG instance * may re-initialize with an incremented OSR, which stops at JENT_OSR_MAX * and returns a failure condition. Otherwise this would run "forever". * Set another value instead of the default 20, if necessary. */ #ifndef JENT_MIN_OSR #define JENT_MIN_OSR 3 #endif #ifndef JENT_MAX_OSR #define JENT_MAX_OSR 20 #endif /*************************************************************************** * Jitter RNG State Definition Section ***************************************************************************/ #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 XDRBG-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). * * The additional bit for the safety factor comes from the fact that the * we want the internal state variable to have 256 + 64 bit of entropy. As this * state variable is generated by one SHAKE256 operation of the input data, we * loose one bit of entropy due to the SHAKE. For more details, see the NTG.1 * analysis provided with the big documentation. */ #define ENTROPY_SAFETY_FACTOR (64 + 1) enum jent_startup_state { jent_startup_completed, jent_startup_sha3, jent_startup_memory }; /* 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 */ /* Initialization state supporting AIS 20/31 NTG.1 */ enum jent_startup_state startup_state; /* The step size should be larger than the cacheline size. */ #ifndef JENT_MEMORY_BLOCKSIZE # define JENT_MEMORY_BLOCKSIZE 128 #endif #define JENT_MEMORY_BLOCKS(ec) ((ec->memmask + 1) / JENT_MEMORY_BLOCKSIZE) unsigned char *mem; /* Memory access location with size of * memmask + 1 */ uint32_t memmask; /* Memory mask (size of memory - 1) */ unsigned int memlocation; /* Pointer to byte in *mem */ unsigned int memaccessloops; /* Number of memory accesses per random * bit generation */ unsigned int hashloopcnt; /* Hash loop count */ /* Repetition Count Test */ unsigned int rct_count; /* Number of stuck values */ unsigned short rct_cutoff; /* RCT intermittent cutoff */ unsigned short rct_cutoff_permanent; /* RCT permanent cutoff */ /* Adaptive Proportion Test for a significance level of 2^-30 */ unsigned int apt_cutoff; /* Intermittent health test failure */ unsigned int apt_cutoff_permanent; /* Permanent health test failure */ #define JENT_APT_WINDOW_SIZE 512 /* Data window size */ unsigned int apt_observations; /* Number of collected observations in * current window. */ unsigned int apt_count; /* The number of times the reference * symbol been encountered in the * window. */ uint64_t apt_base; /* APT base reference */ unsigned int health_failure; /* Permanent health failure */ /* RCT with memory */ unsigned short rct_mem_ctr; /* Loop iteration for generating random bytes */ unsigned short rct_mem_nosr; /* Minimum iteration count of measure jitter loop */ unsigned short rct_mem_count; /* Number of stuck values */ unsigned short rct_mem_cutoff; /* RCT intermittent cutoff */ unsigned short rct_mem_cutoff_permanent; /* RCT permanent cutoff */ unsigned int apt_base_set:1; /* APT base reference set? */ unsigned int fips_enabled:1; unsigned int enable_notime:1; /* Use internal high-res timer */ unsigned int max_mem_set:1; /* Maximum memory configured by user */ unsigned int in_recovery:1; /* Flag to indicate a recovery op. */ #ifdef JENT_CONF_ENABLE_INTERNAL_TIMER volatile uint8_t notime_interrupt; /* indicator to interrupt ctr */ volatile uint64_t notime_timer; /* high-res timer mock-up */ uint64_t notime_prev_timer; /* previous timer value */ void *notime_thread_ctx; /* register thread data */ #endif /* JENT_CONF_ENABLE_INTERNAL_TIMER */ uint64_t jent_common_timer_gcd; /* Common divisor for all time deltas */ #ifdef JENT_HEALTH_LAG_PREDICTOR /* Lag predictor test to look for re-occurring patterns. */ /* The lag global cutoff selected based on the selection of osr. */ unsigned int lag_global_cutoff; /* The lag local cutoff selected based on the selection of osr. */ unsigned int lag_local_cutoff; /* * The number of times the lag predictor was correct. Compared to the * global cutoff. */ unsigned int lag_prediction_success_count; /* * The size of the current run of successes. Compared to the local * cutoff. */ unsigned int lag_prediction_success_run; /* * The total number of collected observations since the health test was * last reset. */ unsigned int lag_best_predictor; /* * The total number of collected observations since the health test was * last reset. */ unsigned int lag_observations; /* * This is the size of the window used by the predictor. The predictor * is reset between windows. */ #define JENT_LAG_WINDOW_SIZE (1U<<17) /* * The amount of history to base predictions on. This must be a power * of 2. Must be 4 or greater. */ #define JENT_LAG_HISTORY_SIZE 8 #define JENT_LAG_MASK (JENT_LAG_HISTORY_SIZE - 1) /* The delta history for the lag predictor. */ uint64_t lag_delta_history[JENT_LAG_HISTORY_SIZE]; /* The scoreboard that tracks how successful each predictor lag is. */ unsigned int lag_scoreboard[JENT_LAG_HISTORY_SIZE]; #endif /* JENT_HEALTH_LAG_PREDICTOR */ }; #ifdef __cplusplus } #endif #endif /* _JITTERENTROPY_INTERNAL_H */ jitterentropy-rngd-1.3.1/lib/jitterentropy-noise.c000066400000000000000000000503071517635422300223520ustar00rootroot00000000000000/* Jitter RNG: Noise Sources * * Copyright (C) 2021 - 2026, 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" /*************************************************************************** * Noise sources ***************************************************************************/ /* * Structure of the intermediary buffer: * * | time delta | domain separator | hash loop hash | 0 ... | * * Note, this buffer is truncted to the current rate size which implies that * data with entropy must be placed at a location to guarantee they are not * truncated off. */ #define JENT_SIZEOF_TIMEDELTA (sizeof(uint64_t)) #define JENT_SIZEOF_DOMAINSEPARATOR (sizeof(uint8_t)) #define JENT_SIZEOF_HASH_BLOCK (JENT_SHA3_256_SIZE_DIGEST) #define JENT_SIZEOF_INTERMEDIARY_DATA (JENT_SIZEOF_TIMEDELTA + \ JENT_SIZEOF_DOMAINSEPARATOR + \ JENT_SIZEOF_HASH_BLOCK) /* Intemediary is as big as the maximum rate it will be read with */ #define JENT_SIZEOF_INTERMEDIARY (JENT_SHA3_256_SIZE_BLOCK) #define JENT_OFFSET_TIMEDELTA (0) #define JENT_OFFSET_DOMAINSEPARATOR \ (JENT_OFFSET_TIMEDELTA + JENT_SIZEOF_TIMEDELTA) #define JENT_OFFSET_HASH_BLOCK \ (JENT_OFFSET_DOMAINSEPARATOR + JENT_SIZEOF_DOMAINSEPARATOR) /** * Insert a data block into the entropy pool * * The function inserts the intermediary buffer and the time delta together * into the entropy pool. The intermediary buffer is of exact the SHA3-256 rate * size to ensure that always one Keccak operation is triggered. * * Note, this function also clears the intermediary buffer immediately after it * was injected into the entropy pool. * * @param[in] ec Reference to entropy collector * @param[in] time_delta the time delta raw entropy value * @param[in] intermediary buffer that may hold other data */ static void jent_hash_insert(struct rand_data *ec, uint64_t time_delta, uint8_t intermediary[JENT_SIZEOF_INTERMEDIARY]) { /* * Insert the time stamp into the intermediary buffer after the message * digest of the intermediate data. */ memcpy(intermediary + JENT_OFFSET_TIMEDELTA, (uint8_t *)&time_delta, sizeof(uint64_t)); BUILD_BUG_ON(JENT_SIZEOF_INTERMEDIARY < JENT_SIZEOF_INTERMEDIARY_DATA); /* * Inject the data from the intermediary buffer, including the hash we * are using for timing, and the time stamp. Only the time is considered * to contain any entropy. The intermediary buffer is exactly rate-size * to always cause a Keccak operation. * * This operation seeds the XDRBG conditioning component as follows: * * XDRBG reseed: * V ← XOF( encode(( V' || seed ), α, 1), |V| ) * * where * * seed ← (intermediary_0 || intermediary_1 || ... || * intermediary_[(osr + safety_factor)*256]) */ jent_sha3_update(ec->hash_state, intermediary, jent_sha3_rate(ec->hash_state)); jent_memset_secure(intermediary, JENT_SIZEOF_INTERMEDIARY); } /** * Hash loop noise source -- this is the noise source based on the CPU * execution time jitter * * @param[in] ec entropy collector struct * @param[in] loop_cnt if a value not equal to 0 is set, use the given value as * number of loops to perform the hash operation * @param[in] stuck Is the time delta identified as stuck? */ static void jent_hash_loop(struct rand_data *ec, uint8_t intermediary[JENT_SIZEOF_INTERMEDIARY], uint64_t loop_cnt) { HASH_CTX_ON_STACK(ctx); uint8_t *digest = intermediary + JENT_OFFSET_HASH_BLOCK; uint64_t j = 0; /* * allow caller to set the counter */ uint64_t hash_loop_cnt = loop_cnt ? loop_cnt : ec->hashloopcnt; BUILD_BUG_ON(JENT_HASH_LOOP_DEFAULT < 1); BUILD_BUG_ON(JENT_HASH_LOOP_INIT < 1); jent_sha3_256_init(&ctx); /* * 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++) { /* Limit data size to prevent Keccak operation during update */ jent_sha3_update(&ctx, digest, 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 *) &ec->rct_mem_count, sizeof(ec->rct_mem_count)); jent_sha3_update(&ctx, (uint8_t *)&j, sizeof(uint64_t)); jent_sha3_final(&ctx, digest); } jent_memset_secure(&ctx, JENT_SHA_MAX_CTX_SIZE); } 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; } /** * Memory access noise source -- this is the noise source based on the memory * access time jitter * * @param[in] ec entropy collector struct * @param[in] loop_cnt 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_pseudorandom(struct rand_data *ec, uint64_t loop_cnt, uint64_t *current_delta) { uint64_t i = 0, time_now_start = 0, time_now_end = 0, tmp_delta = 0; union { uint32_t u[4]; uint8_t b[sizeof(uint32_t) * 4]; } prngState = { .u = {0x8e93eec0, 0xce65608a, 0xa8d46b46, 0xe83cef69} }; uint32_t addressMask; /* * allow caller to set the counter */ uint64_t mem_loop_cnt = loop_cnt ? loop_cnt : ec->memaccessloops; 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_start); prngState.b[i] ^= (uint8_t)(time_now_start & 0xff); } /* * Obtain the start time of the timing measurement when requested by * the caller. */ if (current_delta) jent_get_nstime_internal(ec, &time_now_start); for (i = 0; i < mem_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); } /* * Calculate the execution time by measuring the end time and obtain * the time delta. */ if (current_delta) { jent_get_nstime_internal(ec, &time_now_end); tmp_delta += jent_delta(time_now_start, time_now_end) / ec->jent_common_timer_gcd; *current_delta = tmp_delta; } } /** * 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. * * @param[in] ec 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 * @param[in] loop_cnt 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_deterministic(struct rand_data *ec, uint64_t loop_cnt, uint64_t *current_delta) { uint64_t time_now_start = 0, time_now_end = 0, tmp_delta = 0; unsigned int wrap = 0; uint64_t i = 0; /* * allow caller to set the counter */ uint64_t mem_loop_cnt = loop_cnt ? loop_cnt : ec->memaccessloops; if (NULL == ec || NULL == ec->mem) return; wrap = ec->memmask + 1; if (current_delta) jent_get_nstime_internal(ec, &time_now_start); for (i = 0; i < mem_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 + JENT_MEMORY_BLOCKSIZE - 1; ec->memlocation = ec->memlocation % wrap; } if (current_delta) { jent_get_nstime_internal(ec, &time_now_end); tmp_delta += jent_delta(time_now_start, time_now_end) / ec->jent_common_timer_gcd; *current_delta = tmp_delta; } } /*************************************************************************** * Start of entropy processing logic ***************************************************************************/ /** * This is the heart of the entropy generation for NTG.1 startup, invoking only * the memory access noise source: calculate time deltas and use the CPU jitter * in the time deltas. The jitter is injected into the entropy pool. * * @param[in] ec Reference to entropy collector * @param[in] loop_cnt see jent_hash_time * @param[out] ret_current_delta Test interface: return time delta - may be NULL * * @return: result of stuck test */ unsigned int jent_measure_jitter_ntg1_memaccess(struct rand_data *ec, uint64_t loop_cnt, uint64_t *ret_current_delta) { uint8_t intermediary[JENT_SIZEOF_INTERMEDIARY] = { 0 }; uint64_t current_delta = 0; unsigned int stuck; /* * Now call the memory noise source with tripple the default iteration * count considering this is the only noise source. * * The call returns the execution time delta. * * For the NTG.1 discussion, the following is of interest. NTG.1 * mandates that 2 separate noise sources are used. The hash loop * operation uses the variations from the CPU instructions and the L1 * cache data. The memory access loop here shall deliver variations from * the L2, L3 caches or RAM. To ensure that as little as possible L1 * operations are present, the xoshiro128starstar operation is not used. * The deterministic operation has less instructions and less L1 * accesses. Therefore, the deterministic operation only is used here. * * Furthermore, the increase of the memory access loop by 3 (the value * below is added to the original memory access loop) to ensure that * sufficient variations from L2 are collected to meet the NTG.1 * requirement of at least 240 bits of entropy from the L2/L3/RAM * accesses. */ jent_memaccess_deterministic( ec, loop_cnt ? loop_cnt : ec->memaccessloops * JENT_MEM_ACC_LOOP_INIT, ¤t_delta); /* * Check whether we have a stuck measurement - and apply the health * tests. */ stuck = jent_stuck(ec, current_delta); /* Domain separation */ intermediary[JENT_OFFSET_DOMAINSEPARATOR] = 0x01; /* Insert the data into the entropy pool */ jent_hash_insert(ec, current_delta, intermediary); /* return the raw entropy value */ if (ret_current_delta) *ret_current_delta = current_delta; return stuck; } /** * This is the heart of the entropy generation for NTG.1 startup, invoking only * the hash loop noise source: calculate time deltas and use the CPU jitter in * the time deltas. The jitter is injected into the entropy pool. * * @param[in] ec Reference to entropy collector * @param[in] loop_cnt see jent_hash_loop * @param[out] ret_current_delta Test interface: return time delta - may be NULL * * @return: result of stuck test */ unsigned int jent_measure_jitter_ntg1_sha3(struct rand_data *ec, uint64_t loop_cnt, uint64_t *ret_current_delta) { uint8_t intermediary[JENT_SIZEOF_INTERMEDIARY] = { 0 }; uint64_t time_now = 0; uint64_t current_delta = 0; unsigned int stuck; /* * Get time stamp to only measure the execution time of the hash loop * to make this part an independent entropy source (even excluding the * SHA3 update to insert the data into the entropy pool). */ jent_get_nstime_internal(ec, &ec->prev_time); /* * Now call the hash noise source with tripple the default iteration * count considering this is the only noise source. * * Place the digest at an offset allowing the time stamp and the * domain separator to be added before. */ jent_hash_loop(ec, intermediary, loop_cnt ? loop_cnt : ec->hashloopcnt * JENT_HASH_LOOP_INIT); /* * 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; /* * Check whether we have a stuck measurement - and apply the health * tests. */ stuck = jent_stuck(ec, current_delta); /* Domain separation */ intermediary[JENT_OFFSET_DOMAINSEPARATOR] = 0x02; /* Insert the data into the entropy pool */ jent_hash_insert(ec, current_delta, intermediary); /* return the raw entropy value */ if (ret_current_delta) *ret_current_delta = current_delta; return stuck; } /** * 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. * * @param[in] ec Reference to entropy collector * @param[in] loop_cnt see jent_hash_loop * @param[out] ret_current_delta 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) { /* Size of intermediary ensures a Keccak operation during hash_update */ uint8_t intermediary[JENT_SIZEOF_INTERMEDIARY] = { 0 }; uint64_t time_now = 0; uint64_t current_delta = 0; unsigned int stuck; /* Invoke memory access loop noise source */ #ifdef JENT_RANDOM_MEMACCESS jent_memaccess_pseudorandom(ec, loop_cnt, NULL); #else jent_memaccess_deterministic(ec, loop_cnt, NULL); #endif /* * 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); /* Invoke hash loop noise source */ jent_hash_loop(ec, intermediary, loop_cnt); /* Domain separation */ intermediary[JENT_OFFSET_DOMAINSEPARATOR] = 0x03; /* Insert the data into the entropy pool */ jent_hash_insert(ec, current_delta, intermediary); /* return the raw entropy value */ if (ret_current_delta) *ret_current_delta = current_delta; return stuck; } /* * We multiply the loop value with ->osr to obtain the oversampling rate * requested by the caller */ #define JENT_MEASURE_JITTER_LOOP_CTR(_osr, _safety_factor) \ ((DATA_SIZE_BITS + (_safety_factor)) * (_osr)) /* * The health test RCT with memory operates on multiples of three time deltas. * Therefore, round up the jitter loop counter to the nearest multiple of three. */ #define JENT_ROUNDUP_TO_THREE(x) \ ( (((x) + 2) / 3) * 3 ) #define JENT_ADJUSTED_MEASURE_JITTER_LOOP_CTR(_osr, _safety_factor) \ JENT_ROUNDUP_TO_THREE( \ JENT_MEASURE_JITTER_LOOP_CTR(_osr, _safety_factor)) static void jent_random_data_one( struct rand_data *ec, unsigned int (*measure_jitter)(struct rand_data *ec, uint64_t loop_cnt, uint64_t *ret_current_delta)) { unsigned int safety_factor = 0, ctr = 0; if (ec->fips_enabled) safety_factor = ENTROPY_SAFETY_FACTOR; /* RCT with memory: start a new iteration loop */ ec->rct_mem_ctr = 0; /* Obtain number of loop iterations */ ec->rct_mem_nosr = (unsigned short) JENT_ADJUSTED_MEASURE_JITTER_LOOP_CTR(ec->osr, safety_factor); /* Safety measure against wrapping */ if (ec->rct_mem_nosr < DATA_SIZE_BITS) { ec->health_failure |= JENT_RCT_MEM_FAILURE_PERMANENT; return; } /* Entropy collection loop */ while (!jent_health_failure(ec)) { /* If a stuck measurement is received, repeat measurement */ if (measure_jitter(ec, 0, NULL)) continue; if (++ctr >= ec->rct_mem_nosr) break; } } /** * Generator of one 256 bit random number * Function fills rand_data->hash_state * * @param[in] ec Reference to entropy collector */ void jent_random_data(struct rand_data *ec) { /* * Select which noise source to use for the entropy collection */ switch (ec->startup_state) { case jent_startup_memory: jent_random_data_one(ec, jent_measure_jitter_ntg1_memaccess); ec->startup_state--; /* * Initialize the health tests as we fall through to * independently invoke the next noise source. */ jent_health_init(ec, ec->flags & JENT_NTG1 ? jent_health_init_type_ntg1 : jent_health_init_type_common); /* FALLTHROUGH */ case jent_startup_sha3: jent_random_data_one(ec, jent_measure_jitter_ntg1_sha3); ec->startup_state--; /* * Initialize the health tests as we fall through to * independently invoke the next noise source. */ jent_health_init(ec, ec->flags & JENT_NTG1 ? jent_health_init_type_ntg1 : jent_health_init_type_common); break; case jent_startup_completed: default: /* priming of the ->prev_time value */ jent_measure_jitter(ec, 0, NULL); jent_random_data_one(ec, jent_measure_jitter); } } void jent_read_random_block(struct rand_data *ec, char *dst, size_t dst_len) { jent_drbg_generate_block(ec->hash_state, (uint8_t*)dst, dst_len); } jitterentropy-rngd-1.3.1/lib/jitterentropy-noise.h000066400000000000000000000030561517635422300223560ustar00rootroot00000000000000/* * Copyright (C) 2021 - 2026, 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_ntg1_memaccess(struct rand_data *ec, uint64_t loop_cnt, uint64_t *ret_current_delta); unsigned int jent_measure_jitter_ntg1_sha3(struct rand_data *ec, uint64_t loop_cnt, uint64_t *ret_current_delta); 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-rngd-1.3.1/lib/jitterentropy-sha3.c000066400000000000000000000412031517635422300220660ustar00rootroot00000000000000/* Jitter RNG: Keccak / SHA-3 / SHAKE / XDRBG Implementation * * Copyright (C) 2021 - 2026, 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; ctx->padding = 0x06; } void jent_shake256_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 = 0; ctx->padding = 0x1f; ctx->initially_seeded = 0; } 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] = ctx->padding; ctx->partial[ctx->r - 1] |= 0x80; /* Final transformation */ jent_sha3_fill_state(ctx, ctx->partial); jent_keccakp_1600(ctx->state); /* * Sponge squeeze phase - This squeeze implementation is deliberately * short for the use in XDRBG-like constructions as it has the following * caveats compared to a general-purpose squeeze: * * * the digest size is always smaller than the rate size r as we do not * have a loop around the jent_keccakp_1600 / copy out loop below * * * the requested digest size must be multiples of uint64_t */ for (i = 0; i < ctx->digestsize / 8; i++, digest += 8) le64_to_ptr(digest, ctx->state[i]); memset(ctx->partial, 0, ctx->r); jent_sha3_init(ctx); } 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); } /*********************************** XDRBG ************************************/ #define JENT_XDRBG_DRNG_ENCODE_N(x) ((x) * 85) /* * This operation implements XDRBG-256 as defined in [1]. * * The output size is [0:256] bits. * * [1] https://leancrypto.org/papers/xdrbg.pdf */ static void jent_xdrbg256_generate_block(struct jent_sha_ctx *ctx, uint8_t *dst, size_t dst_len) { /* * XDRBG: * 512 Bit for next state (internal memory) || 256 Bit output for user */ uint8_t jent_block_next_state[JENT_XDRBG_SIZE_STATE + JENT_SHA3_256_SIZE_DIGEST]; uint8_t encode; /* Checking the output size */ BUILD_BUG_ON(JENT_SHA3_256_SIZE_DIGEST != ((DATA_SIZE_BITS / 8))); /* * The XOF implementation only allows the generation of up to one * rate-size block. See the comments in the squeeze operation for * details */ BUILD_BUG_ON(JENT_SHA3_256_SIZE_BLOCK < sizeof(jent_block_next_state)); /* * The squeeze operation is limited to return multiples of uint64_t - * verify all set_digestsize values. */ BUILD_BUG_ON(JENT_XDRBG_SIZE_STATE % sizeof(uint64_t)); BUILD_BUG_ON(sizeof(jent_block_next_state) % sizeof(uint64_t)); /* The final operation automatically re-initializes the ->hash_state */ /* * XDRBG: finalize seeding * * seed is inserted with SHAKE-256 update * * initial seeding: * V ← XOF( encode(( seed ), α, 0), |V| ) * * reseeding: * V ← XOF( encode(( V' || seed ), α, 1), |V| ) * * The insertion of the V' is done at the end of this function for the * next finalization of the reseeding. α is defined to be empty. */ encode = JENT_XDRBG_DRNG_ENCODE_N(ctx->initially_seeded); ctx->initially_seeded = 1; jent_sha3_update(ctx, &encode, 1); jent_shake256_set_digestsize(ctx, JENT_XDRBG_SIZE_STATE); jent_sha3_final(ctx, jent_block_next_state); /* * XDRBG: generate * * ℓ = dst_len which is at maximum 256 bits * T ← XOF( encode(V', α, 2), ℓ + |V| ) * V ← first |V| bits of T * Σ ← last ℓ bits of T */ jent_sha3_update(ctx, jent_block_next_state, JENT_XDRBG_SIZE_STATE); encode = JENT_XDRBG_DRNG_ENCODE_N(2); jent_sha3_update(ctx, &encode, 1); /* * Request a full block irrespective of the output size due to * Keccak squeeze implementation limitation. */ jent_shake256_set_digestsize(ctx, sizeof(jent_block_next_state)); jent_sha3_final(ctx, jent_block_next_state); /* Return Σ to the caller truncated to the requested size */ if (dst_len) { /* Safety measure to not overflow the generated buffer */ if (dst_len > JENT_SHA3_256_SIZE_DIGEST) dst_len = JENT_SHA3_256_SIZE_DIGEST; memcpy(dst, jent_block_next_state + JENT_XDRBG_SIZE_STATE, dst_len); } /* * XDRBG: reseed * Set the V into the state. */ jent_sha3_update(ctx, jent_block_next_state, JENT_XDRBG_SIZE_STATE); jent_memset_secure(jent_block_next_state, sizeof(jent_block_next_state)); } void jent_drbg_generate_block(struct jent_sha_ctx *ctx, uint8_t *dst, size_t dst_len) { jent_xdrbg256_generate_block(ctx, dst, dst_len); } /********************************** Selftest **********************************/ /* * The SHAKE-256 support is only needed to support the XDRBG. Therefore, it is * implicitly self-tested with the XDRBG-256 self test. Yet, this self-test * code for SHAKE-256 is left in here to allow implementors to activate it at * their discretion. Furthermore it provides an example how to invoke the * Keccak operation as a SHAKE-256 for testing and analysis. */ #if 0 static int jent_shake256_tester(void) { HASH_CTX_ON_STACK(ctx); static const uint8_t msg[] = { 0x6C, 0x9E, 0xC8, 0x5C, 0xBA, 0xBA, 0x62, 0xF5, 0xBC, 0xFE, 0xA1, 0x9E, 0xB9, 0xC9, 0x20, 0x52, 0xD8, 0xFF, 0x18, 0x81, 0x52, 0xE9, 0x61, 0xC1, 0xEC, 0x5C, 0x75, 0xBF, 0xC3, 0xC9, 0x1C, 0x8D }; static const uint8_t exp[] = { 0x7d, 0x6a, 0x09, 0x6e, 0x13, 0x66, 0x1d, 0x9d, 0x0e, 0xca, 0xf5, 0x38, 0x30, 0xa1, 0x92, 0x87, 0xe0, 0xb3, 0x6e, 0xce, 0x48, 0x82, 0xeb, 0x58, 0x0b, 0x78, 0x5c, 0x1d, 0xef, 0x2d, 0xe5, 0xaa, 0x6c }; uint8_t act[sizeof(exp)] = { 0 }; unsigned int i; jent_shake256_init(&ctx); jent_sha3_update(&ctx, msg, sizeof(msg)); jent_shake256_set_digestsize(&ctx, sizeof(exp)); jent_sha3_final(&ctx, act); for (i = 0; i < sizeof(exp); i++) { if (exp[i] != act[i]) return 1; } return 0; } #endif static int jent_xdrbg256_tester(void) { HASH_CTX_ON_STACK(ctx); /* * Test vectors are generated using the leancrypto XDRBG implementation. */ static const uint8_t seed[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, }; static const uint8_t exp[] = { 0x51, 0xe4, 0x3c, 0xf6, 0x4b, 0xa2, 0x80, 0x77, 0x33, 0x1a, 0x47, 0xe3, 0xf8, 0xb4, 0x1a, 0x42, 0xad, 0xd3, 0xa0, 0xf2, 0x53, 0x97, 0x10, 0xdd, 0x6e, 0xa1, 0x16, 0x1d, 0x37, 0x8a, 0x6f, 0xb6 }; uint8_t act[sizeof(exp)] = { 0 }; unsigned int i; BUILD_BUG_ON(JENT_SHA3_256_SIZE_DIGEST != sizeof(exp)); jent_shake256_init(&ctx); /* Initial seed */ jent_sha3_update(&ctx, seed, sizeof(seed)); jent_xdrbg256_generate_block(&ctx, act, sizeof(act)); /* Reseeding */ jent_sha3_update(&ctx, seed, sizeof(seed)); jent_xdrbg256_generate_block(&ctx, act, sizeof(act)); for (i = 0; i < sizeof(exp); i++) { if (exp[i] != act[i]) return 1; } return 0; } static int jent_sha3_256_tester(void) { HASH_CTX_ON_STACK(ctx); static const uint8_t msg[] = { 0x5E, 0x5E, 0xD6 }; static const uint8_t exp[] = { 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[sizeof(exp)] = { 0 }; unsigned int i; jent_sha3_256_init(&ctx); jent_sha3_update(&ctx, msg, sizeof(msg)); jent_sha3_final(&ctx, act); for (i = 0; i < sizeof(exp); i++) { if (exp[i] != act[i]) return 1; } return 0; } int jent_sha3_tester(void) { if (jent_sha3_256_tester()) return 1; return jent_xdrbg256_tester(); } jitterentropy-rngd-1.3.1/lib/jitterentropy-sha3.h000066400000000000000000000047251517635422300221030ustar00rootroot00000000000000/* * Copyright (C) 2021 - 2026, 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_XDRBG_SIZE_STATE 64 struct jent_sha_ctx { uint64_t state[25]; uint8_t partial[JENT_SHA3_256_SIZE_BLOCK]; size_t msg_len; uint8_t r; uint8_t rword; /* * This implementation only supports up to rate-size digests for XOFs, * thus the data type can be appropriately small. */ uint8_t digestsize; uint8_t padding; uint8_t initially_seeded:1; }; #define JENT_SHA_MAX_CTX_SIZE (sizeof(struct jent_sha_ctx)) #define HASH_CTX_ON_STACK(name) \ struct jent_sha_ctx name static inline unsigned int jent_sha3_rate(void *hash_state) { struct jent_sha_ctx *ctx = hash_state; return ctx->r; } 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); void jent_shake256_init(struct jent_sha_ctx *ctx); static inline void jent_shake256_set_digestsize(struct jent_sha_ctx *ctx, unsigned int digestsize) { ctx->digestsize = (uint8_t)digestsize; } void jent_drbg_generate_block(struct jent_sha_ctx *ctx, uint8_t *dst, size_t dst_len); #ifdef __cplusplus } #endif #endif /* JITTERENTROPY_SHA3_H */ jitterentropy-rngd-1.3.1/lib/jitterentropy-status.c000066400000000000000000000130711517635422300225550ustar00rootroot00000000000000/* * Copyright (C) 2026, 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 "jitterentropy.h" #include "jitterentropy-base.h" #include "jitterentropy-internal.h" /* * Always validate the output with something like "jq -e .", when doing changes here. * * No JSON library is used here to keep dependencies slim and this is serialized only * here. */ int jent_status(const struct rand_data *ec, char *buf, size_t buflen) { size_t used; if (!buf || buflen == 0) return -1; #define jent_add_to_status(...) \ { \ used = strlen(buf); \ if (used < buflen) \ snprintf(buf + used, buflen - used, __VA_ARGS__);\ } /* needed as plain snprintf to make jent_add_to_status len calculation usable */ snprintf(buf, buflen, "{\n"); jent_add_to_status("\t\"version\": \"%u.%u.%u\",\n", JENT_MAJVERSION, JENT_MINVERSION, JENT_PATCHLEVEL) if (!ec) goto out; /* * health */ jent_add_to_status("\t\"healthFailure\": {\n"); jent_add_to_status("\t\t\"apt\": {\n"); jent_add_to_status("\t\t\t\"intermittent\": %s,\n", ec->health_failure & JENT_APT_FAILURE ? "true" : "false"); jent_add_to_status("\t\t\t\"permanent\": %s\n", ec->health_failure & JENT_APT_FAILURE_PERMANENT ? "true" : "false"); jent_add_to_status("\t\t},\n"); jent_add_to_status("\t\t\"rct\": {\n"); jent_add_to_status("\t\t\t\"intermittent\": %s,\n", ec->health_failure & JENT_RCT_FAILURE ? "true" : "false"); jent_add_to_status("\t\t\t\"permanent\": %s\n", ec->health_failure & JENT_RCT_FAILURE_PERMANENT ? "true" : "false"); jent_add_to_status("\t\t},\n"); jent_add_to_status("\t\t\"rctMemory\": {\n"); jent_add_to_status("\t\t\t\"intermittent\": %s,\n", ec->health_failure & JENT_RCT_MEM_FAILURE ? "true" : "false"); jent_add_to_status("\t\t\t\"permanent\": %s\n", ec->health_failure & JENT_RCT_MEM_FAILURE_PERMANENT ? "true" : "false"); jent_add_to_status("\t\t}"); #ifdef JENT_HEALTH_LAG_PREDICTOR jent_add_to_status(",\n"); jent_add_to_status("\t\t\"lag\": {\n"); jent_add_to_status("\t\t\t\"intermittent\": %s,\n", ec->health_failure & JENT_LAG_FAILURE ? "true" : "false"); jent_add_to_status("\t\t\t\"permanent\": %s\n", ec->health_failure & JENT_LAG_FAILURE_PERMANENT ? "true" : "false"); jent_add_to_status("\t\t}\n"); #else jent_add_to_status("\n"); #endif jent_add_to_status("\t},\n"); /* * runtime environment */ jent_add_to_status( "\t\"runtimeEnvironment\": {\n"); jent_add_to_status("\t\t\"cpuCores\": %ld,\n", jent_ncpu()); jent_add_to_status("\t\t\"cpuCache\": {\n"); jent_add_to_status("\t\t\t\"l1Bytes\": %u,\n", jent_cache_size_roundup(0)); jent_add_to_status("\t\t\t\"allBytes\": %u\n", jent_cache_size_roundup(1)); jent_add_to_status("\t\t}\n"); jent_add_to_status("\t},\n"); /* * configuration */ jent_add_to_status( "\t\"configuration\": {\n"); jent_add_to_status( "\t\t\"osr\": %u,\n", ec->osr); jent_add_to_status( "\t\t\"memoryBlockSizeBytes\": %u,\n", jent_memsize(ec->flags)); jent_add_to_status("\t\t\"hashLoopCount\": {\n"); jent_add_to_status("\t\t\t\"runtime\": %u,\n", jent_hashloop_cnt(ec->flags)); jent_add_to_status("\t\t\t\"initialization\": %u\n", jent_hashloop_cnt(ec->flags) * JENT_HASH_LOOP_INIT); jent_add_to_status("\t\t},\n"); jent_add_to_status("\t\t\"memoryLoopCount\": {\n"); jent_add_to_status("\t\t\t\"runtime\": %u,\n", ec->memaccessloops); jent_add_to_status("\t\t\t\"initialization\": %u\n", ec->memaccessloops * JENT_MEM_ACC_LOOP_INIT); jent_add_to_status("\t\t},\n"); jent_add_to_status("\t\t\"secureMemory\": %s,\n", jent_secure_memory_supported() ? "true" : "false"); jent_add_to_status("\t\t\"internalTimer\": %s,\n", ec->enable_notime ? "true" : "false"); jent_add_to_status("\t\t\"fipsMode\": %s,\n", ec->fips_enabled ? "true" : "false"); jent_add_to_status("\t\t\"ntg1Mode\": %s,\n", !!(ec->flags & JENT_NTG1) ? "true" : "false"); jent_add_to_status("\t\t\"flags\": {\n"); jent_add_to_status("\t\t\t\"JENT_DISABLE_MEMORY_ACCESS\": %s,\n", !!(ec->flags & JENT_DISABLE_MEMORY_ACCESS) ? "true" : "false"); jent_add_to_status("\t\t\t\"JENT_FORCE_INTERNAL_TIMER\": %s,\n", !!(ec->flags & JENT_FORCE_INTERNAL_TIMER) ? "true" : "false"); jent_add_to_status("\t\t\t\"JENT_DISABLE_INTERNAL_TIMER\": %s,\n", !!(ec->flags & JENT_DISABLE_INTERNAL_TIMER) ? "true" : "false"); jent_add_to_status("\t\t\t\"JENT_FORCE_FIPS\": %s,\n", !!(ec->flags & JENT_FORCE_FIPS) ? "true" : "false"); jent_add_to_status("\t\t\t\"JENT_NTG1\": %s,\n", !!(ec->flags & JENT_NTG1) ? "true" : "false"); jent_add_to_status("\t\t\t\"JENT_CACHE_ALL\": %s\n", !!(ec->flags & JENT_CACHE_ALL) ? "true" : "false"); jent_add_to_status("\t\t}\n"); jent_add_to_status("\t}\n"); out: jent_add_to_status("}\n"); used = strlen(buf); return (used >= buflen - 1) ? -1 : 0; #undef jent_add_to_status } jitterentropy-rngd-1.3.1/lib/jitterentropy-timer.c000066400000000000000000000164351517635422300223610ustar00rootroot00000000000000/* Jitter RNG: Internal timer implementation * * Copyright (C) 2021 - 2026, 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" /* Timer-less entropy source */ #ifdef JENT_CONF_ENABLE_INTERNAL_TIMER #ifdef JENT_PTHREAD #include struct jent_notime_ctx { pthread_attr_t notime_pthread_attr; /* pthreads library */ pthread_t notime_thread_id; /* pthreads thread ID */ }; #else #include struct jent_notime_ctx { thrd_t notime_thread_id; /* thread ID */ }; #endif /*************************************************************************** * Thread handler ***************************************************************************/ 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 -ENOENT; thread_ctx = jent_zalloc(sizeof(struct jent_notime_ctx)); if (!thread_ctx) return -ENOMEM; *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) jent_zfree(thread_ctx, sizeof(struct jent_notime_ctx)); } #else /* JENT_CONF_ENABLE_INTERNAL_TIMER */ int jent_notime_init(void **ctx) { (void)ctx; return 0; } void jent_notime_fini(void *ctx) { (void)ctx; } #endif /* JENT_CONF_ENABLE_INTERNAL_TIMER */ #ifdef JENT_CONF_ENABLE_INTERNAL_TIMER static int jent_notime_start(void *ctx, #ifdef JENT_PTHREAD void *(*start_routine) (void *), #else int (*start_routine) (void *), #endif void *arg) { struct jent_notime_ctx *thread_ctx = (struct jent_notime_ctx *)ctx; #ifdef JENT_PTHREAD int ret; #endif if (!thread_ctx) return -EINVAL; #ifdef JENT_PTHREAD 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); #else switch (thrd_create(&thread_ctx->notime_thread_id, start_routine, arg)) { case thrd_success: return 0; case thrd_nomem: return -ENOMEM; case thrd_timedout: return -ETIMEDOUT; case thrd_busy: return -EBUSY; case thrd_error: default: return -EINVAL; } #endif } static void jent_notime_stop(void *ctx) { struct jent_notime_ctx *thread_ctx = (struct jent_notime_ctx *)ctx; /* defensive check */ if (ctx == NULL) return; #ifdef JENT_PTHREAD pthread_join(thread_ctx->notime_thread_id, NULL); pthread_attr_destroy(&thread_ctx->notime_pthread_attr); #else thrd_join(thread_ctx->notime_thread_id, NULL); #endif } 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. */ #ifdef JENT_PTHREAD static void *jent_notime_sample_timer(void *arg) #else static int jent_notime_sample_timer(void *arg) #endif { struct rand_data *ec = (struct rand_data *)arg; ec->notime_timer = 0; while (1) { if (ec->notime_interrupt) goto out; ec->notime_timer++; } out: #ifdef JENT_PTHREAD return NULL; #else return 0; #endif } /* * 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-rngd-1.3.1/lib/jitterentropy-timer.h000066400000000000000000000047321517635422300223630ustar00rootroot00000000000000/* * Copyright (C) 2021 - 2026, 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 -1; } 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 */