aesfix/0000755007273400016420000000000011040030636011625 5ustar jhaldermgradaesfix/aesfix.cpp0000644007273400016420000002175211040146467013631 0ustar jhaldermgrad// AESFix 1.0.1 (2008-07-18) // By Nadia Heninger and J. Alex Halderman #include #include #include #include #include using namespace std; #ifdef __FreeBSD__ #include #else #define err(x,y) { perror(y); exit(x); } #endif #include "aes.h" #include "errvect.h" #define ROUND_SIZE 16 // Bytes in an AES round #define ROUNDS 11 // Rounds in an AES-128 key schedule #define SCHED_LEN (ROUND_SIZE * ROUNDS) // Bytes in an AES-128 key schedule #define SLICES 4 // Number of slices used in decoding #define SLICE_SIZE 7 // Bytes per slice // AES-128 key schedule union Sched { uint8_t byte[ROUNDS*ROUND_SIZE]; union { union { uint8_t byte[4]; uint32_t all; } word[ROUND_SIZE/4]; } round[ROUNDS]; union { uint8_t byte[4]; uint32_t all; } word[ROUNDS*ROUND_SIZE/4]; }; // Key schedule slice used for decoding union Slice { uint8_t byte[SLICE_SIZE]; uint32_t word; uint64_t qword; }; typedef std::vector SliceVector; // Tests whether codeword could have decayed to vector via // unidirectional bit decay of 1->0 (i.e. that all the bits in vector // that are 1 are also 1 in codeword) and returns the opposite inline bool InvalidDecay(uint64_t vector, uint64_t codeword) { return codeword ^ (vector | codeword); } inline bool InvalidDecay(uint32_t vector, uint32_t codeword) { return codeword ^ (vector | codeword); } inline bool InvalidDecay(uint8_t vector, uint8_t codeword) { return codeword ^ (vector | codeword); } // Prints a key schedule void PrintSched(Sched &sched) { for (int r=0; r < ROUNDS; r++) { for (int w=0; w < ROUND_SIZE/4; w++) { for (int b=0; b < 4; b++) printf("%02X", sched.round[r].word[w].byte[b]); printf(" "); } printf("\n"); } printf("\n"); } // Places the necessary bytes back in the key schedule in slice-position s // (it wouldn't hurt to do all the bytes, but this is faster) void inline SmushSched(Sched &sched, Slice &slice, int s) { sched.word[3].byte[(s+1)&3] = slice.byte[3]; sched.word[4].byte[s] = slice.byte[4]; sched.word[5].byte[s] = slice.byte[5]; sched.word[6].byte[s] = slice.byte[6]; } // Places bytes of round 0 back in the key schedule in slice-position s void SmushKey(Sched &sched, Slice &slice, int s) { sched.word[0].byte[s] = slice.byte[0]; sched.word[1].byte[s] = slice.byte[1]; sched.word[2].byte[s] = slice.byte[2]; sched.word[3].byte[(s+1)&3] = slice.byte[3]; } // Expands candidate key schedule and checks whether the original key // schedule could have been formed from it by unidirectional bit decay inline bool TestDecoding(Sched &original, Sched &candidate) { candidate.round[1].word[3].all = candidate.round[1].word[2].all ^ candidate.round[0].word[3].all; if (InvalidDecay(original.round[1].word[3].all, candidate.round[1].word[3].all)) return false; for (int r = 2; r < ROUNDS; r++) { candidate.round[r].word[0].byte[0] = sbox[candidate.round[r-1].word[3].byte[1]] ^ candidate.round[r-1].word[0].byte[0] ^ rcon[r]; candidate.round[r].word[0].byte[1] = sbox[candidate.round[r-1].word[3].byte[2]] ^ candidate.round[r-1].word[0].byte[1]; candidate.round[r].word[0].byte[2] = sbox[candidate.round[r-1].word[3].byte[3]] ^ candidate.round[r-1].word[0].byte[2]; candidate.round[r].word[0].byte[3] = sbox[candidate.round[r-1].word[3].byte[0]] ^ candidate.round[r-1].word[0].byte[3]; if (InvalidDecay(original.round[r].word[0].all, candidate.round[r].word[0].all)) return false; for (int w = 1; w < ROUND_SIZE/4; w++) { candidate.round[r].word[w].all = candidate.round[r].word[w-1].all ^ candidate.round[r-1].word[w].all; if (InvalidDecay(original.round[r].word[w].all, candidate.round[r].word[w].all)) return false; } } return true; } // Expands slices a and b to form a single byte, // round[1].word[3].byte[s], and returns true if it could not have // decayed into the corresponding byte of the original key schedule. // (This test is a performance optimization, and may be skipped.) inline bool TestDecodeByte(Sched &original, int s, Slice &a, Slice &b) { return InvalidDecay(original.round[1].word[3].byte[s], a.byte[6] ^ b.byte[3]); } // Tests all combinations of current decodings that have the slice // cand in slice-position s; prints the corrected key schedule if // a combination passes the test void CombineDecodings(Sched &original, SliceVector decodings[SLICES], Slice &cand, int s) { int a, b, c; switch (s) { case 0: a = 3; b = 2; c = 1; break; case 1: a = 0; b = 3; c = 2; break; case 2: a = 1; b = 0; c = 3; break; default: a = 2; b = 1; c = 0; } Sched sched; SmushSched(sched, cand, s); SmushKey(sched, cand, s); SliceVector &A = decodings[a]; SliceVector &B = decodings[b]; SliceVector &C = decodings[c]; for (int i=A.size()-1; i >= 0; i--) { if (TestDecodeByte(original, s, cand, A[i])) continue; SmushSched(sched, A[i], (s+3)&3); for (int j=B.size()-1; j >= 0; j--) { if (TestDecodeByte(original, (s+3)&3, A[i], B[j])) continue; SmushSched(sched, B[j], (s+6)&3); for (int k=C.size()-1; k >= 0; k--) { if (TestDecodeByte(original, (s+6)&3, B[j], C[k])) continue; if (TestDecodeByte(original, (s+9)&3, C[k], cand)) continue; SmushSched(sched, C[k], (s+9)&3); if (TestDecoding(original, sched)) { SmushKey(sched, A[i], a); SmushKey(sched, B[j], b); SmushKey(sched, C[k], c); fprintf(stderr, "\ncorrected key schedule:\n"); PrintSched(sched); exit(1); } } } } } // Tests all combinations of current decodings with at least one // element from newDecodings void TryNewDecodings(Sched &original, SliceVector oldDecodings[4], SliceVector newDecodings[4]) { long long unsigned int p1=1, p2=1; for (int i=0; i < SLICES; i++) { p1 *= oldDecodings[i].size() + newDecodings[i].size(); p2 *= oldDecodings[i].size(); } fprintf(stderr, "%llu possibilities\n", p1-p2); for (int s=0; s < SLICES; s++) { for (unsigned int i=0; i < newDecodings[s].size(); i++) { CombineDecodings(original, oldDecodings, newDecodings[s][i], s); oldDecodings[s].push_back(newDecodings[s][i]); } } } // Expands the first 4 bytes of slice n into 7 bytes void SliceExpand(Slice &s, int n) { s.byte[4] = sbox[s.byte[3]] ^ s.byte[0]; if (n == 0) s.byte[4] ^= rcon[1]; s.byte[5] = s.byte[1] ^ s.byte[4]; s.byte[6] = s.byte[2] ^ s.byte[5]; } // Generates all legal decodings for slices with a given weight void DecodeSlices(Slice slice[SLICES], int weight, SliceVector decodings[4]) { fprintf(stderr, "decoding for weight %d ... ", weight); for (int i=0; i < SLICES; i++) { ErrorVectorUnique ev(weight, 32, slice[i].byte); while (!ev.Done()) { Slice code = slice[i]; ev.Apply(code.byte); SliceExpand(code,i); if (!InvalidDecay(slice[i].qword, code.qword)) decodings[i].push_back(code); ev.Next(); } } fprintf(stderr, "%lu new slices ... ", decodings[0].size() + decodings[1].size() + decodings[2].size() + decodings[3].size()); } // Slices a key schedule into 4 groups of 7 bytes, each of which is // uniquely defined by its first 4 bytes void SliceSched(Sched &sched, Slice slices[4]) { for (int w=0; w < SLICE_SIZE; w++) { slices[0].byte[w] = sched.word[w].byte[0]; slices[1].byte[w] = sched.word[w].byte[1]; slices[2].byte[w] = sched.word[w].byte[2]; slices[3].byte[w] = sched.word[w].byte[3]; } slices[0].byte[3] = sched.word[3].byte[1]; slices[1].byte[3] = sched.word[3].byte[2]; slices[2].byte[3] = sched.word[3].byte[3]; slices[3].byte[3] = sched.word[3].byte[0]; } // Returns a decoded byte from a file of hex values, ignoring whitespace int GetHexByte(FILE *f) { for (;;) { char a[3]; if ((a[0] = fgetc(f)) == EOF) break; if ((a[0] >= '0' && a[0] <= '9') || (a[0] >= 'a' && a[0] <= 'f') || (a[0] >= 'A' && a[0] <= 'F')) { if ((a[1] = fgetc(f)) == EOF) break; a[2] = '\0'; return strtol(a,NULL,16); } } return EOF; } // Reads hex-encoded bytes of a key schedule from filename // into sched (does not return on error) void ReadSched(char *filename, Sched &sched) { FILE *f = fopen(filename, "r"); if (!f) err(1, "key schedule open failed"); for (int i=0; i < SCHED_LEN; i++) { int c = GetHexByte(f); if (c == EOF) { fprintf(stderr, "error reading key schedule\n"); exit(1); } sched.byte[i] = c; } fclose(f); } void Usage() { fprintf(stderr, "usage: aesfix SCHEDULE-FILE\n" "Corrects bit errors in an AES key schedule " "read from the specified hex-encoded file.\n\n"); } int main(int argc, char *argv[]) { if (argc != 2) { Usage(); exit(1); } Sched sched; ReadSched(argv[1], sched); Slice slices[SLICES]; SliceSched(sched, slices); SliceVector oldDecodings[SLICES]; for (int weight=0; weight < 32; weight++) { SliceVector newDecodings[SLICES]; DecodeSlices(slices, weight, newDecodings); TryNewDecodings(sched, oldDecodings, newDecodings); } return 0; } aesfix/aes.h0000644007273400016420000000652111040146470012556 0ustar jhaldermgrad#ifndef __AES_H__ #define __AES_H__ uint8_t sbox[256] = { //0 1 2 3 4 5 6 7 8 9 A B C D E F 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, //0 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, //1 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, //2 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, //3 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, //4 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, //5 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, //6 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, //7 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, //8 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, //9 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, //A 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, //B 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, //C 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, //D 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, //E 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 }; //F uint8_t rcon[255] = { 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb }; #endif//__AES_H__ aesfix/errvect.cpp0000644007273400016420000000276511040146471014022 0ustar jhaldermgrad#include #include "errvect.h" ErrorVector::ErrorVector(int w, int s) : weight(w), size(s) { pos = new int[weight]; for (int i=0; i < weight; i++) pos[i] = i; done = weight > size; } ErrorVector::~ErrorVector() { if (pos) delete [] pos; } bool ErrorVector::Next() { if (done) return false; if (!weight) { done = true; return false; } if (pos[weight-1] != size-1) { pos[weight-1]++; } else { int mobile = -1; for (int i=weight-2; i >= 0; i--) if (pos[i]+1 != pos[i+1]) { mobile = i; break; } if (mobile < 0) { done = true; return false; } pos[mobile]++; for (int i=mobile+1; i < weight; i++) pos[i] = pos[i-1]+1; } return true; } void ErrorVector::Apply(uint8_t *vector) { for (int i=0; i < weight; i++) { int p = pos[i]; vector[p >> 3] |= (1 << (p & 0x7)); } } ErrorVectorUnique::ErrorVectorUnique(int w, int s, uint8_t *v) : ErrorVector(w,s) { zero = new int[s]; int z=0; for (int i=0; i < s; i++) if (IsZero(v,i)) zero[z++] = i; size = z; done = weight > size; } ErrorVectorUnique::~ErrorVectorUnique() { if (zero) delete [] zero; } // Is the initialization vector 0 at bit-position p? bool ErrorVectorUnique::IsZero(uint8_t *v, int p) { return (p < size) && !(v[p >> 3] & (1 << (p & 0x7))); } void ErrorVectorUnique::Apply(uint8_t *vector) { for (int i=0; i < weight; i++) { int p = zero[pos[i]]; vector[p >> 3] |= (1 << (p & 0x7)); } } aesfix/errvect.h0000644007273400016420000000151611040146472013461 0ustar jhaldermgrad// Iterates through vectors of a given size and Hamming weight class ErrorVector { protected: int weight; int size; int *pos; bool done; public: ErrorVector(int w, int s); ~ErrorVector(); // Advances to the next vector bool Next(); // ORs vector with the current iteration void Apply(uint8_t *vector); // Have we iterated through all vectors? bool Done() { return done; } }; // Iterates through vectors of a given size and Hamming weight // with fixed 1s at positions containing 1s in the specified vector // (we use this to iterate through unique vectors that could have // decayed into a particular vector) class ErrorVectorUnique : public ErrorVector { int *zero; bool IsZero(uint8_t *v, int p); public: ErrorVectorUnique(int w, int s, uint8_t *v); ~ErrorVectorUnique(); void Apply(uint8_t *vector); }; aesfix/LICENSE0000644007273400016420000000304211040146472012637 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. aesfix/Makefile0000644007273400016420000000023311040146473013272 0ustar jhaldermgradCXXFLAGS= -Wall -O4 -funroll-loops OBJS= aesfix.o errvect.o all: aesfix aesfix: $(OBJS) $(CXX) -o aesfix $(OBJS) clean: @rm -f aesfix *~ \#* $(OBJS) aesfix/README0000644007273400016420000000314111040146473012513 0ustar jhaldermgradAESFix 1.0.1 (2008-07-18) By Nadia Heninger and J. Alex Halderman This program illustrates a technique for correcting bit errors in an AES key schedule, as described in Section 5.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/ This program is a simplified version of our algorithm. It is limited to AES-128 key schedules, and it can only correct unidirectional 1->0 bit errors. For the most part it has been optimized for readability rather than performance. The algorithm has these major steps: 1. Given a key schedule containing bit errors, divide the schedule into four 7-bit "slices", each of which should be uniquely determined by its first four bits. 2. For increasing number of errors w to the key (round 0) bytes: a. List possible "decoded" values that could have suffered w or fewer unidirectional errors to form the slice. b. Consider all the key schedules generated by combinations of these decodings. If one could have decayed into the key schedule that we're trying to repair, output it and stop. USAGE: aesfix SCHEDULE-FILE Corrects bit errors in an AES key schedule read from the specified hex-encoded file. SAMPLES: The samples/ directory contains example input files. Each is labeled with the number of bit errors from a correct AES-128 key schedule. aesfix/samples/0000755007273400016420000000000011040030733013267 5ustar jhaldermgradaesfix/samples/sched.1000000644007273400016420000000062711040030157014604 0ustar jhaldermgrad91280ACC D22E4559 825C8143 287111E6 33AAF41D C1C420C0 4318B817 2F49A971 88795580 019D644C 4AA5D413 65CC74AA 87E4D1C5 8A589589 C07C01D2 A1102478 83B845F7 05A1D07E C14989AC 60498994 62610425 67CCD549 A61544F5 C6FCE120 7211F091 154D25C2 3340493F C524080E 0A558234 3F08A7BF 08C0CE80 E1F4469A 950F89EC 8A062E53 A487E0D3 55338645 45296A23 E72C4470 41EAA0A3 1ED8004E 1A5C4251 FD300421 BC9B2200 A2438068 aesfix/samples/sched.1200000644007273400016420000000062711040030157014606 0ustar jhaldermgrad1C96875E 325EB74B 18846C19 E130DB91 5A274908 60316E40 F4F6105B 19C643C2 6C5C48DF 80ED921F 741202C4 6DDC4906 ACC703E3 640A917C 121093B0 73CCD03E 8D80A506 C2B23C62 C92A2FD2 AE66756C 8E2CFD62 4D078198 943C6E4A 3A5A0B22 15820872 5A158A8A 0E00A500 7073BC86 102842E0 02398508 CC11202A A0629E2C 52263F84 A00EB884 2406982C 84650000 55D55C93 A4CAE654 98C47879 19A97879 90416A77 15A00C02 0866704A 81CF0820 aesfix/samples/sched.1400000644007273400016420000000062711040030157014610 0ustar jhaldermgrad3A31E268 A95E5916 B01DD2E8 525BC682 02CDE140 A8918816 188E0A5C 48D19C7E 0313026C 28808A22 1306C090 4EDA4CE8 3E3A9041 02B2130B A5B0C395 3A0F8E75 12490440 08F1144B AD06C4D2 96281B83 386008B6 328319FD 8DC4410A 49E81288 C4E0C20D C6439350 71A6004B 20498083 21240C88 814777E1 88E061A2 88ABE971 C1380F4D 047470B4 9C9D1116 0426F067 DB7B8211 DE02BAE1 031B4A73 53AD1190 7806820A 270010EB C49BFB10 8316E880 aesfix/samples/sched.1600000644007273400016420000000062711040030157014612 0ustar jhaldermgradB1C2B25B 053A003B 5EAA0520 55C7C8B1 640A1120 33140118 CDB818E0 98385404 42426825 71066A71 38C8768D 24808388 0E60BC0C 7F1A47D4 C3D42018 63670340 03030029 700D1BF4 9FDABBA0 D8ACB870 B47B5C48 8A500114 31895C10 ED154224 0F250D0C 051718A9 10FE26A1 9D89E0D9 0240CC5C 23138475 036000CC C686C211 22E10E57 C132CA22 D20FF8EE 109928F7 1721080B D61392E1 000C4207 08955078 01320066 1D018B0A 990DF088 C198A170