├── android-projects
├── Virtual_Keycard
│ ├── settings.gradle
│ ├── .directory
│ ├── app
│ │ ├── ic_launcher-web.png
│ │ ├── src
│ │ │ ├── main
│ │ │ │ ├── res
│ │ │ │ │ ├── drawable-hdpi
│ │ │ │ │ │ └── ic_launcher.png
│ │ │ │ │ ├── drawable-mdpi
│ │ │ │ │ │ └── ic_launcher.png
│ │ │ │ │ ├── drawable-xhdpi
│ │ │ │ │ │ └── ic_launcher.png
│ │ │ │ │ ├── drawable-xxhdpi
│ │ │ │ │ │ └── ic_launcher.png
│ │ │ │ │ ├── values
│ │ │ │ │ │ ├── dimens.xml
│ │ │ │ │ │ ├── styles.xml
│ │ │ │ │ │ └── strings.xml
│ │ │ │ │ ├── values-v11
│ │ │ │ │ │ └── styles.xml
│ │ │ │ │ ├── xml
│ │ │ │ │ │ └── apduservice.xml
│ │ │ │ │ ├── menu
│ │ │ │ │ │ ├── ask_for_ok.xml
│ │ │ │ │ │ ├── main.xml
│ │ │ │ │ │ ├── create_pin_persistent.xml
│ │ │ │ │ │ └── last_login_try_with_gui.xml
│ │ │ │ │ ├── values-w820dp
│ │ │ │ │ │ └── dimens.xml
│ │ │ │ │ ├── values-v14
│ │ │ │ │ │ └── styles.xml
│ │ │ │ │ └── layout
│ │ │ │ │ │ ├── activity_last_login_try_with_gui.xml
│ │ │ │ │ │ ├── activity_main.xml
│ │ │ │ │ │ └── activity_create_pin_persistent.xml
│ │ │ │ ├── AndroidManifest.xml
│ │ │ │ └── java
│ │ │ │ │ └── de
│ │ │ │ │ └── nellessen
│ │ │ │ │ └── virtual_keycard
│ │ │ │ │ ├── LastLoginTryWithGUIActivity.java
│ │ │ │ │ ├── MainActivity.java
│ │ │ │ │ └── CreatePinPersistent.java
│ │ │ └── test
│ │ │ │ └── java
│ │ │ │ └── de
│ │ │ │ └── nellessen
│ │ │ │ └── virtual_keycard
│ │ │ │ └── MainActivityTest.java
│ │ └── build.gradle
│ ├── gradle
│ │ └── wrapper
│ │ │ ├── gradle-wrapper.jar
│ │ │ └── gradle-wrapper.properties
│ ├── .classpath
│ ├── build.gradle
│ ├── .project
│ ├── gradlew.bat
│ └── gradlew
├── Muscle_Card_on_Android
│ ├── settings.gradle
│ ├── .directory
│ ├── gradle
│ │ └── wrapper
│ │ │ ├── gradle-wrapper.jar
│ │ │ └── gradle-wrapper.properties
│ ├── app
│ │ ├── src
│ │ │ ├── main
│ │ │ │ ├── res
│ │ │ │ │ ├── drawable-hdpi
│ │ │ │ │ │ └── ic_launcher.png
│ │ │ │ │ ├── drawable-mdpi
│ │ │ │ │ │ └── ic_launcher.png
│ │ │ │ │ ├── drawable-xhdpi
│ │ │ │ │ │ └── ic_launcher.png
│ │ │ │ │ ├── values
│ │ │ │ │ │ ├── dimens.xml
│ │ │ │ │ │ ├── strings.xml
│ │ │ │ │ │ └── styles.xml
│ │ │ │ │ ├── values-v11
│ │ │ │ │ │ └── styles.xml
│ │ │ │ │ ├── xml
│ │ │ │ │ │ └── apduservice.xml
│ │ │ │ │ ├── menu
│ │ │ │ │ │ └── ask_for_ok.xml
│ │ │ │ │ ├── values-w820dp
│ │ │ │ │ │ └── dimens.xml
│ │ │ │ │ └── values-v14
│ │ │ │ │ │ └── styles.xml
│ │ │ │ ├── java
│ │ │ │ │ ├── de
│ │ │ │ │ │ └── nellessen
│ │ │ │ │ │ │ ├── muscle_card_on_android
│ │ │ │ │ │ │ ├── AskForOk.java
│ │ │ │ │ │ │ ├── LastLoginTryWithGUI.java
│ │ │ │ │ │ │ └── processCommandApduWrapper.java
│ │ │ │ │ │ │ └── pace_on_android
│ │ │ │ │ │ │ └── Pace.java
│ │ │ │ │ ├── javax
│ │ │ │ │ │ └── smartcardio
│ │ │ │ │ │ │ ├── ResponseAPDU.java
│ │ │ │ │ │ │ └── CommandAPDU.java
│ │ │ │ │ └── com
│ │ │ │ │ │ └── musclecard
│ │ │ │ │ │ └── CardEdge
│ │ │ │ │ │ ├── ObjectManager.src
│ │ │ │ │ │ ├── MemoryManager.src
│ │ │ │ │ │ ├── MemoryManager.java
│ │ │ │ │ │ └── ObjectManager.java
│ │ │ │ └── AndroidManifest.xml
│ │ │ └── test
│ │ │ │ └── java
│ │ │ │ └── de
│ │ │ │ └── nellessen
│ │ │ │ └── muscle_card_on_android
│ │ │ │ └── MSCHostApduServiceTest.java
│ │ └── build.gradle
│ ├── .classpath
│ ├── build.gradle
│ ├── .project
│ ├── gradlew.bat
│ └── gradlew
├── .directory
└── jacoco.gradle
├── overview.dia
├── overview.png
├── .gitmodules
├── .gitignore
├── opensc-files
├── opensc.conf.patch
├── virtualkeycard.profile
└── pkcs15-virtualkeycard.c
├── README.md
├── Makefile
└── .gitlab-ci.yml
/android-projects/Virtual_Keycard/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------
/android-projects/Muscle_Card_on_Android/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------
/android-projects/.directory:
--------------------------------------------------------------------------------
1 | [Dolphin]
2 | Timestamp=2015,4,15,19,29,45
3 | Version=3
4 |
--------------------------------------------------------------------------------
/overview.dia:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eriknellessen/Virtual-Keycard/HEAD/overview.dia
--------------------------------------------------------------------------------
/overview.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eriknellessen/Virtual-Keycard/HEAD/overview.png
--------------------------------------------------------------------------------
/android-projects/Muscle_Card_on_Android/.directory:
--------------------------------------------------------------------------------
1 | [Dolphin]
2 | Timestamp=2015,4,15,19,51,53
3 | Version=3
4 |
--------------------------------------------------------------------------------
/android-projects/Virtual_Keycard/.directory:
--------------------------------------------------------------------------------
1 | [Dolphin]
2 | Timestamp=2015,4,15,19,28,50
3 | Version=3
4 |
5 | [Settings]
6 | HiddenFilesShown=true
7 |
--------------------------------------------------------------------------------
/android-projects/Virtual_Keycard/app/ic_launcher-web.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eriknellessen/Virtual-Keycard/HEAD/android-projects/Virtual_Keycard/app/ic_launcher-web.png
--------------------------------------------------------------------------------
/android-projects/Virtual_Keycard/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eriknellessen/Virtual-Keycard/HEAD/android-projects/Virtual_Keycard/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/android-projects/Muscle_Card_on_Android/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eriknellessen/Virtual-Keycard/HEAD/android-projects/Muscle_Card_on_Android/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/android-projects/Virtual_Keycard/app/src/main/res/drawable-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eriknellessen/Virtual-Keycard/HEAD/android-projects/Virtual_Keycard/app/src/main/res/drawable-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android-projects/Virtual_Keycard/app/src/main/res/drawable-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eriknellessen/Virtual-Keycard/HEAD/android-projects/Virtual_Keycard/app/src/main/res/drawable-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android-projects/Virtual_Keycard/app/src/main/res/drawable-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eriknellessen/Virtual-Keycard/HEAD/android-projects/Virtual_Keycard/app/src/main/res/drawable-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android-projects/Virtual_Keycard/app/src/main/res/drawable-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eriknellessen/Virtual-Keycard/HEAD/android-projects/Virtual_Keycard/app/src/main/res/drawable-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android-projects/Muscle_Card_on_Android/app/src/main/res/drawable-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eriknellessen/Virtual-Keycard/HEAD/android-projects/Muscle_Card_on_Android/app/src/main/res/drawable-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android-projects/Muscle_Card_on_Android/app/src/main/res/drawable-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eriknellessen/Virtual-Keycard/HEAD/android-projects/Muscle_Card_on_Android/app/src/main/res/drawable-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android-projects/Muscle_Card_on_Android/app/src/main/java/de/nellessen/muscle_card_on_android/AskForOk.java:
--------------------------------------------------------------------------------
1 | package de.nellessen.muscle_card_on_android;
2 |
3 | public interface AskForOk {
4 | public boolean askForOk(String data);
5 | }
6 |
--------------------------------------------------------------------------------
/android-projects/Muscle_Card_on_Android/app/src/main/res/drawable-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eriknellessen/Virtual-Keycard/HEAD/android-projects/Muscle_Card_on_Android/app/src/main/res/drawable-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android-projects/Muscle_Card_on_Android/app/src/main/java/de/nellessen/muscle_card_on_android/LastLoginTryWithGUI.java:
--------------------------------------------------------------------------------
1 | package de.nellessen.muscle_card_on_android;
2 |
3 | public interface LastLoginTryWithGUI {
4 | public void lastLoginTryWithGUI(int loginTriesLeft, int unblockTriesLeft);
5 | }
6 |
--------------------------------------------------------------------------------
/android-projects/Muscle_Card_on_Android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | zipStoreBase=GRADLE_USER_HOME
4 | zipStorePath=wrapper/dists
5 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.0.2-bin.zip
6 |
--------------------------------------------------------------------------------
/android-projects/Virtual_Keycard/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
9 | * 10 | * Objects are linked in a list in the 11 | * dynamic memory. No smart search is done 12 | * at the moment.
13 | * 14 | * Object fields: 15 | *
16 | * short next 17 | * short obj_class 18 | * short obj_id 19 | * short obj_size 20 | * byte[] data 21 | *22 | * 23 | * TODO 24 | * - Could we definitively avoid a map enforcing the ID 25 | * (equal to the memory address, i.e.) - security implications ? 26 | * 27 | */ 28 | 29 | public class ObjectManager { 30 | 31 | public final static byte OBJ_ACL_SIZE = (byte) 6; 32 | 33 | private final static byte OBJ_HEADER_SIZE = (byte) (6 + OBJ_ACL_SIZE + 2); 34 | private final static byte OBJ_H_NEXT = (byte) 0; // Short size; 35 | private final static byte OBJ_H_CLASS = (byte) 2; // Short ocj_class; 36 | private final static byte OBJ_H_ID = (byte) 4; // Short obj_id; 37 | private final static byte OBJ_H_ACL = (byte) 6; // Byte[OBJ_ACL_SIZE] acl; 38 | private final static byte OBJ_H_SIZE = (byte) 12; // Short size; 39 | private final static byte OBJ_H_DATA = (byte) 14; 40 | 41 | /** There have been memory problems on the card */ 42 | public final static short SW_NO_MEMORY_LEFT = (short) 0x9C01; 43 | 44 | /** Size of an Object Record filled by getFirstRecord() 45 | * or getNextRecord(): ID, Size, ACL */ 46 | public final static short RECORD_SIZE = (short) (4 + 4 + OBJ_ACL_SIZE); 47 | 48 | /** Iterator on objects. Stores the offset of the last retrieved object's record. */ 49 | private short it; 50 | 51 | /** The Memory Manager object */ 52 | private MemoryManager mem = null; 53 | 54 | /** Map for fast search of objects (unimplemented) */ 55 | // static Map map; 56 | 57 | /** Head of the objects' list */ 58 | private short obj_list_head = MemoryManager.NULL_OFFSET; 59 | 60 | /** Constructor for the ObjectManager class. 61 | * @param mem_ref The MemoryManager object to be used 62 | * to allocate objects' memory. 63 | */ 64 | public ObjectManager(MemoryManager mem_ref) { 65 | mem = mem_ref; 66 | // map = new Map(); 67 | obj_list_head = MemoryManager.NULL_OFFSET; 68 | } 69 | 70 | /** Creates an object with specified parameters. Throws a SW_NO_MEMORY_LEFT 71 | * exception if cannot allocate the memory. Does not check if object exists. 72 | * @param type Object Type 73 | * @param id Object ID (Type and ID form a generic 4 bytes identifier) 74 | * @param acl_buf Java byte array containing the ACL for the new object 75 | * @param acl_offset Offset at which the ACL starts in acl_buf[] 76 | * @return The memory base address for the object. It can be used 77 | * in successive calls to xxxFromAddress() methods. 78 | */ 79 | public short createObject(short type, short id, short size, 80 | byte[] acl_buf, short acl_offset) { 81 | /* Allocate memory for new object */ 82 | short base = mem.alloc((short) (size + OBJ_HEADER_SIZE)); 83 | if (base == MemoryManager.NULL_OFFSET) 84 | ISOException.throwIt(SW_NO_MEMORY_LEFT); 85 | /* New obj will be inserted in the head of the list */ 86 | mem.setShort(base, OBJ_H_NEXT, obj_list_head); 87 | mem.setShort(base, OBJ_H_CLASS, type); 88 | mem.setShort(base, OBJ_H_ID, id); 89 | mem.setShort(base, OBJ_H_SIZE, size); 90 | mem.setBytes(base, OBJ_H_ACL, acl_buf, acl_offset, OBJ_ACL_SIZE); 91 | obj_list_head = base; 92 | 93 | /* Add to the map */ 94 | // map.addEntry(type, id, base); 95 | 96 | // Return base address 97 | return (short) (base + OBJ_HEADER_SIZE); 98 | } 99 | 100 | /** Creates an object with the maximum available size */ 101 | public short createObjectMax(short type, short id, 102 | byte[] acl_buf, short acl_offset) { 103 | short obj_size = mem.getMaxSize(); 104 | if (obj_size == (short) 0) 105 | ISOException.throwIt(SW_NO_MEMORY_LEFT); 106 | /* The object's real size must take into account that * 107 | * extra bytes are needed for the header */ 108 | return createObject(type, id, (short) (obj_size - OBJ_HEADER_SIZE), 109 | acl_buf, acl_offset); 110 | } 111 | 112 | /** Clamps an object freeing the unused memory 113 | * @param type Object Type 114 | * @param id Object ID (Type and ID form a generic 4 bytes identifier) 115 | * @param new_size The new object size (must be less than current size) 116 | * @return True if clamp was possible, false otherwise 117 | */ 118 | public boolean clampObject(short type, short id, short new_size) { 119 | short base = getEntry(type, id); 120 | if (base == (short) MemoryManager.NULL_OFFSET) 121 | ISOException.throwIt((short) 0x9C07); 122 | // Delegate every check to the Memory Manager 123 | if (mem.realloc(base, (short) (new_size + OBJ_HEADER_SIZE))) { 124 | mem.setShort(base, OBJ_H_SIZE, new_size); 125 | return true; 126 | } 127 | return false; 128 | } 129 | 130 | /** Set the object's ACL. Unused at the moment. */ 131 | private void setACL(short type, short id, byte[] acl_buf, short acl_offset) { 132 | short base = getEntry(type, id); 133 | mem.setBytes(base, OBJ_H_ACL, acl_buf, acl_offset, OBJ_ACL_SIZE); 134 | } 135 | 136 | /** Allow or unallow read on object given the logged identities 137 | * @param base The object base address as returned from getBaseAddress() 138 | * @param logged_ids The current logged in identities as stored in CardEdge.logged_ids 139 | */ 140 | public boolean authorizeReadFromAddress(short base, short logged_ids) { 141 | return authorizeOp(mem.getShort(base, (short) (OBJ_H_ACL - OBJ_HEADER_SIZE)), logged_ids); 142 | } 143 | /** Allow or unallow write on object given the logged identities 144 | * @param base The object base address as returned from getBaseAddress() 145 | * @param logged_ids The current logged in identities as stored in CardEdge.logged_ids 146 | */ 147 | public boolean authorizeWriteFromAddress(short base, short logged_ids) { 148 | return authorizeOp(mem.getShort(base, (short) (OBJ_H_ACL + (short) 2 - OBJ_HEADER_SIZE)), logged_ids); 149 | } 150 | /** Allow or unallow delete on object given the logged identities 151 | * @param base The object base address as returned from getBaseAddress() 152 | * @param logged_ids The current logged in identities as stored in CardEdge.logged_ids 153 | */ 154 | public boolean authorizeDeleteFromAddress(short base, short logged_ids) { 155 | return authorizeOp(mem.getShort(base, (short) (OBJ_H_ACL + (short) 4 - OBJ_HEADER_SIZE)), logged_ids); 156 | } 157 | 158 | /** Check if logged in identities satisfy requirements for an operation 159 | * @param required_ids The required identities as from an ACL short 160 | * @param logged_ids The current logged in identities as stored in CardEdge.logged_ids 161 | */ 162 | private boolean authorizeOp(short required_ids, short logged_ids) { 163 | return ( 164 | (required_ids != (short) 0xFFFF) 165 | && (((short) (required_ids & logged_ids)) == required_ids) 166 | ); 167 | } 168 | 169 | /** Write data at the specified location in an object */ 170 | // public void setObjectData(short type, short id, short dst_offset, 171 | // byte[] src_data, short src_offset, 172 | // short len) { 173 | // // TODO: short dst_base = map.getEntry(type, id); 174 | // short dst_base = getEntry(type, id); 175 | // mem.setBytes(dst_base, dst_offset, src_data, src_offset, len); 176 | // } 177 | 178 | // /** Read data from the specified location in an object */ 179 | // public void getObjectData(byte[] dst_data, short dst_offset, 180 | // short type, short id, short src_offset, 181 | // short len) { 182 | // // TODO: short dst_base = map.getEntry(type, id); 183 | // short src_base = getEntry(type, id); 184 | // mem.getBytes(dst_data, dst_offset, src_base, src_offset, len); 185 | // } 186 | 187 | /** Destroy the specified object 188 | * @param type Object Type 189 | * @param id Object ID (Type and ID form a generic 4 bytes identifier) 190 | * @param secure If true, object memory is zeroed before being released. 191 | */ 192 | public void destroyObject(short type, short id, boolean secure) { 193 | short base = obj_list_head; 194 | short prev = MemoryManager.NULL_OFFSET; 195 | boolean found = false; 196 | while ((! found) && (base != MemoryManager.NULL_OFFSET)) { 197 | if ((mem.getShort(base, OBJ_H_CLASS) == type) 198 | && (mem.getShort(base, OBJ_H_ID) == id)) 199 | found = true; 200 | else { 201 | prev = base; 202 | base = mem.getShort(base, OBJ_H_NEXT); 203 | } 204 | } 205 | if (found) { 206 | // Unlink object from the list 207 | if (prev != MemoryManager.NULL_OFFSET) { 208 | mem.setShort(prev, OBJ_H_NEXT, mem.getShort(base, OBJ_H_NEXT)); 209 | } else { 210 | obj_list_head = mem.getShort(base, OBJ_H_NEXT); 211 | } 212 | // Zero memory if required 213 | if (secure) 214 | Util.arrayFillNonAtomic(mem.getBuffer(), (short) (base + OBJ_HEADER_SIZE), 215 | mem.getShort(base, OBJ_H_SIZE), (byte) 0x00); 216 | 217 | // Free memory 218 | mem.free(base); 219 | } 220 | } 221 | 222 | /** Returns the header base address (offset) for the specified object
223 | * Object header is found at the returned offset, while object 224 | * data starts right after the header
225 | * This performs a linear search, so performance issues could arise 226 | * as the number of objects grows 227 | * If object is not found, then returns NULL_OFFSET 228 | * @param type Object Type 229 | * @param id Object ID (Type and ID form a generic 4 bytes identifier) 230 | * @return The starting offset of the object or NULL_OFFSET if the object 231 | * is not found. 232 | */ 233 | private short getEntry(short type, short id) { 234 | /* This is a stupid linear search. It's fine for a few objects. 235 | * TODO: Use a map for high number of objects */ 236 | short base = obj_list_head; 237 | while (base != MemoryManager.NULL_OFFSET) { 238 | if ((mem.getShort(base, OBJ_H_CLASS) == type) 239 | && (mem.getShort(base, OBJ_H_ID) == id)) 240 | return base; 241 | base = mem.getShort(base, OBJ_H_NEXT); 242 | } 243 | return MemoryManager.NULL_OFFSET; 244 | } 245 | 246 | /** Returns the data base address (offset) for an object.
247 | * The base address can be used for further calls to 248 | * xxxFromAddress() methods
249 | * This function should only be used if performance 250 | * issue arise. setObjectData() and getObjectData() 251 | * should be used, instead. 252 | * @param type Object Type 253 | * @param id Object ID (Type and ID form a generic 4 bytes identifier) 254 | * @return The starting offset of the object. At this location 255 | */ 256 | public short getBaseAddress(short type, short id) { 257 | short base = getEntry(type, id); 258 | if (base == MemoryManager.NULL_OFFSET) 259 | return MemoryManager.NULL_OFFSET; 260 | else 261 | return ((short) (base + OBJ_HEADER_SIZE)); 262 | } 263 | 264 | /** Checks if an object exists 265 | * @param type The object type 266 | * @param id The object ID 267 | * @return true if object exists 268 | */ 269 | public boolean exists(short type, short id) { 270 | short base = getEntry(type, id); 271 | return (base != MemoryManager.NULL_OFFSET); 272 | } 273 | 274 | /** Returns object size from the base address */ 275 | public short getSizeFromAddress(short base) { 276 | return mem.getShort((short) (base - OBJ_HEADER_SIZE + OBJ_H_SIZE)); 277 | } 278 | 279 | /** Resets the objects iterator and retrieves the information 280 | * record of the first object, if any.
281 | * @param buffer The byte array into which the record will be copied 282 | * @param offset The offset in buffer[] at which the record will be copied 283 | * @return True if an object was found. False if there are no objects. 284 | * 285 | * @see #getNextRecord 286 | */ 287 | public boolean getFirstRecord(byte[] buffer, short offset) { 288 | it = obj_list_head; 289 | return getNextRecord(buffer, offset); 290 | } 291 | 292 | /** Retrieves the information record of the next object, if any.
293 | * @param buffer The byte array into which the record will be copied 294 | * @param offset The offset in buffer[] at which the record will be copied 295 | * @return True if an object was found. False if there are no more 296 | * objects to inspect. 297 | * @see #getFirstRecord 298 | */ 299 | public boolean getNextRecord(byte[] buffer, short offset) { 300 | if (it == MemoryManager.NULL_OFFSET) 301 | return false; 302 | // Setting Object Class 303 | Util.setShort(buffer, offset, mem.getShort(it, OBJ_H_CLASS)); 304 | // Setting Object ID 305 | Util.setShort(buffer, (short) (offset + 2), mem.getShort(it, OBJ_H_ID)); 306 | // Setting Size's M.S.Short to zero. 307 | Util.setShort(buffer, (short) (offset + 4), (short) 0); 308 | // Setting Size's L.S.Short 309 | Util.setShort(buffer, (short) (offset + 6), mem.getShort(it, (short) OBJ_H_SIZE)); 310 | // Setting ACL 311 | Util.arrayCopyNonAtomic(mem.getBuffer(), (short) (it + OBJ_H_ACL), 312 | buffer, (short) (offset + 8), OBJ_ACL_SIZE); 313 | // Advance iterator 314 | it = mem.getShort(it, OBJ_H_NEXT); 315 | return true; 316 | } 317 | 318 | /** 319 | * Compare an object's ACL with the provided ACL. 320 | * @param base The object base address, as returned from getBaseAddress() 321 | * @param acl The buffer containing the ACL 322 | * @return True if the ACLs are equal 323 | */ 324 | public boolean compareACLFromAddress(short base, byte[] acl) { 325 | return (Util.arrayCompare(mem.getBuffer(), (short) (base - OBJ_HEADER_SIZE + OBJ_H_ACL), 326 | acl, (short) 0, OBJ_ACL_SIZE) == (byte) 0); 327 | } 328 | 329 | } // class MemoryManager 330 | -------------------------------------------------------------------------------- /android-projects/Muscle_Card_on_Android/app/src/main/java/com/musclecard/CardEdge/MemoryManager.src: -------------------------------------------------------------------------------- 1 | package JAVA_PACKAGE; 2 | 3 | import javacard.framework.Util; 4 | 5 | /** Memory Manager class.
6 | * 7 | * An instance of this class is capable of handling 8 | * allocation and deallocation of chunks in a large 9 | * Java byte array that is allocated once during the 10 | * object instantiation.
11 | * The Memory Manager allocates or frees memory chunks 12 | * in the preallocated byte array on demand.
13 | * 14 | * No defragmentation is done, actually.
15 | * Consecutive freed memory chunks are recompacted.
16 | * 17 | * Every allocation takes 2 more bytes to 18 | * store the allocated block size, just 19 | * before the allocated offset.
20 | * 21 | * A free memory block starts with 22 | * a node (NODE_SIZE bytes): 23 | *
24 | * short size; 25 | * short next; 26 | *27 | */ 28 | 29 | public class MemoryManager { 30 | /** Special offset value used as invalid offset */ 31 | public final static short NULL_OFFSET = (short) 0xFFFF; // Also used as End Of List 32 | private final static byte NODE_SIZE = (byte) 4; 33 | 34 | // All the available memory as a byte array 35 | private byte ptr[] = null; 36 | // Free memory list 37 | private short free_head = NULL_OFFSET; 38 | 39 | /** Constructor for the MemoryManager class 40 | * @param mem_size Size of the memory are to be allocated 41 | */ 42 | public MemoryManager(short mem_size) { 43 | Init(mem_size); 44 | } 45 | 46 | private void Init(short mem_size) { 47 | if (ptr != null) 48 | return; 49 | // Allocate the memory 50 | ptr = new byte[mem_size]; 51 | // Setup the free memory list 52 | // set the size 53 | Util.setShort(ptr, (short) 0, (short) mem_size); 54 | // set the pointer to EndOfList 55 | Util.setShort(ptr, (short) 2, (short) NULL_OFFSET); 56 | // set the pointer to the head node 57 | free_head = (short) 0; 58 | } 59 | 60 | /** Allocate memory
61 | * Each allocation takes actually a 2 bytes overhead. 62 | * @param size Size of the memory block 63 | * @return The offset at which allocated memory starts 64 | * or NULL_OFFSET if an error occurred. 65 | * @see #free 66 | * @see #freemem 67 | */ 68 | public short alloc(short size) { 69 | short offset = free_head; 70 | short prev = NULL_OFFSET; 71 | size = (short) (size + 2); // We need a 2 bytes more for block size 72 | // Forbid allocation of single bytes: when freeing, 73 | // they could remain isolated and a free node would not fit ! 74 | if (size < NODE_SIZE) 75 | size = NODE_SIZE; 76 | 77 | // Search the free mem list for a suitable location 78 | // (no special memory management policies, at the moment) 79 | while (offset != NULL_OFFSET) { 80 | // System.out.println(offset); 81 | short free_size = Util.getShort(ptr, offset); 82 | short next_offset = Util.getShort(ptr, (short) (offset + 2)); 83 | // System.out.println(free_size); 84 | // System.out.println(next_offset); 85 | if (free_size >= size) { 86 | // We've got it 87 | short remain = (short) (free_size - size); 88 | if (remain >= NODE_SIZE) { 89 | /* There's enough space for a new free mem node; * 90 | * - just clamp this node (it won't move) * 91 | * - previous node doesn't change at all */ 92 | Util.setShort(ptr, offset, remain); 93 | } else { 94 | /* Not enough space for a new free mem node; * 95 | * - just allocate all the node's space * 96 | * - previous node must skip to the next one */ 97 | size = free_size; 98 | remain = (short) 0; 99 | if (prev == NULL_OFFSET) { 100 | // No previous: it was the 1st 101 | free_head = next_offset; 102 | } else { 103 | // Previous: set it's next offset field 104 | Util.setShort(ptr, (short) (prev + 2), next_offset); 105 | } 106 | } 107 | /* Write the memory block size and skip it * 108 | * while returning allocated offset (from * 109 | * the tail of the free space) */ 110 | Util.setShort(ptr, (short) (offset + remain), size); 111 | return (short) (offset + remain + 2); 112 | } else { 113 | // Go to next list node 114 | prev = offset; 115 | offset = next_offset; 116 | } 117 | } 118 | /* No memory found ! */ 119 | return NULL_OFFSET; 120 | } 121 | 122 | /** Gets the size of the greatest chunk of available memory 123 | * @return The size of the greatest free memory chunk, 124 | * or zero if there is no free mem left 125 | */ 126 | public short getMaxSize() { 127 | short max_size = 2; 128 | short base = free_head; 129 | while (base != NULL_OFFSET) { 130 | short size = Util.getShort(ptr, base); 131 | if (size > max_size) 132 | max_size = size; 133 | base = Util.getShort(ptr, (short) (base + 2)); 134 | } 135 | return (short) (max_size - 2); 136 | } 137 | 138 | /** Free a memory block
139 | * Consecutive free blocks are recompacted. Recompaction happens 140 | * on free(). 4 cases are considered: don't recompact, recompact 141 | * with next only, with previous only and with both of them. 142 | * @param offset The offset at which the memory block starts; 143 | * it was returned from a previous call to 144 | * {@link #alloc} 145 | * @see #alloc 146 | * @see #freemem 147 | */ 148 | public void free(short offset) { 149 | offset -= 2; 150 | short size = Util.getShort(ptr, offset); 151 | 152 | /* Search for the right insertion point */ 153 | short prev = NULL_OFFSET; 154 | short base = free_head; 155 | boolean found = false; 156 | short node_next = (short) 0; // Compiler warning... 157 | while (base != NULL_OFFSET) { 158 | node_next = Util.getShort(ptr, (short) (base + 2)); 159 | if (offset < base) { 160 | found = true; 161 | break; 162 | } 163 | prev = base; 164 | base = node_next; 165 | } 166 | 167 | /* Check if can recompact with next */ 168 | 169 | if (found && ((short) (offset + size) == base)) { 170 | /* Recompact with next: extract next from list * 171 | * so we handle a single case, after compacting * 172 | * next with new node to be inserted */ 173 | size += Util.getShort(ptr, base); 174 | /* We have to rewrite down the right size, in case it 175 | * becomes a new node */ 176 | Util.setShort(ptr, offset, size); 177 | if (prev != NULL_OFFSET) 178 | Util.setShort(ptr, (short) (prev + 2), node_next); 179 | else 180 | free_head = node_next; 181 | base = node_next; 182 | } 183 | 184 | /* Check if can recompact with previous */ 185 | if (prev != NULL_OFFSET) { 186 | short prev_size = Util.getShort(ptr, prev); 187 | if ((short) (prev + prev_size) == offset) { 188 | /* Recompact with previous and don't insert a new node */ 189 | Util.setShort(ptr, prev, (short) (prev_size + size)); 190 | } else { 191 | /* Couldn't recompact: insert node after previous */ 192 | // Write node next pointer only (size is already in place) 193 | Util.setShort(ptr, (short) (offset + 2), base); 194 | Util.setShort(ptr, (short) (prev + 2), offset); 195 | } 196 | } else { 197 | /* Couldn't recompact with prev; head-insert new node */ 198 | // Write node next pointer only (size is already in place) 199 | Util.setShort(ptr, (short) (offset + 2), base); 200 | free_head = offset; 201 | } 202 | } 203 | 204 | /** Get the size of a memory block 205 | * @param offset The offset at which the memory block starts 206 | */ 207 | public short getBlockSize(short offset) { 208 | return (short) (Util.getShort(ptr, (short) (offset - 2)) - 2); 209 | } 210 | 211 | /** Get available free memory 212 | * @return The total amount of available free memory, 213 | * equal to the sum of all free fragments' sizes. 214 | * @see free 215 | * @see alloc 216 | */ 217 | public short freemem() { 218 | short offset = free_head; 219 | short total = (short) 0; 220 | // Scan free mem list 221 | while (offset != NULL_OFFSET) { 222 | // Return free memory in case that every single free block 223 | // is entirely allocated at once (best case) 224 | // (every allocation keeps 2 bytes for block size) 225 | total = (short) (total + Util.getShort(ptr, offset) - 2); 226 | offset = Util.getShort(ptr, (short) (offset + 2)); 227 | } 228 | return total; 229 | } 230 | 231 | /** Resize (only clamping is supported) a previously allocated memory chunk
232 | * @param offset Memory offset as returned by alloc()
233 | * @param size New size of the memory block
234 | * @return True if it was possible to realloc(), False otherwise
235 | * @see #alloc
236 | * @see #free
237 | * @see #freemem
238 | */
239 | public boolean realloc(short offset, short new_size) {
240 | short actual_size = Util.getShort(ptr, (short) (offset - 2));
241 | new_size += (short) 2;
242 | if ((new_size < (short) (1 + 2)) || ((short) (actual_size - new_size) < NODE_SIZE))
243 | // Cannot free any memory (really here there are issues...)
244 | return false;
245 | // Clamp this node
246 | Util.setShort(ptr, (short) (offset - 2), new_size);
247 | // Create a fake allocated node
248 | Util.setShort(ptr, (short) (offset + new_size - 2), (short) (actual_size - new_size));
249 | // Deallocate the freed memory
250 | free((short) (offset + new_size));
251 | return true;
252 | }
253 |
254 | /** Set a byte value into memory
255 | * @param base The base memory location (offset) of the byte to set
256 | * @param offset The offset of the byte (is added to the base parameter)
257 | * @param b The new byte value
258 | */
259 | public void setByte(short base, short offset, byte b) {
260 | ptr[(short) (base + offset)] = b;
261 | }
262 | /** Set a byte value into memory
263 | * @param base The complete memory location (offset) of the byte to set
264 | * @param b The new byte value
265 | */
266 | public void setByte(short base, byte b) {
267 | ptr[base] = b;
268 | }
269 | /** Read a byte value from memory
270 | * @param base The base memory location (offset) of the byte to read
271 | * @param offset The offset of the byte (is added to the base parameter)
272 | * @return The byte value
273 | */
274 | public byte getByte(short base, short offset) {
275 | return ptr[(short) (base + offset)];
276 | }
277 | /** Read a byte value from memory
278 | * @param base The complete memory location (offset) of the byte to read
279 | * @return The byte value
280 | */
281 | public byte getByte(short base) {
282 | return ptr[base];
283 | }
284 |
285 | /** Set a short value into memory
286 | * @param base The base memory location (offset) of the short to set
287 | * @param offset The offset of the short (is added to the base parameter)
288 | * @param b The short value
289 | */
290 | public void setShort(short base, short offset, short b) {
291 | Util.setShort(ptr, (short) (base + offset), b);
292 | }
293 |
294 | /** Set a short value into memory
295 | * @param base The complete memory location (offset) of the short to set
296 | * @param b The short value
297 | */
298 | public void setShort(short base, short b) {
299 | Util.setShort(ptr, base, b);
300 | }
301 |
302 | /** Read a short value from memory
303 | * @param base The base memory location (offset) of the short to read
304 | * @param offset The offset of the short (is added to the base parameter)
305 | * @return The short value
306 | */
307 | public short getShort(short base, short offset) {
308 | return Util.getShort(ptr, (short) (base + offset));
309 | }
310 |
311 | /** Read a short value from memory
312 | * @param base The base memory location (offset) of the short to read
313 | * @return The short value
314 | */
315 | public short getShort(short base) {
316 | return Util.getShort(ptr, base);
317 | }
318 |
319 | /** Copy a byte sequence into memory
320 | * @param dst_base The base memory location (offset) of the destination byte sequence
321 | * @param dst_offset The offset of the destination byte sequence
322 | * (is added to the dst_base parameter)
323 | * @param src_bytes The source byte array
324 | * @param src_offset The offset at which the source sequence starts in src_bytes[]
325 | * @param size The number of bytes to be copied
326 | */
327 | public void setBytes(short dst_base, short dst_offset,
328 | byte[] src_bytes, short src_offset,
329 | short size) {
330 | Util.arrayCopy(src_bytes, src_offset,
331 | ptr, (short) (dst_base + dst_offset),
332 | size);
333 | }
334 |
335 | /** Copy a byte sequence from memory
336 | * @param dst_bytes The destination byte array
337 | * @param dst_offset The offset at which the sequence will be copied in dst_bytes[]
338 | * @param src_base The base memory location (offset) of the source byte sequence
339 | * @param src_offset The offset of the source byte sequence
340 | * (is added to the src_base parameter)
341 | * @param size The number of bytes to be copied
342 | */
343 | public void getBytes(byte[] dst_bytes, short dst_offset,
344 | short src_base, short src_offset,
345 | short size) {
346 | Util.arrayCopy(ptr, (short) (src_base + src_offset),
347 | dst_bytes, dst_offset,
348 | size);
349 | }
350 |
351 | /** Retrieve the Java byte array containing all the memory contents.
352 | * To optimize, we don't use external buffers, *
353 | * but we directly copy from the memory array *
354 | * Use this function only if really required. *
355 | * @return The Java byte array containing all memory contents
356 | */
357 | public byte[] getBuffer() {
358 | return ptr;
359 | }
360 |
361 | #ifdef DEBUG_FROM_JAVA
362 | public void dumpMemory() {
363 | System.out.print("Head=");
364 | System.out.print(free_head);
365 | System.out.print(", Free=");
366 | System.out.print(freemem());
367 | System.out.print(", MaxSize=");
368 | System.out.println(getMaxSize());
369 | for (short i = 0; i < 200; i++) {
370 | System.out.print(Util.makeShort((byte)0, ptr[i]));
371 | System.out.print(" ");
372 | }
373 | System.out.print("\n");
374 | }
375 | #endif
376 |
377 | } // class MemoryManager
378 |
--------------------------------------------------------------------------------
/android-projects/Muscle_Card_on_Android/app/src/main/java/com/musclecard/CardEdge/MemoryManager.java:
--------------------------------------------------------------------------------
1 | /* Copyright (C) 1991-2013 Free Software Foundation, Inc.
2 | This file is part of the GNU C Library.
3 |
4 | The GNU C Library is free software; you can redistribute it and/or
5 | modify it under the terms of the GNU Lesser General Public
6 | License as published by the Free Software Foundation; either
7 | version 2.1 of the License, or (at your option) any later version.
8 |
9 | The GNU C Library is distributed in the hope that it will be useful,
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 | Lesser General Public License for more details.
13 |
14 | You should have received a copy of the GNU Lesser General Public
15 | License along with the GNU C Library; if not, see
16 |
36 | *
37 | * An instance of this class is capable of handling
38 | * allocation and deallocation of chunks in a large
39 | * Java byte array that is allocated once during the
40 | * object instantiation.
41 | * The Memory Manager allocates or frees memory chunks
42 | * in the preallocated byte array on demand.
43 | *
44 | * No defragmentation is done, actually.
45 | * Consecutive freed memory chunks are recompacted.
46 | *
47 | * Every allocation takes 2 more bytes to
48 | * store the allocated block size, just
49 | * before the allocated offset.
50 | *
51 | * A free memory block starts with
52 | * a node (NODE_SIZE bytes):
53 | *
86 | * Each allocation takes actually a 2 bytes overhead.
87 | * @param size Size of the memory block
88 | * @return The offset at which allocated memory starts
89 | * or NULL_OFFSET if an error occurred.
90 | * @see #free
91 | * @see #freemem
92 | */
93 | public short alloc(short size) {
94 | short offset = free_head;
95 | short prev = NULL_OFFSET;
96 | size = (short) (size + 2); // We need a 2 bytes more for block size
97 | // Forbid allocation of single bytes: when freeing,
98 | // they could remain isolated and a free node would not fit !
99 | if (size < NODE_SIZE)
100 | size = NODE_SIZE;
101 | // Search the free mem list for a suitable location
102 | // (no special memory management policies, at the moment)
103 | while (offset != NULL_OFFSET) {
104 | // System.out.println(offset);
105 | short free_size = Util.getShort(ptr, offset);
106 | short next_offset = Util.getShort(ptr, (short) (offset + 2));
107 | // System.out.println(free_size);
108 | // System.out.println(next_offset);
109 | if (free_size >= size) {
110 | // We've got it
111 | short remain = (short) (free_size - size);
112 | if (remain >= NODE_SIZE) {
113 | /* There's enough space for a new free mem node; *
114 | * - just clamp this node (it won't move) *
115 | * - previous node doesn't change at all */
116 | Util.setShort(ptr, offset, remain);
117 | } else {
118 | /* Not enough space for a new free mem node; *
119 | * - just allocate all the node's space *
120 | * - previous node must skip to the next one */
121 | size = free_size;
122 | remain = (short) 0;
123 | if (prev == NULL_OFFSET) {
124 | // No previous: it was the 1st
125 | free_head = next_offset;
126 | } else {
127 | // Previous: set it's next offset field
128 | Util.setShort(ptr, (short) (prev + 2), next_offset);
129 | }
130 | }
131 | /* Write the memory block size and skip it *
132 | * while returning allocated offset (from *
133 | * the tail of the free space) */
134 | Util.setShort(ptr, (short) (offset + remain), size);
135 | return (short) (offset + remain + 2);
136 | } else {
137 | // Go to next list node
138 | prev = offset;
139 | offset = next_offset;
140 | }
141 | }
142 | /* No memory found ! */
143 | return NULL_OFFSET;
144 | }
145 | /** Gets the size of the greatest chunk of available memory
146 | * @return The size of the greatest free memory chunk,
147 | * or zero if there is no free mem left
148 | */
149 | public short getMaxSize() {
150 | short max_size = 2;
151 | short base = free_head;
152 | while (base != NULL_OFFSET) {
153 | short size = Util.getShort(ptr, base);
154 | if (size > max_size)
155 | max_size = size;
156 | base = Util.getShort(ptr, (short) (base + 2));
157 | }
158 | return (short) (max_size - 2);
159 | }
160 | /** Free a memory block
161 | * Consecutive free blocks are recompacted. Recompaction happens
162 | * on free(). 4 cases are considered: don't recompact, recompact
163 | * with next only, with previous only and with both of them.
164 | * @param offset The offset at which the memory block starts;
165 | * it was returned from a previous call to
166 | * {@link #alloc}
167 | * @see #alloc
168 | * @see #freemem
169 | */
170 | public void free(short offset) {
171 | offset -= 2;
172 | short size = Util.getShort(ptr, offset);
173 | /* Search for the right insertion point */
174 | short prev = NULL_OFFSET;
175 | short base = free_head;
176 | boolean found = false;
177 | short node_next = (short) 0; // Compiler warning...
178 | while (base != NULL_OFFSET) {
179 | node_next = Util.getShort(ptr, (short) (base + 2));
180 | if (offset < base) {
181 | found = true;
182 | break;
183 | }
184 | prev = base;
185 | base = node_next;
186 | }
187 | /* Check if can recompact with next */
188 | if (found && ((short) (offset + size) == base)) {
189 | /* Recompact with next: extract next from list *
190 | * so we handle a single case, after compacting *
191 | * next with new node to be inserted */
192 | size += Util.getShort(ptr, base);
193 | /* We have to rewrite down the right size, in case it
194 | * becomes a new node */
195 | Util.setShort(ptr, offset, size);
196 | if (prev != NULL_OFFSET)
197 | Util.setShort(ptr, (short) (prev + 2), node_next);
198 | else
199 | free_head = node_next;
200 | base = node_next;
201 | }
202 | /* Check if can recompact with previous */
203 | if (prev != NULL_OFFSET) {
204 | short prev_size = Util.getShort(ptr, prev);
205 | if ((short) (prev + prev_size) == offset) {
206 | /* Recompact with previous and don't insert a new node */
207 | Util.setShort(ptr, prev, (short) (prev_size + size));
208 | } else {
209 | /* Couldn't recompact: insert node after previous */
210 | // Write node next pointer only (size is already in place)
211 | Util.setShort(ptr, (short) (offset + 2), base);
212 | Util.setShort(ptr, (short) (prev + 2), offset);
213 | }
214 | } else {
215 | /* Couldn't recompact with prev; head-insert new node */
216 | // Write node next pointer only (size is already in place)
217 | Util.setShort(ptr, (short) (offset + 2), base);
218 | free_head = offset;
219 | }
220 | }
221 | /** Get the size of a memory block
222 | * @param offset The offset at which the memory block starts
223 | */
224 | public short getBlockSize(short offset) {
225 | return (short) (Util.getShort(ptr, (short) (offset - 2)) - 2);
226 | }
227 | /** Get available free memory
228 | * @return The total amount of available free memory,
229 | * equal to the sum of all free fragments' sizes.
230 | * @see free
231 | * @see alloc
232 | */
233 | public short freemem() {
234 | short offset = free_head;
235 | short total = (short) 0;
236 | // Scan free mem list
237 | while (offset != NULL_OFFSET) {
238 | // Return free memory in case that every single free block
239 | // is entirely allocated at once (best case)
240 | // (every allocation keeps 2 bytes for block size)
241 | total = (short) (total + Util.getShort(ptr, offset) - 2);
242 | offset = Util.getShort(ptr, (short) (offset + 2));
243 | }
244 | return total;
245 | }
246 | /** Resize (only clamping is supported) a previously allocated memory chunk
247 | * @param offset Memory offset as returned by alloc()
248 | * @param size New size of the memory block
249 | * @return True if it was possible to realloc(), False otherwise
250 | * @see #alloc
251 | * @see #free
252 | * @see #freemem
253 | */
254 | public boolean realloc(short offset, short new_size) {
255 | short actual_size = Util.getShort(ptr, (short) (offset - 2));
256 | new_size += (short) 2;
257 | if ((new_size < (short) (1 + 2)) || ((short) (actual_size - new_size) < NODE_SIZE))
258 | // Cannot free any memory (really here there are issues...)
259 | return false;
260 | // Clamp this node
261 | Util.setShort(ptr, (short) (offset - 2), new_size);
262 | // Create a fake allocated node
263 | Util.setShort(ptr, (short) (offset + new_size - 2), (short) (actual_size - new_size));
264 | // Deallocate the freed memory
265 | free((short) (offset + new_size));
266 | return true;
267 | }
268 | /** Set a byte value into memory
269 | * @param base The base memory location (offset) of the byte to set
270 | * @param offset The offset of the byte (is added to the base parameter)
271 | * @param b The new byte value
272 | */
273 | public void setByte(short base, short offset, byte b) {
274 | ptr[(short) (base + offset)] = b;
275 | }
276 | /** Set a byte value into memory
277 | * @param base The complete memory location (offset) of the byte to set
278 | * @param b The new byte value
279 | */
280 | public void setByte(short base, byte b) {
281 | ptr[base] = b;
282 | }
283 | /** Read a byte value from memory
284 | * @param base The base memory location (offset) of the byte to read
285 | * @param offset The offset of the byte (is added to the base parameter)
286 | * @return The byte value
287 | */
288 | public byte getByte(short base, short offset) {
289 | return ptr[(short) (base + offset)];
290 | }
291 | /** Read a byte value from memory
292 | * @param base The complete memory location (offset) of the byte to read
293 | * @return The byte value
294 | */
295 | public byte getByte(short base) {
296 | return ptr[base];
297 | }
298 | /** Set a short value into memory
299 | * @param base The base memory location (offset) of the short to set
300 | * @param offset The offset of the short (is added to the base parameter)
301 | * @param b The short value
302 | */
303 | public void setShort(short base, short offset, short b) {
304 | Util.setShort(ptr, (short) (base + offset), b);
305 | }
306 | /** Set a short value into memory
307 | * @param base The complete memory location (offset) of the short to set
308 | * @param b The short value
309 | */
310 | public void setShort(short base, short b) {
311 | Util.setShort(ptr, base, b);
312 | }
313 | /** Read a short value from memory
314 | * @param base The base memory location (offset) of the short to read
315 | * @param offset The offset of the short (is added to the base parameter)
316 | * @return The short value
317 | */
318 | public short getShort(short base, short offset) {
319 | return Util.getShort(ptr, (short) (base + offset));
320 | }
321 | /** Read a short value from memory
322 | * @param base The base memory location (offset) of the short to read
323 | * @return The short value
324 | */
325 | public short getShort(short base) {
326 | return Util.getShort(ptr, base);
327 | }
328 | /** Copy a byte sequence into memory
329 | * @param dst_base The base memory location (offset) of the destination byte sequence
330 | * @param dst_offset The offset of the destination byte sequence
331 | * (is added to the dst_base parameter)
332 | * @param src_bytes The source byte array
333 | * @param src_offset The offset at which the source sequence starts in src_bytes[]
334 | * @param size The number of bytes to be copied
335 | */
336 | public void setBytes(short dst_base, short dst_offset,
337 | byte[] src_bytes, short src_offset,
338 | short size) {
339 | Util.arrayCopy(src_bytes, src_offset,
340 | ptr, (short) (dst_base + dst_offset),
341 | size);
342 | }
343 | /** Copy a byte sequence from memory
344 | * @param dst_bytes The destination byte array
345 | * @param dst_offset The offset at which the sequence will be copied in dst_bytes[]
346 | * @param src_base The base memory location (offset) of the source byte sequence
347 | * @param src_offset The offset of the source byte sequence
348 | * (is added to the src_base parameter)
349 | * @param size The number of bytes to be copied
350 | */
351 | public void getBytes(byte[] dst_bytes, short dst_offset,
352 | short src_base, short src_offset,
353 | short size) {
354 | Util.arrayCopy(ptr, (short) (src_base + src_offset),
355 | dst_bytes, dst_offset,
356 | size);
357 | }
358 | /** Retrieve the Java byte array containing all the memory contents.
359 | * To optimize, we don't use external buffers, *
360 | * but we directly copy from the memory array *
361 | * Use this function only if really required. *
362 | * @return The Java byte array containing all memory contents
363 | */
364 | public byte[] getBuffer() {
365 | return ptr;
366 | }
367 | } // class MemoryManager
368 |
--------------------------------------------------------------------------------
/android-projects/Muscle_Card_on_Android/app/src/main/java/com/musclecard/CardEdge/ObjectManager.java:
--------------------------------------------------------------------------------
1 | /* Copyright (C) 1991-2013 Free Software Foundation, Inc.
2 | This file is part of the GNU C Library.
3 |
4 | The GNU C Library is free software; you can redistribute it and/or
5 | modify it under the terms of the GNU Lesser General Public
6 | License as published by the Free Software Foundation; either
7 | version 2.1 of the License, or (at your option) any later version.
8 |
9 | The GNU C Library is distributed in the hope that it will be useful,
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 | Lesser General Public License for more details.
13 |
14 | You should have received a copy of the GNU Lesser General Public
15 | License along with the GNU C Library; if not, see
16 |
38 | *
39 | * Objects are linked in a list in the
40 | * dynamic memory. No smart search is done
41 | * at the moment.
42 | *
43 | * Object fields:
44 | *
229 | * Object header is found at the returned offset, while object
230 | * data starts right after the header
231 | * This performs a linear search, so performance issues could arise
232 | * as the number of objects grows
233 | * If object is not found, then returns NULL_OFFSET
234 | * @param type Object Type
235 | * @param id Object ID (Type and ID form a generic 4 bytes identifier)
236 | * @return The starting offset of the object or NULL_OFFSET if the object
237 | * is not found.
238 | */
239 | private short getEntry(short type, short id) {
240 | /* This is a stupid linear search. It's fine for a few objects.
241 | * TODO: Use a map for high number of objects */
242 | short base = obj_list_head;
243 | while (base != MemoryManager.NULL_OFFSET) {
244 | if ((mem.getShort(base, OBJ_H_CLASS) == type)
245 | && (mem.getShort(base, OBJ_H_ID) == id))
246 | return base;
247 | base = mem.getShort(base, OBJ_H_NEXT);
248 | }
249 | return MemoryManager.NULL_OFFSET;
250 | }
251 | /** Returns the data base address (offset) for an object.
252 | * The base address can be used for further calls to
253 | * xxxFromAddress() methods
254 | * This function should only be used if performance
255 | * issue arise. setObjectData() and getObjectData()
256 | * should be used, instead.
257 | * @param type Object Type
258 | * @param id Object ID (Type and ID form a generic 4 bytes identifier)
259 | * @return The starting offset of the object. At this location
260 | */
261 | public short getBaseAddress(short type, short id) {
262 | short base = getEntry(type, id);
263 | if (base == MemoryManager.NULL_OFFSET)
264 | return MemoryManager.NULL_OFFSET;
265 | else
266 | return ((short) (base + OBJ_HEADER_SIZE));
267 | }
268 | /** Checks if an object exists
269 | * @param type The object type
270 | * @param id The object ID
271 | * @return true if object exists
272 | */
273 | public boolean exists(short type, short id) {
274 | short base = getEntry(type, id);
275 | return (base != MemoryManager.NULL_OFFSET);
276 | }
277 | /** Returns object size from the base address */
278 | public short getSizeFromAddress(short base) {
279 | return mem.getShort((short) (base - OBJ_HEADER_SIZE + OBJ_H_SIZE));
280 | }
281 | /** Resets the objects iterator and retrieves the information
282 | * record of the first object, if any.
283 | * @param buffer The byte array into which the record will be copied
284 | * @param offset The offset in buffer[] at which the record will be copied
285 | * @return True if an object was found. False if there are no objects.
286 | *
287 | * @see #getNextRecord
288 | */
289 | public boolean getFirstRecord(byte[] buffer, short offset) {
290 | it = obj_list_head;
291 | return getNextRecord(buffer, offset);
292 | }
293 | /** Retrieves the information record of the next object, if any.
294 | * @param buffer The byte array into which the record will be copied
295 | * @param offset The offset in buffer[] at which the record will be copied
296 | * @return True if an object was found. False if there are no more
297 | * objects to inspect.
298 | * @see #getFirstRecord
299 | */
300 | public boolean getNextRecord(byte[] buffer, short offset) {
301 | //Debug by erik
302 | /*
303 | if (it == MemoryManager.NULL_OFFSET){
304 | System.out.println("it == MemoryManager.NULL_OFFSET");
305 | return false;
306 | }
307 | */
308 | if (it == MemoryManager.NULL_OFFSET)
309 | return false;
310 | // Setting Object Class
311 | Util.setShort(buffer, offset, mem.getShort(it, OBJ_H_CLASS));
312 | // Setting Object ID
313 | Util.setShort(buffer, (short) (offset + 2), mem.getShort(it, OBJ_H_ID));
314 | // Setting Size's M.S.Short to zero.
315 | Util.setShort(buffer, (short) (offset + 4), (short) 0);
316 | // Setting Size's L.S.Short
317 | Util.setShort(buffer, (short) (offset + 6), mem.getShort(it, (short) OBJ_H_SIZE));
318 | // Setting ACL
319 | Util.arrayCopyNonAtomic(mem.getBuffer(), (short) (it + OBJ_H_ACL),
320 | buffer, (short) (offset + 8), OBJ_ACL_SIZE);
321 | // Advance iterator
322 | it = mem.getShort(it, OBJ_H_NEXT);
323 | return true;
324 | }
325 | /**
326 | * Compare an object's ACL with the provided ACL.
327 | * @param base The object base address, as returned from getBaseAddress()
328 | * @param acl The buffer containing the ACL
329 | * @return True if the ACLs are equal
330 | */
331 | public boolean compareACLFromAddress(short base, byte[] acl) {
332 | return (Util.arrayCompare(mem.getBuffer(), (short) (base - OBJ_HEADER_SIZE + OBJ_H_ACL),
333 | acl, (short) 0, OBJ_ACL_SIZE) == (byte) 0);
334 | }
335 | } // class MemoryManager
336 |
--------------------------------------------------------------------------------
54 | * short size;
55 | * short next;
56 | *
57 | */
58 | public class MemoryManager {
59 | /** Special offset value used as invalid offset */
60 | public final static short NULL_OFFSET = (short) 0xFFFF; // Also used as End Of List
61 | private final static byte NODE_SIZE = (byte) 4;
62 | // All the available memory as a byte array
63 | private byte ptr[] = null;
64 | // Free memory list
65 | private short free_head = NULL_OFFSET;
66 | /** Constructor for the MemoryManager class
67 | * @param mem_size Size of the memory are to be allocated
68 | */
69 | public MemoryManager(short mem_size) {
70 | Init(mem_size);
71 | }
72 | private void Init(short mem_size) {
73 | if (ptr != null)
74 | return;
75 | // Allocate the memory
76 | ptr = new byte[mem_size];
77 | // Setup the free memory list
78 | // set the size
79 | Util.setShort(ptr, (short) 0, (short) mem_size);
80 | // set the pointer to EndOfList
81 | Util.setShort(ptr, (short) 2, (short) NULL_OFFSET);
82 | // set the pointer to the head node
83 | free_head = (short) 0;
84 | }
85 | /** Allocate memory
45 | * short next
46 | * short obj_class
47 | * short obj_id
48 | * short obj_size
49 | * byte[] data
50 | *
51 | *
52 | * TODO
53 | * - Could we definitively avoid a map enforcing the ID
54 | * (equal to the memory address, i.e.) - security implications ?
55 | *
56 | */
57 | public class ObjectManager {
58 | public final static byte OBJ_ACL_SIZE = (byte) 6;
59 | private final static byte OBJ_HEADER_SIZE = (byte) (6 + OBJ_ACL_SIZE + 2);
60 | private final static byte OBJ_H_NEXT = (byte) 0; // Short size;
61 | private final static byte OBJ_H_CLASS = (byte) 2; // Short ocj_class;
62 | private final static byte OBJ_H_ID = (byte) 4; // Short obj_id;
63 | private final static byte OBJ_H_ACL = (byte) 6; // Byte[OBJ_ACL_SIZE] acl;
64 | private final static byte OBJ_H_SIZE = (byte) 12; // Short size;
65 | private final static byte OBJ_H_DATA = (byte) 14;
66 | /** There have been memory problems on the card */
67 | public final static short SW_NO_MEMORY_LEFT = (short) 0x9C01;
68 | /** Size of an Object Record filled by getFirstRecord()
69 | * or getNextRecord(): ID, Size, ACL */
70 | public final static short RECORD_SIZE = (short) (4 + 4 + OBJ_ACL_SIZE);
71 | /** Iterator on objects. Stores the offset of the last retrieved object's record. */
72 | private short it;
73 | /** The Memory Manager object */
74 | private MemoryManager mem = null;
75 | /** Map for fast search of objects (unimplemented) */
76 | // static Map map;
77 | /** Head of the objects' list */
78 | private short obj_list_head = MemoryManager.NULL_OFFSET;
79 | /** Constructor for the ObjectManager class.
80 | * @param mem_ref The MemoryManager object to be used
81 | * to allocate objects' memory.
82 | */
83 | public ObjectManager(MemoryManager mem_ref) {
84 | mem = mem_ref;
85 | // map = new Map();
86 | obj_list_head = MemoryManager.NULL_OFFSET;
87 | }
88 | /** Creates an object with specified parameters. Throws a SW_NO_MEMORY_LEFT
89 | * exception if cannot allocate the memory. Does not check if object exists.
90 | * @param type Object Type
91 | * @param id Object ID (Type and ID form a generic 4 bytes identifier)
92 | * @param acl_buf Java byte array containing the ACL for the new object
93 | * @param acl_offset Offset at which the ACL starts in acl_buf[]
94 | * @return The memory base address for the object. It can be used
95 | * in successive calls to xxxFromAddress() methods.
96 | */
97 | public short createObject(short type, short id, short size,
98 | byte[] acl_buf, short acl_offset) {
99 | /* Allocate memory for new object */
100 | short base = mem.alloc((short) (size + OBJ_HEADER_SIZE));
101 | if (base == MemoryManager.NULL_OFFSET)
102 | ISOException.throwIt(SW_NO_MEMORY_LEFT);
103 | /* New obj will be inserted in the head of the list */
104 | mem.setShort(base, OBJ_H_NEXT, obj_list_head);
105 | mem.setShort(base, OBJ_H_CLASS, type);
106 | mem.setShort(base, OBJ_H_ID, id);
107 | mem.setShort(base, OBJ_H_SIZE, size);
108 | mem.setBytes(base, OBJ_H_ACL, acl_buf, acl_offset, OBJ_ACL_SIZE);
109 | obj_list_head = base;
110 | /* Add to the map */
111 | // map.addEntry(type, id, base);
112 | // Return base address
113 | return (short) (base + OBJ_HEADER_SIZE);
114 | }
115 | /** Creates an object with the maximum available size */
116 | public short createObjectMax(short type, short id,
117 | byte[] acl_buf, short acl_offset) {
118 | short obj_size = mem.getMaxSize();
119 | if (obj_size == (short) 0)
120 | ISOException.throwIt(SW_NO_MEMORY_LEFT);
121 | /* The object's real size must take into account that *
122 | * extra bytes are needed for the header */
123 | return createObject(type, id, (short) (obj_size - OBJ_HEADER_SIZE),
124 | acl_buf, acl_offset);
125 | }
126 | /** Clamps an object freeing the unused memory
127 | * @param type Object Type
128 | * @param id Object ID (Type and ID form a generic 4 bytes identifier)
129 | * @param new_size The new object size (must be less than current size)
130 | * @return True if clamp was possible, false otherwise
131 | */
132 | public boolean clampObject(short type, short id, short new_size) {
133 | short base = getEntry(type, id);
134 | if (base == (short) MemoryManager.NULL_OFFSET)
135 | ISOException.throwIt((short) 0x9C07);
136 | // Delegate every check to the Memory Manager
137 | if (mem.realloc(base, (short) (new_size + OBJ_HEADER_SIZE))) {
138 | mem.setShort(base, OBJ_H_SIZE, new_size);
139 | return true;
140 | }
141 | return false;
142 | }
143 | /** Set the object's ACL. Unused at the moment. */
144 | private void setACL(short type, short id, byte[] acl_buf, short acl_offset) {
145 | short base = getEntry(type, id);
146 | mem.setBytes(base, OBJ_H_ACL, acl_buf, acl_offset, OBJ_ACL_SIZE);
147 | }
148 | /** Allow or unallow read on object given the logged identities
149 | * @param base The object base address as returned from getBaseAddress()
150 | * @param logged_ids The current logged in identities as stored in CardEdge.logged_ids
151 | */
152 | public boolean authorizeReadFromAddress(short base, short logged_ids) {
153 | return authorizeOp(mem.getShort(base, (short) (OBJ_H_ACL - OBJ_HEADER_SIZE)), logged_ids);
154 | }
155 | /** Allow or unallow write on object given the logged identities
156 | * @param base The object base address as returned from getBaseAddress()
157 | * @param logged_ids The current logged in identities as stored in CardEdge.logged_ids
158 | */
159 | public boolean authorizeWriteFromAddress(short base, short logged_ids) {
160 | return authorizeOp(mem.getShort(base, (short) (OBJ_H_ACL + (short) 2 - OBJ_HEADER_SIZE)), logged_ids);
161 | }
162 | /** Allow or unallow delete on object given the logged identities
163 | * @param base The object base address as returned from getBaseAddress()
164 | * @param logged_ids The current logged in identities as stored in CardEdge.logged_ids
165 | */
166 | public boolean authorizeDeleteFromAddress(short base, short logged_ids) {
167 | return authorizeOp(mem.getShort(base, (short) (OBJ_H_ACL + (short) 4 - OBJ_HEADER_SIZE)), logged_ids);
168 | }
169 | /** Check if logged in identities satisfy requirements for an operation
170 | * @param required_ids The required identities as from an ACL short
171 | * @param logged_ids The current logged in identities as stored in CardEdge.logged_ids
172 | */
173 | private boolean authorizeOp(short required_ids, short logged_ids) {
174 | return (
175 | (required_ids != (short) 0xFFFF)
176 | && (((short) (required_ids & logged_ids)) == required_ids)
177 | );
178 | }
179 | /** Write data at the specified location in an object */
180 | // public void setObjectData(short type, short id, short dst_offset,
181 | // byte[] src_data, short src_offset,
182 | // short len) {
183 | // // TODO: short dst_base = map.getEntry(type, id);
184 | // short dst_base = getEntry(type, id);
185 | // mem.setBytes(dst_base, dst_offset, src_data, src_offset, len);
186 | // }
187 | // /** Read data from the specified location in an object */
188 | // public void getObjectData(byte[] dst_data, short dst_offset,
189 | // short type, short id, short src_offset,
190 | // short len) {
191 | // // TODO: short dst_base = map.getEntry(type, id);
192 | // short src_base = getEntry(type, id);
193 | // mem.getBytes(dst_data, dst_offset, src_base, src_offset, len);
194 | // }
195 | /** Destroy the specified object
196 | * @param type Object Type
197 | * @param id Object ID (Type and ID form a generic 4 bytes identifier)
198 | * @param secure If true, object memory is zeroed before being released.
199 | */
200 | public void destroyObject(short type, short id, boolean secure) {
201 | short base = obj_list_head;
202 | short prev = MemoryManager.NULL_OFFSET;
203 | boolean found = false;
204 | while ((! found) && (base != MemoryManager.NULL_OFFSET)) {
205 | if ((mem.getShort(base, OBJ_H_CLASS) == type)
206 | && (mem.getShort(base, OBJ_H_ID) == id))
207 | found = true;
208 | else {
209 | prev = base;
210 | base = mem.getShort(base, OBJ_H_NEXT);
211 | }
212 | }
213 | if (found) {
214 | // Unlink object from the list
215 | if (prev != MemoryManager.NULL_OFFSET) {
216 | mem.setShort(prev, OBJ_H_NEXT, mem.getShort(base, OBJ_H_NEXT));
217 | } else {
218 | obj_list_head = mem.getShort(base, OBJ_H_NEXT);
219 | }
220 | // Zero memory if required
221 | if (secure)
222 | Util.arrayFillNonAtomic(mem.getBuffer(), (short) (base + OBJ_HEADER_SIZE),
223 | mem.getShort(base, OBJ_H_SIZE), (byte) 0x00);
224 | // Free memory
225 | mem.free(base);
226 | }
227 | }
228 | /** Returns the header base address (offset) for the specified object