rsakeyfind/0000755007273400016420000000000011040032700012477 5ustar jhaldermgradrsakeyfind/LICENSE0000644007273400016420000000304211040032700013503 0ustar jhaldermgradSoftware License Agreement (BSD License) Copyright (c) 2008, Nadia Heninger and J. Alex Halderman All rights reserved. Redistribution and use of this software in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * 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. * Neither the names of the authors nor the names of their institutions may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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. rsakeyfind/Makefile0000644007273400016420000000022511040032700014136 0ustar jhaldermgradCXXFLAGS= -Wall -O4 OBJS=rsakeyfind.o all: rsakeyfind rsakeyfind: $(OBJS) $(CXX) -o rsakeyfind $(OBJS) clean: @rm -f rsakeyfind *~ \#* $(OBJS) rsakeyfind/README0000644007273400016420000000305211040032700013357 0ustar jhaldermgradRSAKeyFinder 1.0 (2008-07-18) By Nadia Heninger and J. Alex Halderman This program illustrates automatic techniques for locating RSA private and public keys in a captured memory image, as described in Section 6.2 of the research paper: J. A. Halderman, S. D. Schoen, N. Heninger, W. Clarkson, W. Paul, J. A. Calandrino, A. J. Feldman, J. Appelbaum, and E. W. Felten. "Lest We Remember: Cold-Boot Attacks on Encryption Keys." Proc. 17th USENIX Security Symposium (Sec '08), San Jose, CA, July 2008. For more information, see: http://citp.princeton.edu/memory/ There are two simple approaches: a) The first method requires a modulus from a known public key. The program searches for the modulus and attempts to parse the surrounding data as a BER-encoded public or private key. b) The second method does not require any knowledge of the key. The program searches for a fixed pattern--the BER-encoded RSA version field followed by the integer type of the following field in an RSA key--and attempts to parse the surrounding data as a BER-encoded private key. We successfully tested these techniques on a Linux system running Apache 2.2.3 with mod_ssl. However, RSA implementations that store keys in memory using a different format will not be susceptible. USAGE: rsakeyfind MEMORY-IMAGE [MODULUS-FILE] If MODULUS-FILE is specified, the program uses method (a) and attempts to locate private and public keys; the MODULUS-FILE should contain a hex-encoded version of the RSA modulus. Otherwise, it uses method (b) and attempts to locate only private keys. rsakeyfind/rsakeyfind.cpp0000644007273400016420000001344411040032700015350 0ustar jhaldermgrad// RSAKeyFinder 1.0 (2008-07-18) // By Nadia Heninger and J. Alex Halderman #include #include #include #include #include #include #include #include #include #ifdef __FreeBSD__ #include #else #define err(x,y) { perror(y); exit(x); } #endif using namespace std; // Baby BER parser, just good enough for RSA keys. // // This is not robust to errors in the memory image, but if we added // some entropy testing and intelligent guessing, it could be made to be. // // Parses a single field of the key, beginning at start. Each field // consists of a type, a length, and a value. Puts the type of field // into type, the number of bytes into len, and returns a pointer to // the beginning of the value. unsigned char* ParseNext(unsigned char* start, unsigned int &type, unsigned int &len) { unsigned char *val = NULL; type = start[0]; len = 0; if ((start[1] & 0x80) == 0) { len = start[1]; val = &start[2]; } else { int lensize = start[1] & 0x7F; for (int i=0; i < lensize; i++) len = (len << 8) | start[2+i]; val = &start[2+lensize]; } return val; } // Sets output to a string displaying len bytes from buffer void OutputBytes(unsigned char* buffer, int len, string& output) { for (int i=0; i 1000) return false; output += *fields + " = \n"; OutputBytes(start,len,output); start += len; } return true; } // Returns a pointer to the beginning of a BER-encoded key by working // backwards from the given memory map offset, looking for the // sequence identifier (this is not completely safe) unsigned char *FindKeyStart(unsigned char *map, int offset) { for (int k = offset; k >= 0 && k > offset-20; k--) if (map[k] == 0x30) return &map[k]; return NULL; } // Finds and prints private (or private and public) keys in the memory // map by searching for given target pattern void FindKeys(unsigned char *image, int isize, unsigned char *target, int target_size, bool find_public) { for (int i = 0; i < isize - target_size; i++) { if (memcmp(&image[i], target, target_size)) continue; unsigned char *key = FindKeyStart(image, i); if (!key) continue; string output; if (PrintFields(key,private_fields,output)) { printf("FOUND PRIVATE KEY AT %x\n", (unsigned int)(key-image)); cout << output << "\n"; } else if (find_public && PrintFields(key,public_fields,output)) { printf("FOUND PUBLIC KEY AT %x\n", (unsigned int)(key-image)); cout << output << "\n"; } } } // Memory maps filename and return a pointer on success, setting len // to the length of the file (does not return on error) unsigned char *MapFile(char *filename, unsigned int &len) { int fd = open(filename, O_RDONLY); if (fd < 0) err(1, "image open failed"); struct stat st; if (fstat(fd, &st) != 0) err(1, "image fstat failed"); unsigned char *map; map = (unsigned char*)mmap(0, st.st_size, PROT_READ, MAP_SHARED, fd, 0); if (map == MAP_FAILED) err(1, "image mmap failed"); len = st.st_size; return map; } // Returns a decoded byte from a file of hex values, ignoring whitespace int GetHexByte(int fd) { for (;;) { char a[3]; if (read(fd, &a[0], 1) < 1) break; if ((a[0] >= '0' && a[0] <= '9') || (a[0] >= 'a' && a[0] <= 'f')) { if (read(fd, &a[1], 1) < 1) break; a[2] = '\0'; return strtol(a,NULL,16); } } return -1; } // Reads hexadecimal bytes from filename and returns a byte array // containing these values, setting len to the number of bytes (does not // return on error) unsigned char *ReadModulus(char *filename, unsigned int &len) { int fd = open(filename, O_RDONLY); if (fd < 0) err(1, "modulus open failed"); struct stat st; if (fstat(fd, &st) != 0) err(1, "modulus fstat failed"); unsigned char *modulus = new unsigned char[st.st_size]; for (len=0; ;len++) { int c = GetHexByte(fd); if (c == -1) break; modulus[len] = c; } close(fd); return modulus; } void Usage() { fprintf(stderr, "USAGE: rsakeyfind MEMORY-IMAGE [MODULUS-FILE]\n" "Locates BER-encoded RSA private keys in MEMORY-IMAGE.\n" "If MODULUS-FILE is specified, it will locate private and public keys" "matching the hex-encoded modulus read from this file.\n"); } int main(int argc, char *argv[]) { if (argc < 2 || argc > 3) { Usage(); exit(1); } unsigned int ilen; unsigned char *image = MapFile(argv[1], ilen); if (argc == 3) { // method 1: searching for modulus unsigned int mlen; unsigned char *modulus = ReadModulus(argv[2], mlen); FindKeys(image, ilen, modulus, mlen, true); } else { // method 2: searching for versionmarker unsigned char versionmarker[4] = {0x02, 0x01, 0x00, 0x02}; FindKeys(image, ilen, versionmarker, sizeof(versionmarker), false); } return 0; }