├── .gitignore ├── LICENSE ├── README.md ├── TokenTools.xcodeproj └── project.pbxproj ├── check-entropy.py ├── requirements.txt ├── token-rng.py ├── token-rng.upstart-systempy ├── token-rng.upstart-virtualenv └── token-tools.conf.sample /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | build/* 3 | *.pbxuser 4 | !default.pbxuser 5 | *.mode1v3 6 | !default.mode1v3 7 | *.mode2v3 8 | !default.mode2v3 9 | *.perspectivev3 10 | !default.perspectivev3 11 | *.xcworkspace 12 | !default.xcworkspace 13 | xcuserdata 14 | profile 15 | *.moved-aside 16 | DerivedData 17 | 18 | # OSX Noise 19 | .DS_Store 20 | profile 21 | *~ 22 | *.lock 23 | *.DS_Store 24 | *.swp 25 | *.out 26 | 27 | # Windows Noise 28 | [Tt]humbs.db 29 | 30 | 31 | # Python 32 | *.pyc 33 | env 34 | 35 | # runtime 36 | logs 37 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) [2013] [Stephen Oliver] 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TokenTools 2 | 3 | TokenTools is a set of simple utilities for interacting with cryptographic tokens like smartcards, hardware security modules (HSMs) and other similar devices. 4 | 5 | TokenTools is a successor project to a program I wrote a few years ago called CardRand, which I am [deprecating](#deprecating-cardrand) in favor of something cleaner, more capable and reliable. 6 | 7 | ## TokenRNG 8 | 9 | The first addition to TokenTools is TokenRNG, a direct replacement for CardRand. Instead of using libopensc directly as CardRand did, TokenRNG uses the standard PKCS#11 interface, so any device that is supported by a PKCS#11 library should work, including all devices that work with OpenSC as they provide a PKCS#11 library. 10 | 11 | ### Security notes 12 | 13 | It is possible that your cryptographic token is not actually giving you good 14 | quality random data, and it is also possible that your PKCS#11 library is altering 15 | what the token provides. All TokenRNG can do is make it possible to use them as 16 | a kernel entropy source, trust and entropy quality decisions are up to you. 17 | 18 | By default, TokenRNG tells the kernel that there are only 2 bits of entropy per 19 | byte of data received from the PKCS#11 library (the entropy_ratio configuration 20 | setting). This is probably a sane default in most cases. Setting it to zero will 21 | still mix random data from your device into the kernel pool without increasing 22 | the entropy count. Setting it to 8 is probably unwise without a very good reason. 23 | 24 | 25 | ### Setup 26 | 27 | Before you try to use anything in TokenTools, you need to ensure you have a working cryptographic token with all the right drivers and libraries installed. Some minor assistance to help you with that is available in the [Token Support](#token-support) section. 28 | 29 | Very minimal setup is required to use TokenRNG from the git repository, but you do need to install any libraries required to support your cryptographic token, and one Python library which can be installed either from your Linux package manager or from PyPi into a virtualenv. 30 | 31 | Package names and instructions are written for Ubuntu/Debian, so minor changes may be needed for Arch, Suse, CentOS, Fedora and others. 32 | 33 | #### Clone the repo 34 | 35 | At some point I may upload TokenTools to PyPi or package it for specific Linux distributions, but for now it's all just in git, so you'll just need to clone the repo to the right spot. 36 | 37 | cd /opt/ 38 | git clone https://github.com/infincia/TokenTools.git 39 | 40 | #### Install Python libraries 41 | 42 | If you intend to use a virtualenv, create and activate it, then install the python libraries into it: 43 | 44 | virtualenv /opt/TokenTools/env 45 | source /opt/TokenTools/env/bin/activate 46 | pip install -r /opt/TokenTools/requirements.txt 47 | 48 | If you don't intend to use a virtualenv, just install the PyKCS11 library directly from your package manager: 49 | 50 | sudo aptitude install python-pykcs11 51 | 52 | #### Configuration 53 | 54 | There's a simple, optional configuration file included in the root of the project called 'token-tools.conf.sample'. If you need to change the configuration for any of the utilities in TokenTools, copy and rename that file to '/etc/token-tools.conf': 55 | 56 | cp /opt/TokenTools/token-tools.conf.sample /etc/token-tools.conf 57 | 58 | If no configuration file is present in '/etc/', TokenRNG will simply use sane default settings that will work for most situations. 59 | 60 | ### Using TokenRNG 61 | 62 | As long as your token is generally working on the system, TokenRNG should work fine. You may need to change the 'reader_slot' configuration option in '/etc/token-tools.conf' if your token isn't in slot 0. 63 | 64 | If you leave the token plugged in all the time and aren't using it for anything else it, TokenRNG should work all the time without issue. 65 | 66 | #### Run TokenRNG directly for testing 67 | 68 | If using a virtualenv, first activate it: 69 | 70 | source /opt/TokenTools/env/bin/activate 71 | 72 | Then run the program directly to test it: 73 | 74 | cd /opt/TokenTools 75 | python token-rng.py 76 | 77 | 78 | #### Long term use 79 | 80 | There are 2 Ubuntu Upstart scripts included in the repo, just copy one of them to /etc/init and Upstart will keep it running for you. 81 | 82 | If you're using a virtualenv: 83 | 84 | cp /opt/TokenTools/token-rng.upstart-virtualenv /etc/init/token-rng.conf 85 | service token-rng start 86 | 87 | Otherwise: 88 | 89 | cp /opt/TokenTools/token-rng.upstart-systempy /etc/init/token-rng.conf 90 | service token-rng start 91 | 92 | 93 | ## Token Support 94 | 95 | You'll need a working PKCS#11 library and drivers for your token, and you'll need to ensure you can use the token on the system before trying to get TokenTools to work with it. 96 | 97 | There are some tokens that just work 100% with OpenSC, and others that don't work without proprietary drivers from the manufacturer even if they are CCID compliant, even on Linux, so you'll need to obtain those. 98 | 99 | I believe 'pcscd' and/or 'pcsclite' need to be installed for all of them, so do that first: 100 | 101 | sudo aptitude install pcscd libpcsclite1 pcsc-tools 102 | 103 | ### OpenSC supported tokens 104 | 105 | Install the right components directly from your Linux packager manager 106 | 107 | sudo aptitude install openct opensc 108 | 109 | ### Safenet/Aladdin eTokens 110 | 111 | The eToken PRO 32k, eToken PRO 64k and a few other models *should* work with OpenSC, so try that first. The eToken PRO 72K Javacard model and some of the other newer models require the proprietary Safenet Authentication Client in order to work on Linux. You'll have to find SAC via Google as it isn't freely available. The most recent version I'm aware of is SAC 8.3, but I don't have it and I'm currently using SAC 8.1 on Ubuntu 13.04 without much trouble. 112 | 113 | For SAC 8.1 I needed to install libhal1 and create some symlinks before everything worked: 114 | 115 | apt-get install libhal1 116 | dpkg -i SafenetAuthenticationClient-8.1.0-5_amd64.deb 117 | ln -s /lib64/libeToken.so.8.1 /usr/lib64/eToken/libeToken.so.8 118 | ln -s /lib64/libeTokenUI.so.8.1 /usr/lib64/eToken/libeTokenUI.so.8 119 | 120 | ### Testing your token 121 | 122 | Plug in your token and run one of these: 123 | 124 | opensc-tool -l 125 | openct-tool list 126 | pcsc_scan 127 | 128 | If your token shows up with any of those commands, you shouldn't have much trouble getting it to work with TokenTools. If nothing shows up, 'pcscd' or 'openct' or a proprietary service for your token may need to be running, check the documentation for it. 129 | 130 | ## Deprecating CardRand 131 | 132 | CardRand was a simple C program that used the hardware random number generator (HWRNG) present in many smartcard/eToken devices as a random number source for the Linux kernel entropy pool, allowing systems that don't otherwise have a high quality HWRNG built-in to attach one easily, even on systems like laptops or embedded ARM devices where connecting a PCI card or making internal modifications is not possible. Only a USB port on the host and a USB cryptographic token are required in most cases, which are both very common. 133 | 134 | Back when it was written, CardRand worked pretty well for the quick hack that it was. However, it was designed to use OpenSC libraries directly, which prevented it from working with any cryptographic tokens that OpenSC did not support. 135 | 136 | Additionally, the functions CardRand was using in libopensc were likely never intended to be used by other applications at all, but rather were used to support their own internal tools like opensc-explorer. So the functions CardRand depended on were something of a defacto "private API", and they do seem to have changed more than once from one OpenSC release to another. 137 | 138 | There's a better way to do this. 139 | 140 | So, CardRand is deprecated. It does not work on most systems anymore, it is difficult to compile with modern versions of OpenSC on modern Linux distributions, and TokenRNG is a superior drop-in replacement for it. 141 | 142 | -------------------------------------------------------------------------------- /TokenTools.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXFileReference section */ 10 | AA96224A18134DF900CB2D8F /* check-entropy.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = "check-entropy.py"; sourceTree = ""; }; 11 | AAB2774C17D696BB00277751 /* token-tools.conf.sample */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "token-tools.conf.sample"; sourceTree = ""; }; 12 | AADA260F17D3F5E000B9E48D /* .gitignore */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = .gitignore; sourceTree = ""; }; 13 | AADA261017D3F5E000B9E48D /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = README.md; sourceTree = ""; }; 14 | AADA261117D3F5E000B9E48D /* LICENSE */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = LICENSE; sourceTree = ""; }; 15 | AADA261217D3F5E000B9E48D /* requirements.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = requirements.txt; sourceTree = ""; }; 16 | AADA261317D4013100B9E48D /* token-rng.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = "token-rng.py"; sourceTree = ""; }; 17 | AADA261417D4374700B9E48D /* token-rng.upstart-systempy */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "token-rng.upstart-systempy"; sourceTree = ""; }; 18 | AADA261517D43AC000B9E48D /* token-rng.upstart-virtualenv */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "token-rng.upstart-virtualenv"; sourceTree = ""; }; 19 | /* End PBXFileReference section */ 20 | 21 | /* Begin PBXGroup section */ 22 | AADA260417D3F5A700B9E48D = { 23 | isa = PBXGroup; 24 | children = ( 25 | AADA261717D4786E00B9E48D /* Configuration */, 26 | AADA261817D4787A00B9E48D /* Init scripts */, 27 | AADA261917D4788900B9E48D /* Code */, 28 | AADA261A17D4789400B9E48D /* Other */, 29 | ); 30 | sourceTree = ""; 31 | }; 32 | AADA261717D4786E00B9E48D /* Configuration */ = { 33 | isa = PBXGroup; 34 | children = ( 35 | AAB2774C17D696BB00277751 /* token-tools.conf.sample */, 36 | ); 37 | name = Configuration; 38 | sourceTree = ""; 39 | }; 40 | AADA261817D4787A00B9E48D /* Init scripts */ = { 41 | isa = PBXGroup; 42 | children = ( 43 | AADA261517D43AC000B9E48D /* token-rng.upstart-virtualenv */, 44 | AADA261417D4374700B9E48D /* token-rng.upstart-systempy */, 45 | ); 46 | name = "Init scripts"; 47 | sourceTree = ""; 48 | }; 49 | AADA261917D4788900B9E48D /* Code */ = { 50 | isa = PBXGroup; 51 | children = ( 52 | AADA261317D4013100B9E48D /* token-rng.py */, 53 | AA96224A18134DF900CB2D8F /* check-entropy.py */, 54 | ); 55 | name = Code; 56 | sourceTree = ""; 57 | }; 58 | AADA261A17D4789400B9E48D /* Other */ = { 59 | isa = PBXGroup; 60 | children = ( 61 | AADA260F17D3F5E000B9E48D /* .gitignore */, 62 | AADA261017D3F5E000B9E48D /* README.md */, 63 | AADA261117D3F5E000B9E48D /* LICENSE */, 64 | AADA261217D3F5E000B9E48D /* requirements.txt */, 65 | ); 66 | name = Other; 67 | sourceTree = ""; 68 | }; 69 | /* End PBXGroup section */ 70 | 71 | /* Begin PBXLegacyTarget section */ 72 | AADA260917D3F5A700B9E48D /* TokenTools */ = { 73 | isa = PBXLegacyTarget; 74 | buildArgumentsString = "$(ACTION)"; 75 | buildConfigurationList = AADA260C17D3F5A700B9E48D /* Build configuration list for PBXLegacyTarget "TokenTools" */; 76 | buildPhases = ( 77 | ); 78 | buildToolPath = open; 79 | dependencies = ( 80 | ); 81 | name = TokenTools; 82 | passBuildSettingsInEnvironment = 1; 83 | productName = TokenRNG; 84 | }; 85 | /* End PBXLegacyTarget section */ 86 | 87 | /* Begin PBXProject section */ 88 | AADA260517D3F5A700B9E48D /* Project object */ = { 89 | isa = PBXProject; 90 | attributes = { 91 | LastUpgradeCheck = 0460; 92 | ORGANIZATIONNAME = infincia; 93 | }; 94 | buildConfigurationList = AADA260817D3F5A700B9E48D /* Build configuration list for PBXProject "TokenTools" */; 95 | compatibilityVersion = "Xcode 3.2"; 96 | developmentRegion = English; 97 | hasScannedForEncodings = 0; 98 | knownRegions = ( 99 | en, 100 | ); 101 | mainGroup = AADA260417D3F5A700B9E48D; 102 | projectDirPath = ""; 103 | projectRoot = ""; 104 | targets = ( 105 | AADA260917D3F5A700B9E48D /* TokenTools */, 106 | ); 107 | }; 108 | /* End PBXProject section */ 109 | 110 | /* Begin XCBuildConfiguration section */ 111 | AADA260A17D3F5A700B9E48D /* Debug */ = { 112 | isa = XCBuildConfiguration; 113 | buildSettings = { 114 | ALWAYS_SEARCH_USER_PATHS = NO; 115 | ARCHS = "$(ARCHS_STANDARD_64_BIT)"; 116 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 117 | CLANG_CXX_LIBRARY = "libc++"; 118 | CLANG_WARN_CONSTANT_CONVERSION = YES; 119 | CLANG_WARN_EMPTY_BODY = YES; 120 | CLANG_WARN_ENUM_CONVERSION = YES; 121 | CLANG_WARN_INT_CONVERSION = YES; 122 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 123 | COPY_PHASE_STRIP = NO; 124 | GCC_C_LANGUAGE_STANDARD = gnu99; 125 | GCC_DYNAMIC_NO_PIC = NO; 126 | GCC_ENABLE_OBJC_EXCEPTIONS = YES; 127 | GCC_OPTIMIZATION_LEVEL = 0; 128 | GCC_PREPROCESSOR_DEFINITIONS = ( 129 | "DEBUG=1", 130 | "$(inherited)", 131 | ); 132 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 133 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 134 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 135 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 136 | GCC_WARN_UNUSED_VARIABLE = YES; 137 | MACOSX_DEPLOYMENT_TARGET = 10.8; 138 | ONLY_ACTIVE_ARCH = YES; 139 | SDKROOT = macosx; 140 | }; 141 | name = Debug; 142 | }; 143 | AADA260B17D3F5A700B9E48D /* Release */ = { 144 | isa = XCBuildConfiguration; 145 | buildSettings = { 146 | ALWAYS_SEARCH_USER_PATHS = NO; 147 | ARCHS = "$(ARCHS_STANDARD_64_BIT)"; 148 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 149 | CLANG_CXX_LIBRARY = "libc++"; 150 | CLANG_WARN_CONSTANT_CONVERSION = YES; 151 | CLANG_WARN_EMPTY_BODY = YES; 152 | CLANG_WARN_ENUM_CONVERSION = YES; 153 | CLANG_WARN_INT_CONVERSION = YES; 154 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 155 | COPY_PHASE_STRIP = YES; 156 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 157 | GCC_C_LANGUAGE_STANDARD = gnu99; 158 | GCC_ENABLE_OBJC_EXCEPTIONS = YES; 159 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 160 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 161 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 162 | GCC_WARN_UNUSED_VARIABLE = YES; 163 | MACOSX_DEPLOYMENT_TARGET = 10.8; 164 | SDKROOT = macosx; 165 | }; 166 | name = Release; 167 | }; 168 | AADA260D17D3F5A700B9E48D /* Debug */ = { 169 | isa = XCBuildConfiguration; 170 | buildSettings = { 171 | DEBUGGING_SYMBOLS = YES; 172 | GCC_GENERATE_DEBUGGING_SYMBOLS = YES; 173 | GCC_OPTIMIZATION_LEVEL = 0; 174 | OTHER_CFLAGS = ""; 175 | OTHER_LDFLAGS = ""; 176 | PRODUCT_NAME = TokenTools; 177 | }; 178 | name = Debug; 179 | }; 180 | AADA260E17D3F5A700B9E48D /* Release */ = { 181 | isa = XCBuildConfiguration; 182 | buildSettings = { 183 | OTHER_CFLAGS = ""; 184 | OTHER_LDFLAGS = ""; 185 | PRODUCT_NAME = TokenTools; 186 | }; 187 | name = Release; 188 | }; 189 | /* End XCBuildConfiguration section */ 190 | 191 | /* Begin XCConfigurationList section */ 192 | AADA260817D3F5A700B9E48D /* Build configuration list for PBXProject "TokenTools" */ = { 193 | isa = XCConfigurationList; 194 | buildConfigurations = ( 195 | AADA260A17D3F5A700B9E48D /* Debug */, 196 | AADA260B17D3F5A700B9E48D /* Release */, 197 | ); 198 | defaultConfigurationIsVisible = 0; 199 | defaultConfigurationName = Release; 200 | }; 201 | AADA260C17D3F5A700B9E48D /* Build configuration list for PBXLegacyTarget "TokenTools" */ = { 202 | isa = XCConfigurationList; 203 | buildConfigurations = ( 204 | AADA260D17D3F5A700B9E48D /* Debug */, 205 | AADA260E17D3F5A700B9E48D /* Release */, 206 | ); 207 | defaultConfigurationIsVisible = 0; 208 | defaultConfigurationName = Release; 209 | }; 210 | /* End XCConfigurationList section */ 211 | }; 212 | rootObject = AADA260517D3F5A700B9E48D /* Project object */; 213 | } 214 | -------------------------------------------------------------------------------- /check-entropy.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import sys 4 | import os 5 | import logging 6 | import time 7 | 8 | log = logging.getLogger(__name__) 9 | log.setLevel(logging.INFO) 10 | mainHandler = logging.StreamHandler() 11 | mainHandler.setFormatter(logging.Formatter('%(levelname)s %(asctime)s - %(module)s - %(funcName)s: %(message)s')) 12 | log.addHandler(mainHandler) 13 | 14 | 15 | PROC_ENTROPY_AVAIL = '/proc/sys/kernel/random/entropy_avail' 16 | 17 | 18 | def print_entropy_avail(): 19 | with open(PROC_ENTROPY_AVAIL, 'r') as entropy_avail: 20 | log.info('Entropy in pool: %s' % entropy_avail.readline()) 21 | 22 | 23 | def run_loop(): 24 | try: 25 | while True: 26 | print_entropy_avail() 27 | time.sleep(1) 28 | except KeyboardInterrupt as e: 29 | log.debug('Exiting due to keyboard interrupt') 30 | sys.exit(0) 31 | 32 | 33 | if __name__ == '__main__': 34 | run_loop() -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | PyKCS11==1.2.4 -------------------------------------------------------------------------------- /token-rng.py: -------------------------------------------------------------------------------- 1 | import PyKCS11 2 | import threading 3 | import fcntl 4 | import time 5 | import struct 6 | import sys 7 | import os 8 | import logging 9 | import configparser 10 | import binascii 11 | 12 | # Defaults for the program constants, DO NOT change them here, insert your own 13 | # values in /etc/token-tools.conf 14 | tokenrng_defaults = {'pkcs11_library': '/usr/lib/x86_64-linux-gnu/opensc-pkcs11.so', 15 | 'reader_slot': 0, 16 | 'random_chunk_size': 128, 17 | 'entropy_ratio': 2, 18 | 'debug': False} 19 | 20 | tokenrng_config = configparser.ConfigParser(defaults=tokenrng_defaults) 21 | tokenrng_config.read('/etc/token-tools.conf') 22 | 23 | 24 | """ 25 | constants 26 | 27 | """ 28 | 29 | FS_DEV_RANDOM = '/dev/random' 30 | PROC_ENTROPY_AVAIL = '/proc/sys/kernel/random/entropy_avail' 31 | 32 | DEBUG = tokenrng_config.getboolean('Global', 'debug', 33 | fallback=tokenrng_defaults['debug']) 34 | 35 | # The actual PKCS#11 library on the system used to interact with your 36 | # cryptographic token, defaults to OpenSC 37 | PKCS11_LIBRARY = tokenrng_config.get('Global', 'pkcs11_library', 38 | fallback=tokenrng_defaults['pkcs11_library']) 39 | 40 | # Which reader slot is the token connected to, should be zero when only one 41 | # token is ever connected 42 | READER_SLOT = tokenrng_config.getint('Global', 'reader_slot', 43 | fallback=tokenrng_defaults['reader_slot']) 44 | 45 | # How much random data to request from the library in each pass 46 | RANDOM_CHUNK_SIZE = tokenrng_config.getint('Global', 'random_chunk_size', 47 | fallback=tokenrng_defaults['random_chunk_size']) 48 | 49 | # Depending on the device + PKCS#11 library, the actual entropy per byte 50 | # received may be less than 8bits per byte, so we must make it configurable by 51 | # the user. Defaults low at 2bits per byte, increase if you're SURE your 52 | # device+library provide more. 53 | ENTROPY_RATIO = tokenrng_config.getint('Global', 'entropy_ratio', 54 | fallback=tokenrng_defaults['entropy_ratio']) 55 | 56 | 57 | # This IOCTL macro was derived from include/uapi/linux/random.h in linux source 58 | RNDADDENTROPY = 1074287107 59 | # It seems to be universally constant, but in case it isn't, we could retrieve 60 | # it from the kernel headers on each system at runtime and fall back to this one 61 | # if they're missing. To check, compile and run this C on your Linux system: 62 | # gcc -o randaddentropy randaddentropy.c; ./randaddentropy 63 | """ 64 | #include 65 | #include 66 | 67 | int main(void) { 68 | int rndval = RNDADDENTROPY; 69 | printf("\n RNDADDENTROPY: %d", rndval); 70 | return 0; 71 | } 72 | """ 73 | 74 | 75 | 76 | """ 77 | globals 78 | 79 | """ 80 | 81 | pkcs11_api = None 82 | token_session = None 83 | 84 | # Someday we'll handle signals or other runtime commands but for now just loop 85 | RUN_LOOP = True 86 | 87 | 88 | # setup logging according to configuration 89 | log = logging.getLogger(__name__) 90 | if DEBUG: 91 | log.setLevel(logging.DEBUG) 92 | else: 93 | log.setLevel(logging.INFO) 94 | mainHandler = logging.StreamHandler() 95 | mainHandler.setFormatter(logging.Formatter('%(levelname)s %(asctime)s - %(module)s - %(funcName)s: %(message)s')) 96 | log.addHandler(mainHandler) 97 | 98 | 99 | # helper functions 100 | def pkcs11_getrandom(): 101 | if token_session is not None: 102 | raw = token_session.generateRandom(RANDOM_CHUNK_SIZE) 103 | rand_byte_array = bytearray(raw) 104 | rand_byte_hex = binascii.hexlify(rand_byte_array) 105 | log.debug('Random data length: %d bytes, hex value: %s' % (len(rand_byte_array),rand_byte_hex)) 106 | return rand_byte_array 107 | else: 108 | log.error('No token session available, can\'t get random data') 109 | return None 110 | 111 | def pkcs11_reset(library=None): 112 | global pkcs11_api 113 | global token_session 114 | if library is not None: 115 | log.debug('Initializing library: %s' % library) 116 | pkcs11_api = PyKCS11.PyKCS11Lib() 117 | pkcs11_api.load(library) 118 | while token_session is None: 119 | try: 120 | # Session doesn't initialize without this, does initialize on 121 | # 2nd attempt with it. TODO:0 Investigate why this fixes it. 122 | pkcs11_api.getSlotList() 123 | token_session = pkcs11_api.openSession(READER_SLOT) 124 | log.debug('Token session initialized: %s' % token_session) 125 | except PyKCS11.PyKCS11Error as e: 126 | token_session = None 127 | log.error('Token session unavailable at slot: %s, check configuration', READER_SLOT) 128 | log.error(pkcs11_api.getSlotList()) 129 | time.sleep(3) 130 | 131 | def print_entropy_avail(): 132 | with open(PROC_ENTROPY_AVAIL, 'r') as entropy_avail: 133 | log.debug('Entropy in pool: %s' % entropy_avail.readline()) 134 | 135 | 136 | # main program loop 137 | def run_loop(): 138 | log.info('TokenRNG initializing at %s', time.ctime()) 139 | log.debug('Config defaults: %s', tokenrng_config.defaults()) 140 | try: 141 | log.debug('Config token: %s', tokenrng_config.items('Global')) 142 | except configparser.NoSectionError: 143 | log.debug('Unable to load /etc/token-tools.conf') 144 | 145 | try: 146 | while RUN_LOOP: 147 | if token_session is None: 148 | pkcs11_reset(library=PKCS11_LIBRARY) 149 | random_sample = pkcs11_getrandom() 150 | if random_sample is not None: 151 | fmt = 'ii%is' % RANDOM_CHUNK_SIZE 152 | packed_data = struct.pack(fmt, 153 | len(random_sample) * ENTROPY_RATIO, 154 | len(random_sample), 155 | bytes(random_sample)) 156 | with open(FS_DEV_RANDOM, 'a+') as dev_random: 157 | fcntl.ioctl(dev_random, RNDADDENTROPY, packed_data) 158 | print_entropy_avail() 159 | else: 160 | time.sleep(1) 161 | except KeyboardInterrupt as e: 162 | log.debug('Exiting due to keyboard interrupt') 163 | sys.exit(0) 164 | 165 | 166 | if __name__ == '__main__': 167 | run_loop() 168 | 169 | 170 | -------------------------------------------------------------------------------- /token-rng.upstart-systempy: -------------------------------------------------------------------------------- 1 | # token-rng 2 | # 3 | # Allows Linux kernel to utilize cryptographic hardware to feed kernel entropy pool 4 | 5 | description "TokenRNG" 6 | 7 | start on filesystem or runlevel [2345] 8 | stop on runlevel [!2345] 9 | 10 | respawn 11 | respawn limit 10 5 12 | 13 | exec /usr/bin/python /opt/TokenTools/token-rng.py 14 | 15 | -------------------------------------------------------------------------------- /token-rng.upstart-virtualenv: -------------------------------------------------------------------------------- 1 | # token-rng 2 | # 3 | # Allows Linux kernel to utilize cryptographic hardware to feed kernel entropy pool 4 | 5 | description "TokenRNG" 6 | 7 | start on filesystem or runlevel [2345] 8 | stop on runlevel [!2345] 9 | 10 | respawn 11 | respawn limit 10 5 12 | 13 | exec /opt/TokenTools/env/bin/python /opt/TokenTools/token-rng.py 14 | 15 | -------------------------------------------------------------------------------- /token-tools.conf.sample: -------------------------------------------------------------------------------- 1 | [Global] 2 | # Common library locations 3 | # safenet 4 | #pkcs11_library = /lib64/libeToken.so.8.1 5 | # opensc on x86_64 in debian/ubuntu 6 | pkcs11_library = /usr/lib/x86_64-linux-gnu/opensc-pkcs11.so 7 | reader_slot = 0 8 | random_chunk_size = 128 9 | entropy_ratio = 2 10 | debug = no --------------------------------------------------------------------------------