├── .gitignore ├── .jscsrc ├── .jshintrc ├── .travis.yml ├── LICENSE ├── README.md ├── adb.js ├── binding.gyp ├── binding ├── sign.cc └── sign.h ├── connectionStateMachine.png ├── deps └── libmincrypt │ ├── NOTICE │ ├── dsa_sig.c │ ├── include │ ├── dsa_sig.h │ ├── hash-internal.h │ ├── p256.h │ ├── p256_ecdsa.h │ ├── rsa.h │ ├── sha.h │ └── sha256.h │ ├── libmincrypt.gyp │ ├── p256.c │ ├── p256_ec.c │ ├── p256_ecdsa.c │ ├── rsa.c │ ├── sha.c │ └── sha256.c ├── gulpfile.js ├── index.js ├── lib ├── adb-device.js ├── constants.js ├── examples │ ├── install.js │ ├── list.es5.js │ ├── list.js │ ├── pull.js │ ├── push.js │ ├── reboot.js │ ├── shell.js │ ├── shellBySerial.js │ └── uninstall.js ├── helpers.js └── usb-device.js ├── package.json └── test ├── .jshintrc ├── fixtures ├── ContactManager.apk ├── largeFile └── smallFile ├── functional └── adb-e2e-specs.js └── unit ├── adb-device-specs.js ├── adb-specs.js ├── helpers-specs.js └── usb-specs.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | Vagrantfile 3 | build 4 | *.log 5 | .DS_store 6 | deps/build 7 | 8 | -------------------------------------------------------------------------------- /.jscsrc: -------------------------------------------------------------------------------- 1 | { 2 | "excludeFiles": ["node_modules/**"], 3 | "requireCurlyBraces": ["for", "while", "do", "try", "catch"], 4 | "requireSpaceAfterKeywords": ["if", "else", "for", "while", "do", "switch", 5 | "return", "try", "catch", "function"], 6 | "disallowMixedSpacesAndTabs": true, 7 | "disallowTrailingWhitespace": true, 8 | "requireSpacesInFunctionExpression": { 9 | "beforeOpeningCurlyBrace": true 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "laxcomma": true, 3 | "undef": true, 4 | "unused": true, 5 | "node": true, 6 | "eqeqeq": true, 7 | "trailing": true, 8 | "indent": 2, 9 | "esnext": true, 10 | "experimental": ["asyncawait"] 11 | } 12 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "4" 4 | - "6" 5 | - "7" 6 | env: 7 | - CXX=g++-4.8 8 | addons: 9 | apt: 10 | sources: 11 | - ubuntu-toolchain-r-test 12 | packages: 13 | - build-essential 14 | - libudev-dev 15 | - g++-4.8 16 | before_script: 17 | - mkdir ~/.android 18 | - touch ~/.android/adbkey.pub 19 | - touch ~/.android/adbkey 20 | - echo "public" > ~/.android/adbkey.pub 21 | - echo "private" > ~/.android/adbkey 22 | after_success: 23 | - gulp coveralls 24 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2012-2016 JS Foundation and other contributors 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.org/appium/node-adb-client.svg)](https://travis-ci.org/appium/node-adb-client) 2 | [![Coverage Status](https://coveralls.io/repos/github/appium/node-adb-client/badge.svg?branch=master)](https://coveralls.io/github/appium/node-adb-client?branch=master) 3 | 4 | # node-adb-client 5 | A direct-to-device ADB client implementation in Node. 6 | 7 | # Protocol Documentation 8 | Documentation for the ADB protocol can be found [here](https://github.com/cstyan/adbDocumentation). 9 | 10 | # Installation. 11 | node-adb-client relies on the npm module [usb](https://www.npmjs.com/package/usb), 12 | please follow it's installation instructions to get the required libraries for your 13 | platform before running `npm install`. 14 | 15 | After `npm install`, please run `node-gyp configure build` to build libmincrypt. 16 | 17 | # Examples 18 | For example usage of each implemented command type see the `lib/examples` folder, 19 | or the tests. 20 | 21 | # Public Functions 22 | These are the functions you should be interacting with when using this library. 23 | 24 | ## Static Functions 25 | Including the library (ADB class) will get you access to the static function 26 | findAdbDevices. This function will return an array of ADB compatible devices, 27 | including the devices serial number. 28 | ``` 29 | let availableDevices = await ADB.findAdbDevices(); 30 | if (availableDevices.length > 0) { 31 | // just select the first device 32 | let device = new ADB(CONNECTION_TYPES.USB, availableDevices[0]); 33 | ``` 34 | 35 | You can also use the `selectBySerial` function from `lib/helpers` to search through 36 | available ADB devices and find the device with a given serial number. For example: 37 | ``` 38 | // select device by serial number: 4d00a90c4f041119 39 | let serial = "4d00a90c4f041119"; 40 | let selectedDevice = selectBySerialNumber(availableDevices, serial); 41 | ``` 42 | 43 | ## Member Functions 44 | After creating a new ADB instance from a device you gain access to a few functions 45 | that allow you to interact with the device. 46 | 47 | ### Connect 48 | Connect takes care of the ADB connection handshake, after which your device is in 49 | a state where you can run any normal ADB command on that device. The connect function 50 | assumes your ADB keys are in `~/.android/` with the names `adbkey` and `adbkey.pub`. 51 | If you've never used ADB before, it's likely that the device will not recognize 52 | your private key, meaning your public key will be sent to the device. If this is 53 | the case, a dialog will show on the devices screen asking you if you want to accept 54 | that public key. Checking the save key checkbox will allow you to skip this step 55 | in the future, and your public key will be accepted for authentication with the 56 | device. 57 | `await device.connect();` 58 | 59 | ### Run Command 60 | The Run Command function takes in a command object, with the command type and 61 | parameters required for that command, and sends them to the device (ADB daemon). 62 | Any results of that command are returned to the client. Available command types 63 | are: 64 | 65 | #### Shell 66 | Run a shell command on the device. 67 | ``` 68 | let command = { 69 | type: "shell" 70 | , string: "ls /sdcard" 71 | , print: false 72 | }; 73 | ``` 74 | By default all shell command output is printed to the console, you can use 75 | `print: false` to block this. 76 | 77 | #### Push 78 | Push a file to the device. 79 | ``` 80 | let command = { 81 | type: "push" 82 | , source: "path/to/some/file" 83 | , destination: "sdcard/" 84 | }; 85 | ``` 86 | 87 | #### Pull 88 | Pull a file from the device. 89 | ``` 90 | let command = { 91 | type: "push" 92 | , source: "sdcard/some/file" 93 | , destination: "~/Desktop/file" 94 | }; 95 | ``` 96 | 97 | #### Install 98 | Install an apk on the deivce. 99 | ``` 100 | let command = { 101 | type: "install" 102 | , source: "path/to/app.apk" 103 | }; 104 | ``` 105 | 106 | #### Uninstall 107 | Uninstall an apk. 108 | ``` 109 | let command = { 110 | type: "uninstall" 111 | , packageName: "com.example.android.contactmanager" 112 | }; 113 | ``` 114 | 115 | #### Reboot 116 | Reboot the device. Note that the promise for this function resolves when the reboot 117 | executes, it does not wait for the device to fully boot up before resolving. 118 | ``` 119 | let command = { 120 | type: "reboot" 121 | }; 122 | ``` 123 | 124 | # Implementing a device type 125 | Currently node-adb-client only supports connecting to ADB devices via USB. The following 126 | functions would have to be implemented in a new class for connections over TCP, or 127 | any other connection type supported by the ADB daemon in the future. See the USB 128 | Device class for implementation examples. 129 | 130 | ## Send Msg 131 | This function should generate an ADB packet with the required fields and format, 132 | and send it to the device. 133 | 134 | ## Recv Msg 135 | This function should take in data from the device and parse it into an ADB packet 136 | format, and return that packet. -------------------------------------------------------------------------------- /adb.js: -------------------------------------------------------------------------------- 1 | import usb from 'usb'; 2 | import { USB_VENDOR_IDS, ADB_VALUES, CONNECTION_TYPES } from './lib/constants'; 3 | import { logExceptOnTest } from './lib/helpers'; 4 | import ADBDevice from './lib/adb-device'; 5 | import Promise from 'bluebird'; 6 | 7 | const NOT_CONNECTED = 0; 8 | const WAIT_FOR_AUTH = 1; 9 | const SEND_PRIVATE_KEY = 2; 10 | const SEND_PUBLIC_KEY = 3; 11 | const CONNECTED = 4; 12 | 13 | class ADB { 14 | constructor (connectionType, device) { 15 | if (connectionType === CONNECTION_TYPES.USB || connectionType === CONNECTION_TYPES.TCP) { 16 | this.state = NOT_CONNECTED; 17 | this.device = new ADBDevice(connectionType, device); 18 | } else { 19 | throw new Error("Cannot create new ADB device, invalid connection type."); 20 | } 21 | } 22 | 23 | // *** STATIC FUNCTIONS *** 24 | static async _getSerialNo (device) { 25 | let langid = 0x0409; 26 | let length = 255; 27 | let deviceDescriptor = device.deviceDescriptor; 28 | device.open(); 29 | let tempDevice = Promise.promisifyAll(device); 30 | let serialNumber = await tempDevice.controlTransferAsync(usb.LIBUSB_ENDPOINT_IN 31 | , usb.LIBUSB_REQUEST_GET_DESCRIPTOR 32 | , ((usb.LIBUSB_DT_STRING << 8) | deviceDescriptor.iSerialNumber) 33 | , langid 34 | ,length); 35 | device.close(); 36 | return serialNumber.toString('utf16le', 2); 37 | } 38 | 39 | // return an array of devices that have an ADB interface 40 | static async findAdbDevices () { 41 | logExceptOnTest("Trying to find a usb device"); 42 | let adbDevices = []; 43 | let usbDevices = usb.getDeviceList(); 44 | // node-usb docs are unclear on if this will ever happen 45 | // or if libusb throws it's own error for no devices 46 | if (usbDevices.length === 0) { 47 | throw new Error("No USB devices found."); 48 | } 49 | for (let device of usbDevices) { 50 | let vendorID = device.deviceDescriptor.idVendor; 51 | if (USB_VENDOR_IDS.indexOf(vendorID) === -1) continue; 52 | let deviceInterface = this._getAdbInterface(device); 53 | if (deviceInterface !== null) { 54 | logExceptOnTest("Found an ADB device"); 55 | let serialNumber = await this._getSerialNo(device); 56 | adbDevices.push({device, deviceInterface, serialNumber}); 57 | } 58 | } 59 | if (adbDevices.length === 0) { 60 | throw new Error("No ADB devices found."); 61 | } 62 | return adbDevices; 63 | } 64 | 65 | // search through a devices interfaces for an interface 66 | // that can be used for ADB communications 67 | static _getAdbInterface (device) { 68 | device.open(); 69 | if (device.interfaces === null) return null; 70 | 71 | if (device.deviceDescriptor !== null && device.configDescriptor !== null) { 72 | // if the vendorID is not part of the vendors we recognize 73 | 74 | let interfaces = device.interfaces; 75 | let returnInterface = null; 76 | for (let iface of interfaces) { 77 | // ADB interface will only have two endpoints 78 | if (iface.endpoints.length !== 2) continue; 79 | // interface for ADB always has these values in it's descriptor 80 | if (iface.descriptor.bInterfaceClass !== ADB_VALUES.ADB_CLASS || 81 | iface.descriptor.bInterfaceSubClass !== ADB_VALUES.ADB_SUBCLASS || 82 | iface.descriptor.bInterfaceProtocol !== ADB_VALUES.ADB_PROTOCOL) { 83 | continue; 84 | } 85 | // if we get to this point we have the interface we want 86 | returnInterface = iface; 87 | break; 88 | } 89 | return returnInterface; 90 | } 91 | return null; 92 | } 93 | // *** END OF STATIC FUNCTIONS *** 94 | 95 | // runs the connection state machine 96 | async connect () { 97 | let packet; 98 | while (1) { 99 | switch (this.state) { 100 | case NOT_CONNECTED: 101 | logExceptOnTest("NOT_CONNECTED"); 102 | await this.device.initConnection(); 103 | this.state = WAIT_FOR_AUTH; 104 | break; 105 | case WAIT_FOR_AUTH: 106 | logExceptOnTest("WAIT_FOR_AUTH"); 107 | try { 108 | packet = await this.device.waitForAuth(); 109 | if (packet === false) { 110 | this.state = NOT_CONNECTED; 111 | } else { 112 | this.state = SEND_PRIVATE_KEY; 113 | } 114 | } catch (e) { 115 | if (e.errno === 2) { 116 | logExceptOnTest("Timeout error, this should never happen: ", this.state); 117 | this.state = NOT_CONNECTED; 118 | } else { 119 | throw e; 120 | } 121 | } 122 | break; 123 | case SEND_PRIVATE_KEY: 124 | logExceptOnTest("SEND_PRIVATE_KEY"); 125 | try { 126 | if (await this.device.sendSignedToken(packet.data)) { 127 | this.state = CONNECTED; 128 | } else { 129 | this.state = SEND_PUBLIC_KEY; 130 | } 131 | } catch (e) { 132 | if (e.errno === 2) { 133 | logExceptOnTest("Timeout error, this should never happen: ", this.state); 134 | this.state = NOT_CONNECTED; 135 | } else { 136 | throw e; 137 | } 138 | } 139 | break; 140 | case SEND_PUBLIC_KEY: 141 | logExceptOnTest("SEND_PUBLIC_KEY"); 142 | try { 143 | if (await this.device.sendPublicKey()) { 144 | this.state = CONNECTED; 145 | } else { 146 | this.state = NOT_CONNECTED; 147 | } 148 | } catch (e) { 149 | if (e.errno === 2) { //timeout error 150 | logExceptOnTest("Timeout error, did you accept the public key on the device?"); 151 | this.state = NOT_CONNECTED; 152 | } else { 153 | throw e; 154 | } 155 | } 156 | break; 157 | case CONNECTED: // ready to start runing command on the device now 158 | logExceptOnTest("CONNECTED"); 159 | return; 160 | default: //wtf 161 | this.state = NOT_CONNECTED; 162 | } 163 | } 164 | } 165 | 166 | async runCommand (command) { 167 | let output = null; 168 | if (this.state === CONNECTED) { 169 | output = await this.device.open(command); 170 | } else { 171 | throw new Error("State is not CONNECTED, cannot run a command."); 172 | } 173 | return output; 174 | } 175 | 176 | async closeConnection () { 177 | if (this.state === CONNECTED) { 178 | await this.device.closeConnection(); 179 | this.state = NOT_CONNECTED; 180 | } else { 181 | logExceptOnTest("Not connection to close."); 182 | } 183 | } 184 | } 185 | 186 | export default ADB; -------------------------------------------------------------------------------- /binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | 'targets': 3 | [ 4 | { 5 | 'target_name': 'binding', 6 | 'sources': [ 'binding/sign.cc' ], 7 | 'include_dirs': [ './deps/libmincrypt/include', " 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #define RSA_verify RSA_verify_mincrypt 11 | #include "rsa.h" 12 | #undef RSA_verify 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #include "sign.h" 21 | #include 22 | #include 23 | #define MAX_PAYLOAD 4096 24 | 25 | void Sign(const Nan::FunctionCallbackInfo& args) { 26 | 27 | if (args.Length() < 2) { 28 | Nan::ThrowTypeError("Wrong number of arguments"); 29 | return; 30 | } 31 | 32 | FILE *fd; 33 | unsigned int len; 34 | const char* key_path; 35 | const unsigned char* token; 36 | 37 | key_path = (const char*)node::Buffer::Data(args[0]); 38 | token = (unsigned char*)node::Buffer::Data(args[1]); 39 | 40 | unsigned char sig[MAX_PAYLOAD]; 41 | 42 | RSA *rsa = RSA_new(); 43 | fd = fopen(key_path, "r"); 44 | if (!fd) { 45 | Nan::ThrowTypeError("fopen() failed"); 46 | return; 47 | } 48 | if (!PEM_read_RSAPrivateKey(fd, &rsa, NULL, NULL)) { 49 | fclose(fd); 50 | RSA_free(rsa); 51 | Nan::ThrowTypeError("couldn't read private key"); 52 | return; 53 | } 54 | if (!RSA_sign(NID_sha1, token, node::Buffer::Length(args[1]), sig, &len, rsa)) { 55 | Nan::ThrowTypeError("failed to sign token"); 56 | } 57 | args.GetReturnValue().Set(Nan::CopyBuffer(reinterpret_cast(sig), len).ToLocalChecked()); 58 | } 59 | 60 | void Init(v8::Local exports) { 61 | exports->Set(Nan::New("sign").ToLocalChecked(), 62 | Nan::New(Sign)->GetFunction()); 63 | } 64 | 65 | NODE_MODULE(binding, Init) -------------------------------------------------------------------------------- /binding/sign.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | NAN_METHOD(Sign); -------------------------------------------------------------------------------- /connectionStateMachine.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/appium/node-adb-client/4549760ca6f79f0f7dae5d41b2b1d1502774e20d/connectionStateMachine.png -------------------------------------------------------------------------------- /deps/libmincrypt/NOTICE: -------------------------------------------------------------------------------- 1 | Copyright 2008, The Android Open Source Project 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are met: 5 | * Redistributions of source code must retain the above copyright 6 | notice, this list of conditions and the following disclaimer. 7 | * Redistributions in binary form must reproduce the above copyright 8 | notice, this list of conditions and the following disclaimer in the 9 | documentation and/or other materials provided with the distribution. 10 | * Neither the name of Google Inc. nor the names of its contributors may 11 | be used to endorse or promote products derived from this software 12 | without specific prior written permission. 13 | 14 | THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR 15 | IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 16 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 17 | EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 18 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 20 | OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 21 | WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 22 | OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 23 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | -------------------------------------------------------------------------------- /deps/libmincrypt/dsa_sig.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 The Android Open Source Project 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * * Redistributions of source code must retain the above copyright 7 | * notice, this list of conditions and the following disclaimer. 8 | * * Redistributions in binary form must reproduce the above copyright 9 | * notice, this list of conditions and the following disclaimer in the 10 | * documentation and/or other materials provided with the distribution. 11 | * * Neither the name of Google Inc. nor the names of its contributors may 12 | * be used to endorse or promote products derived from this software 13 | * without specific prior written permission. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR 16 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 17 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 18 | * EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 19 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 21 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 23 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 24 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | #include 28 | 29 | #include "mincrypt/dsa_sig.h" 30 | #include "mincrypt/p256.h" 31 | 32 | /** 33 | * Trims off the leading zero bytes and copy it to a buffer aligning it to the end. 34 | */ 35 | static inline int trim_to_p256_bytes(unsigned char dst[P256_NBYTES], unsigned char *src, 36 | int src_len) { 37 | int dst_offset; 38 | while (*src == '\0' && src_len > 0) { 39 | src++; 40 | src_len--; 41 | } 42 | if (src_len > P256_NBYTES || src_len < 1) { 43 | return 0; 44 | } 45 | dst_offset = P256_NBYTES - src_len; 46 | memset(dst, 0, dst_offset); 47 | memcpy(dst + dst_offset, src, src_len); 48 | return 1; 49 | } 50 | 51 | /** 52 | * Unpacks the ASN.1 DSA signature sequence. 53 | */ 54 | int dsa_sig_unpack(unsigned char* sig, int sig_len, p256_int* r_int, p256_int* s_int) { 55 | /* 56 | * Structure is: 57 | * 0x30 0xNN SEQUENCE + s_length 58 | * 0x02 0xNN INTEGER + r_length 59 | * 0xAA 0xBB .. r_length bytes of "r" (offset 4) 60 | * 0x02 0xNN INTEGER + s_length 61 | * 0xMM 0xNN .. s_length bytes of "s" (offset 6 + r_len) 62 | */ 63 | int seq_len; 64 | unsigned char r_bytes[P256_NBYTES]; 65 | unsigned char s_bytes[P256_NBYTES]; 66 | int r_len; 67 | int s_len; 68 | 69 | memset(r_bytes, 0, sizeof(r_bytes)); 70 | memset(s_bytes, 0, sizeof(s_bytes)); 71 | 72 | /* 73 | * Must have at least: 74 | * 2 bytes sequence header and length 75 | * 2 bytes R integer header and length 76 | * 1 byte of R 77 | * 2 bytes S integer header and length 78 | * 1 byte of S 79 | * 80 | * 8 bytes total 81 | */ 82 | if (sig_len < 8 || sig[0] != 0x30 || sig[2] != 0x02) { 83 | return 0; 84 | } 85 | 86 | seq_len = sig[1]; 87 | if ((seq_len <= 0) || (seq_len + 2 != sig_len)) { 88 | return 0; 89 | } 90 | 91 | r_len = sig[3]; 92 | /* 93 | * Must have at least: 94 | * 2 bytes for R header and length 95 | * 2 bytes S integer header and length 96 | * 1 byte of S 97 | */ 98 | if ((r_len < 1) || (r_len > seq_len - 5) || (sig[4 + r_len] != 0x02)) { 99 | return 0; 100 | } 101 | s_len = sig[5 + r_len]; 102 | 103 | /** 104 | * Must have: 105 | * 2 bytes for R header and length 106 | * r_len bytes for R 107 | * 2 bytes S integer header and length 108 | */ 109 | if ((s_len < 1) || (s_len != seq_len - 4 - r_len)) { 110 | return 0; 111 | } 112 | 113 | /* 114 | * ASN.1 encoded integers are zero-padded for positive integers. Make sure we have 115 | * a correctly-sized buffer and that the resulting integer isn't too large. 116 | */ 117 | if (!trim_to_p256_bytes(r_bytes, &sig[4], r_len) 118 | || !trim_to_p256_bytes(s_bytes, &sig[6 + r_len], s_len)) { 119 | return 0; 120 | } 121 | 122 | p256_from_bin(r_bytes, r_int); 123 | p256_from_bin(s_bytes, s_int); 124 | 125 | return 1; 126 | } 127 | -------------------------------------------------------------------------------- /deps/libmincrypt/include/dsa_sig.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 The Android Open Source Project 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * * Redistributions of source code must retain the above copyright 7 | * notice, this list of conditions and the following disclaimer. 8 | * * Redistributions in binary form must reproduce the above copyright 9 | * notice, this list of conditions and the following disclaimer in the 10 | * documentation and/or other materials provided with the distribution. 11 | * * Neither the name of Google Inc. nor the names of its contributors may 12 | * be used to endorse or promote products derived from this software 13 | * without specific prior written permission. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR 16 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 17 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 18 | * EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 19 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 21 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 23 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 24 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | #ifndef SYSTEM_CORE_INCLUDE_MINCRYPT_DSA_SIG_H_ 28 | #define SYSTEM_CORE_INCLUDE_MINCRYPT_DSA_SIG_H_ 29 | 30 | #include "mincrypt/p256.h" 31 | 32 | #ifdef __cplusplus 33 | extern "C" { 34 | #endif 35 | 36 | // Returns 0 if input sig is not a valid ASN.1 sequence 37 | int dsa_sig_unpack(unsigned char* sig, int sig_len, p256_int* r_int, p256_int* s_int); 38 | 39 | #ifdef __cplusplus 40 | } 41 | #endif 42 | 43 | #endif /* SYSTEM_CORE_INCLUDE_MINCRYPT_DSA_SIG_H_ */ 44 | -------------------------------------------------------------------------------- /deps/libmincrypt/include/hash-internal.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2007 The Android Open Source Project 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * * Redistributions of source code must retain the above copyright 7 | * notice, this list of conditions and the following disclaimer. 8 | * * Redistributions in binary form must reproduce the above copyright 9 | * notice, this list of conditions and the following disclaimer in the 10 | * documentation and/or other materials provided with the distribution. 11 | * * Neither the name of Google Inc. nor the names of its contributors may 12 | * be used to endorse or promote products derived from this software 13 | * without specific prior written permission. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR 16 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 17 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 18 | * EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 19 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 21 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 23 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 24 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | #ifndef SYSTEM_CORE_INCLUDE_MINCRYPT_HASH_INTERNAL_H_ 28 | #define SYSTEM_CORE_INCLUDE_MINCRYPT_HASH_INTERNAL_H_ 29 | 30 | #include 31 | 32 | #ifdef __cplusplus 33 | extern "C" { 34 | #endif // __cplusplus 35 | 36 | struct HASH_CTX; // forward decl 37 | 38 | typedef struct HASH_VTAB { 39 | void (* const init)(struct HASH_CTX*); 40 | void (* const update)(struct HASH_CTX*, const void*, int); 41 | const uint8_t* (* const final)(struct HASH_CTX*); 42 | const uint8_t* (* const hash)(const void*, int, uint8_t*); 43 | int size; 44 | } HASH_VTAB; 45 | 46 | typedef struct HASH_CTX { 47 | const HASH_VTAB * f; 48 | uint64_t count; 49 | uint8_t buf[64]; 50 | uint32_t state[8]; // upto SHA2 51 | } HASH_CTX; 52 | 53 | #define HASH_init(ctx) (ctx)->f->init(ctx) 54 | #define HASH_update(ctx, data, len) (ctx)->f->update(ctx, data, len) 55 | #define HASH_final(ctx) (ctx)->f->final(ctx) 56 | #define HASH_hash(data, len, digest) (ctx)->f->hash(data, len, digest) 57 | #define HASH_size(ctx) (ctx)->f->size 58 | 59 | #ifdef __cplusplus 60 | } 61 | #endif // __cplusplus 62 | 63 | #endif // SYSTEM_CORE_INCLUDE_MINCRYPT_HASH_INTERNAL_H_ 64 | -------------------------------------------------------------------------------- /deps/libmincrypt/include/p256.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 The Android Open Source Project 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * * Redistributions of source code must retain the above copyright 7 | * notice, this list of conditions and the following disclaimer. 8 | * * Redistributions in binary form must reproduce the above copyright 9 | * notice, this list of conditions and the following disclaimer in the 10 | * documentation and/or other materials provided with the distribution. 11 | * * Neither the name of Google Inc. nor the names of its contributors may 12 | * be used to endorse or promote products derived from this software 13 | * without specific prior written permission. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR 16 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 17 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 18 | * EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 19 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 21 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 23 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 24 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | #ifndef SYSTEM_CORE_INCLUDE_MINCRYPT_LITE_P256_H_ 28 | #define SYSTEM_CORE_INCLUDE_MINCRYPT_LITE_P256_H_ 29 | 30 | // Collection of routines manipulating 256 bit unsigned integers. 31 | // Just enough to implement ecdsa-p256 and related algorithms. 32 | 33 | #include 34 | 35 | #ifdef __cplusplus 36 | extern "C" { 37 | #endif 38 | 39 | #define P256_BITSPERDIGIT 32 40 | #define P256_NDIGITS 8 41 | #define P256_NBYTES 32 42 | 43 | typedef int p256_err; 44 | typedef uint32_t p256_digit; 45 | typedef int32_t p256_sdigit; 46 | typedef uint64_t p256_ddigit; 47 | typedef int64_t p256_sddigit; 48 | 49 | // Defining p256_int as struct to leverage struct assigment. 50 | typedef struct { 51 | p256_digit a[P256_NDIGITS]; 52 | } p256_int; 53 | 54 | extern const p256_int SECP256r1_n; // Curve order 55 | extern const p256_int SECP256r1_p; // Curve prime 56 | extern const p256_int SECP256r1_b; // Curve param 57 | 58 | // Initialize a p256_int to zero. 59 | void p256_init(p256_int* a); 60 | 61 | // Clear a p256_int to zero. 62 | void p256_clear(p256_int* a); 63 | 64 | // Return bit. Index 0 is least significant. 65 | int p256_get_bit(const p256_int* a, int index); 66 | 67 | // b := a % MOD 68 | void p256_mod( 69 | const p256_int* MOD, 70 | const p256_int* a, 71 | p256_int* b); 72 | 73 | // c := a * (top_b | b) % MOD 74 | void p256_modmul( 75 | const p256_int* MOD, 76 | const p256_int* a, 77 | const p256_digit top_b, 78 | const p256_int* b, 79 | p256_int* c); 80 | 81 | // b := 1 / a % MOD 82 | // MOD best be SECP256r1_n 83 | void p256_modinv( 84 | const p256_int* MOD, 85 | const p256_int* a, 86 | p256_int* b); 87 | 88 | // b := 1 / a % MOD 89 | // MOD best be SECP256r1_n 90 | // Faster than p256_modinv() 91 | void p256_modinv_vartime( 92 | const p256_int* MOD, 93 | const p256_int* a, 94 | p256_int* b); 95 | 96 | // b := a << (n % P256_BITSPERDIGIT) 97 | // Returns the bits shifted out of most significant digit. 98 | p256_digit p256_shl(const p256_int* a, int n, p256_int* b); 99 | 100 | // b := a >> (n % P256_BITSPERDIGIT) 101 | void p256_shr(const p256_int* a, int n, p256_int* b); 102 | 103 | int p256_is_zero(const p256_int* a); 104 | int p256_is_odd(const p256_int* a); 105 | int p256_is_even(const p256_int* a); 106 | 107 | // Returns -1, 0 or 1. 108 | int p256_cmp(const p256_int* a, const p256_int *b); 109 | 110 | // c: = a - b 111 | // Returns -1 on borrow. 112 | int p256_sub(const p256_int* a, const p256_int* b, p256_int* c); 113 | 114 | // c := a + b 115 | // Returns 1 on carry. 116 | int p256_add(const p256_int* a, const p256_int* b, p256_int* c); 117 | 118 | // c := a + (single digit)b 119 | // Returns carry 1 on carry. 120 | int p256_add_d(const p256_int* a, p256_digit b, p256_int* c); 121 | 122 | // ec routines. 123 | 124 | // {out_x,out_y} := nG 125 | void p256_base_point_mul(const p256_int *n, 126 | p256_int *out_x, 127 | p256_int *out_y); 128 | 129 | // {out_x,out_y} := n{in_x,in_y} 130 | void p256_point_mul(const p256_int *n, 131 | const p256_int *in_x, 132 | const p256_int *in_y, 133 | p256_int *out_x, 134 | p256_int *out_y); 135 | 136 | // {out_x,out_y} := n1G + n2{in_x,in_y} 137 | void p256_points_mul_vartime( 138 | const p256_int *n1, const p256_int *n2, 139 | const p256_int *in_x, const p256_int *in_y, 140 | p256_int *out_x, p256_int *out_y); 141 | 142 | // Return whether point {x,y} is on curve. 143 | int p256_is_valid_point(const p256_int* x, const p256_int* y); 144 | 145 | // Outputs big-endian binary form. No leading zero skips. 146 | void p256_to_bin(const p256_int* src, uint8_t dst[P256_NBYTES]); 147 | 148 | // Reads from big-endian binary form, 149 | // thus pre-pad with leading zeros if short. 150 | void p256_from_bin(const uint8_t src[P256_NBYTES], p256_int* dst); 151 | 152 | #define P256_DIGITS(x) ((x)->a) 153 | #define P256_DIGIT(x,y) ((x)->a[y]) 154 | 155 | #define P256_ZERO {{0}} 156 | #define P256_ONE {{1}} 157 | 158 | #ifdef __cplusplus 159 | } 160 | #endif 161 | 162 | #endif // SYSTEM_CORE_INCLUDE_MINCRYPT_LITE_P256_H_ 163 | -------------------------------------------------------------------------------- /deps/libmincrypt/include/p256_ecdsa.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 The Android Open Source Project 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * * Redistributions of source code must retain the above copyright 7 | * notice, this list of conditions and the following disclaimer. 8 | * * Redistributions in binary form must reproduce the above copyright 9 | * notice, this list of conditions and the following disclaimer in the 10 | * documentation and/or other materials provided with the distribution. 11 | * * Neither the name of Google Inc. nor the names of its contributors may 12 | * be used to endorse or promote products derived from this software 13 | * without specific prior written permission. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR 16 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 17 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 18 | * EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 19 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 21 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 23 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 24 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | #ifndef SYSTEM_CORE_INCLUDE_MINCRYPT_P256_ECDSA_H_ 28 | #define SYSTEM_CORE_INCLUDE_MINCRYPT_P256_ECDSA_H_ 29 | 30 | // Using current directory as relative include path here since 31 | // this code typically gets lifted into a variety of build systems 32 | // and directory structures. 33 | #include "p256.h" 34 | 35 | #ifdef __cplusplus 36 | extern "C" { 37 | #endif 38 | 39 | // Returns 0 if {r,s} is not a signature on message for 40 | // public key {key_x,key_y}. 41 | // 42 | // Note: message is a p256_int. 43 | // Convert from a binary string using p256_from_bin(). 44 | int p256_ecdsa_verify(const p256_int* key_x, 45 | const p256_int* key_y, 46 | const p256_int* message, 47 | const p256_int* r, const p256_int* s); 48 | 49 | #ifdef __cplusplus 50 | } 51 | #endif 52 | 53 | #endif // SYSTEM_CORE_INCLUDE_MINCRYPT_P256_ECDSA_H_ 54 | -------------------------------------------------------------------------------- /deps/libmincrypt/include/rsa.h: -------------------------------------------------------------------------------- 1 | /* rsa.h 2 | ** 3 | ** Copyright 2008, The Android Open Source Project 4 | ** 5 | ** Redistribution and use in source and binary forms, with or without 6 | ** modification, are permitted provided that the following conditions are met: 7 | ** * Redistributions of source code must retain the above copyright 8 | ** notice, this list of conditions and the following disclaimer. 9 | ** * Redistributions in binary form must reproduce the above copyright 10 | ** notice, this list of conditions and the following disclaimer in the 11 | ** documentation and/or other materials provided with the distribution. 12 | ** * Neither the name of Google Inc. nor the names of its contributors may 13 | ** be used to endorse or promote products derived from this software 14 | ** without specific prior written permission. 15 | ** 16 | ** THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR 17 | ** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 18 | ** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 19 | ** EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 | ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 | ** PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 22 | ** OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 23 | ** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 24 | ** OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 25 | ** ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #ifndef SYSTEM_CORE_INCLUDE_MINCRYPT_RSA_H_ 29 | #define SYSTEM_CORE_INCLUDE_MINCRYPT_RSA_H_ 30 | 31 | #include 32 | 33 | #ifdef __cplusplus 34 | extern "C" { 35 | #endif 36 | 37 | #define RSANUMBYTES 256 /* 2048 bit key length */ 38 | #define RSANUMWORDS (RSANUMBYTES / sizeof(uint32_t)) 39 | 40 | typedef struct RSAPublicKey { 41 | int len; /* Length of n[] in number of uint32_t */ 42 | uint32_t n0inv; /* -1 / n[0] mod 2^32 */ 43 | uint32_t n[RSANUMWORDS]; /* modulus as little endian array */ 44 | uint32_t rr[RSANUMWORDS]; /* R^2 as little endian array */ 45 | int exponent; /* 3 or 65537 */ 46 | } RSAPublicKey; 47 | 48 | int RSA_verify(const RSAPublicKey *key, 49 | const uint8_t* signature, 50 | const int len, 51 | const uint8_t* hash, 52 | const int hash_len); 53 | 54 | #ifdef __cplusplus 55 | } 56 | #endif 57 | 58 | #endif // SYSTEM_CORE_INCLUDE_MINCRYPT_RSA_H_ 59 | -------------------------------------------------------------------------------- /deps/libmincrypt/include/sha.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2005 The Android Open Source Project 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * * Redistributions of source code must retain the above copyright 7 | * notice, this list of conditions and the following disclaimer. 8 | * * Redistributions in binary form must reproduce the above copyright 9 | * notice, this list of conditions and the following disclaimer in the 10 | * documentation and/or other materials provided with the distribution. 11 | * * Neither the name of Google Inc. nor the names of its contributors may 12 | * be used to endorse or promote products derived from this software 13 | * without specific prior written permission. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR 16 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 17 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 18 | * EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 19 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 21 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 23 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 24 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | #ifndef SYSTEM_CORE_INCLUDE_MINCRYPT_SHA1_H_ 27 | #define SYSTEM_CORE_INCLUDE_MINCRYPT_SHA1_H_ 28 | 29 | #include 30 | #include "hash-internal.h" 31 | 32 | #ifdef __cplusplus 33 | extern "C" { 34 | #endif // __cplusplus 35 | 36 | typedef HASH_CTX SHA_CTX; 37 | 38 | void SHA_init(SHA_CTX* ctx); 39 | void SHA_update(SHA_CTX* ctx, const void* data, int len); 40 | const uint8_t* SHA_final(SHA_CTX* ctx); 41 | 42 | // Convenience method. Returns digest address. 43 | // NOTE: *digest needs to hold SHA_DIGEST_SIZE bytes. 44 | const uint8_t* SHA_hash(const void* data, int len, uint8_t* digest); 45 | 46 | #define SHA_DIGEST_SIZE 20 47 | 48 | #ifdef __cplusplus 49 | } 50 | #endif // __cplusplus 51 | 52 | #endif // SYSTEM_CORE_INCLUDE_MINCRYPT_SHA1_H_ 53 | -------------------------------------------------------------------------------- /deps/libmincrypt/include/sha256.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 The Android Open Source Project 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * * Redistributions of source code must retain the above copyright 7 | * notice, this list of conditions and the following disclaimer. 8 | * * Redistributions in binary form must reproduce the above copyright 9 | * notice, this list of conditions and the following disclaimer in the 10 | * documentation and/or other materials provided with the distribution. 11 | * * Neither the name of Google Inc. nor the names of its contributors may 12 | * be used to endorse or promote products derived from this software 13 | * without specific prior written permission. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR 16 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 17 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 18 | * EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 19 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 21 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 23 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 24 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | #ifndef SYSTEM_CORE_INCLUDE_MINCRYPT_SHA256_H_ 28 | #define SYSTEM_CORE_INCLUDE_MINCRYPT_SHA256_H_ 29 | 30 | #include 31 | #include "hash-internal.h" 32 | 33 | #ifdef __cplusplus 34 | extern "C" { 35 | #endif // __cplusplus 36 | 37 | typedef HASH_CTX SHA256_CTX; 38 | 39 | void SHA256_init(SHA256_CTX* ctx); 40 | void SHA256_update(SHA256_CTX* ctx, const void* data, int len); 41 | const uint8_t* SHA256_final(SHA256_CTX* ctx); 42 | 43 | // Convenience method. Returns digest address. 44 | const uint8_t* SHA256_hash(const void* data, int len, uint8_t* digest); 45 | 46 | #define SHA256_DIGEST_SIZE 32 47 | 48 | #ifdef __cplusplus 49 | } 50 | #endif // __cplusplus 51 | 52 | #endif // SYSTEM_CORE_INCLUDE_MINCRYPT_SHA256_H_ 53 | -------------------------------------------------------------------------------- /deps/libmincrypt/libmincrypt.gyp: -------------------------------------------------------------------------------- 1 | { 2 | 'targets': 3 | [ 4 | { 5 | 'target_name': 'libmincypt', 6 | 'type': 'static_library', 7 | 'include_dirs': 8 | [ 9 | './include' 10 | ], 11 | 'sources': 12 | [ 13 | 'rsa.c', 14 | 'sha.c', 15 | 'sha256.c', 16 | 'dsa_sig.c', 17 | 'p256.c', 18 | 'p256_ec.c', 19 | 'p256_ecdsa.c' 20 | ] 21 | } 22 | ] 23 | } -------------------------------------------------------------------------------- /deps/libmincrypt/p256.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 The Android Open Source Project 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * * Redistributions of source code must retain the above copyright 7 | * notice, this list of conditions and the following disclaimer. 8 | * * Redistributions in binary form must reproduce the above copyright 9 | * notice, this list of conditions and the following disclaimer in the 10 | * documentation and/or other materials provided with the distribution. 11 | * * Neither the name of Google Inc. nor the names of its contributors may 12 | * be used to endorse or promote products derived from this software 13 | * without specific prior written permission. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR 16 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 17 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 18 | * EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 19 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 21 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 23 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 24 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | // This is an implementation of the P256 elliptic curve group. It's written to 28 | // be portable 32-bit, although it's still constant-time. 29 | // 30 | // WARNING: Implementing these functions in a constant-time manner is far from 31 | // obvious. Be careful when touching this code. 32 | // 33 | // See http://www.imperialviolet.org/2010/12/04/ecc.html ([1]) for background. 34 | 35 | #include 36 | #include 37 | #include 38 | #include 39 | 40 | #include "mincrypt/p256.h" 41 | 42 | const p256_int SECP256r1_n = // curve order 43 | {{0xfc632551, 0xf3b9cac2, 0xa7179e84, 0xbce6faad, -1, -1, 0, -1}}; 44 | 45 | const p256_int SECP256r1_p = // curve field size 46 | {{-1, -1, -1, 0, 0, 0, 1, -1 }}; 47 | 48 | const p256_int SECP256r1_b = // curve b 49 | {{0x27d2604b, 0x3bce3c3e, 0xcc53b0f6, 0x651d06b0, 50 | 0x769886bc, 0xb3ebbd55, 0xaa3a93e7, 0x5ac635d8}}; 51 | 52 | void p256_init(p256_int* a) { 53 | memset(a, 0, sizeof(*a)); 54 | } 55 | 56 | void p256_clear(p256_int* a) { p256_init(a); } 57 | 58 | int p256_get_bit(const p256_int* scalar, int bit) { 59 | return (P256_DIGIT(scalar, bit / P256_BITSPERDIGIT) 60 | >> (bit & (P256_BITSPERDIGIT - 1))) & 1; 61 | } 62 | 63 | int p256_is_zero(const p256_int* a) { 64 | int i, result = 0; 65 | for (i = 0; i < P256_NDIGITS; ++i) result |= P256_DIGIT(a, i); 66 | return !result; 67 | } 68 | 69 | // top, c[] += a[] * b 70 | // Returns new top 71 | static p256_digit mulAdd(const p256_int* a, 72 | p256_digit b, 73 | p256_digit top, 74 | p256_digit* c) { 75 | int i; 76 | p256_ddigit carry = 0; 77 | 78 | for (i = 0; i < P256_NDIGITS; ++i) { 79 | carry += *c; 80 | carry += (p256_ddigit)P256_DIGIT(a, i) * b; 81 | *c++ = (p256_digit)carry; 82 | carry >>= P256_BITSPERDIGIT; 83 | } 84 | return top + (p256_digit)carry; 85 | } 86 | 87 | // top, c[] -= top_a, a[] 88 | static p256_digit subTop(p256_digit top_a, 89 | const p256_digit* a, 90 | p256_digit top_c, 91 | p256_digit* c) { 92 | int i; 93 | p256_sddigit borrow = 0; 94 | 95 | for (i = 0; i < P256_NDIGITS; ++i) { 96 | borrow += *c; 97 | borrow -= *a++; 98 | *c++ = (p256_digit)borrow; 99 | borrow >>= P256_BITSPERDIGIT; 100 | } 101 | borrow += top_c; 102 | borrow -= top_a; 103 | top_c = (p256_digit)borrow; 104 | assert((borrow >> P256_BITSPERDIGIT) == 0); 105 | return top_c; 106 | } 107 | 108 | // top, c[] -= MOD[] & mask (0 or -1) 109 | // returns new top. 110 | static p256_digit subM(const p256_int* MOD, 111 | p256_digit top, 112 | p256_digit* c, 113 | p256_digit mask) { 114 | int i; 115 | p256_sddigit borrow = 0; 116 | for (i = 0; i < P256_NDIGITS; ++i) { 117 | borrow += *c; 118 | borrow -= P256_DIGIT(MOD, i) & mask; 119 | *c++ = (p256_digit)borrow; 120 | borrow >>= P256_BITSPERDIGIT; 121 | } 122 | return top + (p256_digit)borrow; 123 | } 124 | 125 | // top, c[] += MOD[] & mask (0 or -1) 126 | // returns new top. 127 | static p256_digit addM(const p256_int* MOD, 128 | p256_digit top, 129 | p256_digit* c, 130 | p256_digit mask) { 131 | int i; 132 | p256_ddigit carry = 0; 133 | for (i = 0; i < P256_NDIGITS; ++i) { 134 | carry += *c; 135 | carry += P256_DIGIT(MOD, i) & mask; 136 | *c++ = (p256_digit)carry; 137 | carry >>= P256_BITSPERDIGIT; 138 | } 139 | return top + (p256_digit)carry; 140 | } 141 | 142 | // c = a * b mod MOD. c can be a and/or b. 143 | void p256_modmul(const p256_int* MOD, 144 | const p256_int* a, 145 | const p256_digit top_b, 146 | const p256_int* b, 147 | p256_int* c) { 148 | p256_digit tmp[P256_NDIGITS * 2 + 1] = { 0 }; 149 | p256_digit top = 0; 150 | int i; 151 | 152 | // Multiply/add into tmp. 153 | for (i = 0; i < P256_NDIGITS; ++i) { 154 | if (i) tmp[i + P256_NDIGITS - 1] = top; 155 | top = mulAdd(a, P256_DIGIT(b, i), 0, tmp + i); 156 | } 157 | 158 | // Multiply/add top digit 159 | tmp[i + P256_NDIGITS - 1] = top; 160 | top = mulAdd(a, top_b, 0, tmp + i); 161 | 162 | // Reduce tmp, digit by digit. 163 | for (; i >= 0; --i) { 164 | p256_digit reducer[P256_NDIGITS] = { 0 }; 165 | p256_digit top_reducer; 166 | 167 | // top can be any value at this point. 168 | // Guestimate reducer as top * MOD, since msw of MOD is -1. 169 | top_reducer = mulAdd(MOD, top, 0, reducer); 170 | 171 | // Subtract reducer from top | tmp. 172 | top = subTop(top_reducer, reducer, top, tmp + i); 173 | 174 | // top is now either 0 or 1. Make it 0, fixed-timing. 175 | assert(top <= 1); 176 | 177 | top = subM(MOD, top, tmp + i, ~(top - 1)); 178 | 179 | assert(top == 0); 180 | 181 | // We have now reduced the top digit off tmp. Fetch new top digit. 182 | top = tmp[i + P256_NDIGITS - 1]; 183 | } 184 | 185 | // tmp might still be larger than MOD, yet same bit length. 186 | // Make sure it is less, fixed-timing. 187 | addM(MOD, 0, tmp, subM(MOD, 0, tmp, -1)); 188 | 189 | memcpy(c, tmp, P256_NBYTES); 190 | } 191 | int p256_is_odd(const p256_int* a) { return P256_DIGIT(a, 0) & 1; } 192 | int p256_is_even(const p256_int* a) { return !(P256_DIGIT(a, 0) & 1); } 193 | 194 | p256_digit p256_shl(const p256_int* a, int n, p256_int* b) { 195 | int i; 196 | p256_digit top = P256_DIGIT(a, P256_NDIGITS - 1); 197 | 198 | n %= P256_BITSPERDIGIT; 199 | for (i = P256_NDIGITS - 1; i > 0; --i) { 200 | p256_digit accu = (P256_DIGIT(a, i) << n); 201 | accu |= (P256_DIGIT(a, i - 1) >> (P256_BITSPERDIGIT - n)); 202 | P256_DIGIT(b, i) = accu; 203 | } 204 | P256_DIGIT(b, i) = (P256_DIGIT(a, i) << n); 205 | 206 | top = (p256_digit)((((p256_ddigit)top) << n) >> P256_BITSPERDIGIT); 207 | 208 | return top; 209 | } 210 | 211 | void p256_shr(const p256_int* a, int n, p256_int* b) { 212 | int i; 213 | 214 | n %= P256_BITSPERDIGIT; 215 | for (i = 0; i < P256_NDIGITS - 1; ++i) { 216 | p256_digit accu = (P256_DIGIT(a, i) >> n); 217 | accu |= (P256_DIGIT(a, i + 1) << (P256_BITSPERDIGIT - n)); 218 | P256_DIGIT(b, i) = accu; 219 | } 220 | P256_DIGIT(b, i) = (P256_DIGIT(a, i) >> n); 221 | } 222 | 223 | static void p256_shr1(const p256_int* a, int highbit, p256_int* b) { 224 | int i; 225 | 226 | for (i = 0; i < P256_NDIGITS - 1; ++i) { 227 | p256_digit accu = (P256_DIGIT(a, i) >> 1); 228 | accu |= (P256_DIGIT(a, i + 1) << (P256_BITSPERDIGIT - 1)); 229 | P256_DIGIT(b, i) = accu; 230 | } 231 | P256_DIGIT(b, i) = (P256_DIGIT(a, i) >> 1) | 232 | (highbit << (P256_BITSPERDIGIT - 1)); 233 | } 234 | 235 | // Return -1, 0, 1 for a < b, a == b or a > b respectively. 236 | int p256_cmp(const p256_int* a, const p256_int* b) { 237 | int i; 238 | p256_sddigit borrow = 0; 239 | p256_digit notzero = 0; 240 | 241 | for (i = 0; i < P256_NDIGITS; ++i) { 242 | borrow += (p256_sddigit)P256_DIGIT(a, i) - P256_DIGIT(b, i); 243 | // Track whether any result digit is ever not zero. 244 | // Relies on !!(non-zero) evaluating to 1, e.g., !!(-1) evaluating to 1. 245 | notzero |= !!((p256_digit)borrow); 246 | borrow >>= P256_BITSPERDIGIT; 247 | } 248 | return (int)borrow | notzero; 249 | } 250 | 251 | // c = a - b. Returns borrow: 0 or -1. 252 | int p256_sub(const p256_int* a, const p256_int* b, p256_int* c) { 253 | int i; 254 | p256_sddigit borrow = 0; 255 | 256 | for (i = 0; i < P256_NDIGITS; ++i) { 257 | borrow += (p256_sddigit)P256_DIGIT(a, i) - P256_DIGIT(b, i); 258 | if (c) P256_DIGIT(c, i) = (p256_digit)borrow; 259 | borrow >>= P256_BITSPERDIGIT; 260 | } 261 | return (int)borrow; 262 | } 263 | 264 | // c = a + b. Returns carry: 0 or 1. 265 | int p256_add(const p256_int* a, const p256_int* b, p256_int* c) { 266 | int i; 267 | p256_ddigit carry = 0; 268 | 269 | for (i = 0; i < P256_NDIGITS; ++i) { 270 | carry += (p256_ddigit)P256_DIGIT(a, i) + P256_DIGIT(b, i); 271 | if (c) P256_DIGIT(c, i) = (p256_digit)carry; 272 | carry >>= P256_BITSPERDIGIT; 273 | } 274 | return (int)carry; 275 | } 276 | 277 | // b = a + d. Returns carry, 0 or 1. 278 | int p256_add_d(const p256_int* a, p256_digit d, p256_int* b) { 279 | int i; 280 | p256_ddigit carry = d; 281 | 282 | for (i = 0; i < P256_NDIGITS; ++i) { 283 | carry += (p256_ddigit)P256_DIGIT(a, i); 284 | if (b) P256_DIGIT(b, i) = (p256_digit)carry; 285 | carry >>= P256_BITSPERDIGIT; 286 | } 287 | return (int)carry; 288 | } 289 | 290 | // b = 1/a mod MOD, binary euclid. 291 | void p256_modinv_vartime(const p256_int* MOD, 292 | const p256_int* a, 293 | p256_int* b) { 294 | p256_int R = P256_ZERO; 295 | p256_int S = P256_ONE; 296 | p256_int U = *MOD; 297 | p256_int V = *a; 298 | 299 | for (;;) { 300 | if (p256_is_even(&U)) { 301 | p256_shr1(&U, 0, &U); 302 | if (p256_is_even(&R)) { 303 | p256_shr1(&R, 0, &R); 304 | } else { 305 | // R = (R+MOD)/2 306 | p256_shr1(&R, p256_add(&R, MOD, &R), &R); 307 | } 308 | } else if (p256_is_even(&V)) { 309 | p256_shr1(&V, 0, &V); 310 | if (p256_is_even(&S)) { 311 | p256_shr1(&S, 0, &S); 312 | } else { 313 | // S = (S+MOD)/2 314 | p256_shr1(&S, p256_add(&S, MOD, &S) , &S); 315 | } 316 | } else { // U,V both odd. 317 | if (!p256_sub(&V, &U, NULL)) { 318 | p256_sub(&V, &U, &V); 319 | if (p256_sub(&S, &R, &S)) p256_add(&S, MOD, &S); 320 | if (p256_is_zero(&V)) break; // done. 321 | } else { 322 | p256_sub(&U, &V, &U); 323 | if (p256_sub(&R, &S, &R)) p256_add(&R, MOD, &R); 324 | } 325 | } 326 | } 327 | 328 | p256_mod(MOD, &R, b); 329 | } 330 | 331 | void p256_mod(const p256_int* MOD, 332 | const p256_int* in, 333 | p256_int* out) { 334 | if (out != in) *out = *in; 335 | addM(MOD, 0, P256_DIGITS(out), subM(MOD, 0, P256_DIGITS(out), -1)); 336 | } 337 | 338 | // Verify y^2 == x^3 - 3x + b mod p 339 | // and 0 < x < p and 0 < y < p 340 | int p256_is_valid_point(const p256_int* x, const p256_int* y) { 341 | p256_int y2, x3; 342 | 343 | if (p256_cmp(&SECP256r1_p, x) <= 0 || 344 | p256_cmp(&SECP256r1_p, y) <= 0 || 345 | p256_is_zero(x) || 346 | p256_is_zero(y)) return 0; 347 | 348 | p256_modmul(&SECP256r1_p, y, 0, y, &y2); // y^2 349 | 350 | p256_modmul(&SECP256r1_p, x, 0, x, &x3); // x^2 351 | p256_modmul(&SECP256r1_p, x, 0, &x3, &x3); // x^3 352 | if (p256_sub(&x3, x, &x3)) p256_add(&x3, &SECP256r1_p, &x3); // x^3 - x 353 | if (p256_sub(&x3, x, &x3)) p256_add(&x3, &SECP256r1_p, &x3); // x^3 - 2x 354 | if (p256_sub(&x3, x, &x3)) p256_add(&x3, &SECP256r1_p, &x3); // x^3 - 3x 355 | if (p256_add(&x3, &SECP256r1_b, &x3)) // x^3 - 3x + b 356 | p256_sub(&x3, &SECP256r1_p, &x3); 357 | 358 | return p256_cmp(&y2, &x3) == 0; 359 | } 360 | 361 | void p256_from_bin(const uint8_t src[P256_NBYTES], p256_int* dst) { 362 | int i; 363 | const uint8_t* p = &src[0]; 364 | 365 | for (i = P256_NDIGITS - 1; i >= 0; --i) { 366 | P256_DIGIT(dst, i) = 367 | (p[0] << 24) | 368 | (p[1] << 16) | 369 | (p[2] << 8) | 370 | p[3]; 371 | p += 4; 372 | } 373 | } 374 | -------------------------------------------------------------------------------- /deps/libmincrypt/p256_ec.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 The Android Open Source Project 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * * Redistributions of source code must retain the above copyright 7 | * notice, this list of conditions and the following disclaimer. 8 | * * Redistributions in binary form must reproduce the above copyright 9 | * notice, this list of conditions and the following disclaimer in the 10 | * documentation and/or other materials provided with the distribution. 11 | * * Neither the name of Google Inc. nor the names of its contributors may 12 | * be used to endorse or promote products derived from this software 13 | * without specific prior written permission. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR 16 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 17 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 18 | * EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 19 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 21 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 23 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 24 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | // This is an implementation of the P256 elliptic curve group. It's written to 28 | // be portable 32-bit, although it's still constant-time. 29 | // 30 | // WARNING: Implementing these functions in a constant-time manner is far from 31 | // obvious. Be careful when touching this code. 32 | // 33 | // See http://www.imperialviolet.org/2010/12/04/ecc.html ([1]) for background. 34 | 35 | #include 36 | #include 37 | 38 | #include 39 | #include 40 | 41 | #include "mincrypt/p256.h" 42 | 43 | typedef uint8_t u8; 44 | typedef uint32_t u32; 45 | typedef int32_t s32; 46 | typedef uint64_t u64; 47 | 48 | /* Our field elements are represented as nine 32-bit limbs. 49 | * 50 | * The value of an felem (field element) is: 51 | * x[0] + (x[1] * 2**29) + (x[2] * 2**57) + ... + (x[8] * 2**228) 52 | * 53 | * That is, each limb is alternately 29 or 28-bits wide in little-endian 54 | * order. 55 | * 56 | * This means that an felem hits 2**257, rather than 2**256 as we would like. A 57 | * 28, 29, ... pattern would cause us to hit 2**256, but that causes problems 58 | * when multiplying as terms end up one bit short of a limb which would require 59 | * much bit-shifting to correct. 60 | * 61 | * Finally, the values stored in an felem are in Montgomery form. So the value 62 | * |y| is stored as (y*R) mod p, where p is the P-256 prime and R is 2**257. 63 | */ 64 | typedef u32 limb; 65 | #define NLIMBS 9 66 | typedef limb felem[NLIMBS]; 67 | 68 | static const limb kBottom28Bits = 0xfffffff; 69 | static const limb kBottom29Bits = 0x1fffffff; 70 | 71 | /* kOne is the number 1 as an felem. It's 2**257 mod p split up into 29 and 72 | * 28-bit words. */ 73 | static const felem kOne = { 74 | 2, 0, 0, 0xffff800, 75 | 0x1fffffff, 0xfffffff, 0x1fbfffff, 0x1ffffff, 76 | 0 77 | }; 78 | static const felem kZero = {0}; 79 | static const felem kP = { 80 | 0x1fffffff, 0xfffffff, 0x1fffffff, 0x3ff, 81 | 0, 0, 0x200000, 0xf000000, 82 | 0xfffffff 83 | }; 84 | static const felem k2P = { 85 | 0x1ffffffe, 0xfffffff, 0x1fffffff, 0x7ff, 86 | 0, 0, 0x400000, 0xe000000, 87 | 0x1fffffff 88 | }; 89 | /* kPrecomputed contains precomputed values to aid the calculation of scalar 90 | * multiples of the base point, G. It's actually two, equal length, tables 91 | * concatenated. 92 | * 93 | * The first table contains (x,y) felem pairs for 16 multiples of the base 94 | * point, G. 95 | * 96 | * Index | Index (binary) | Value 97 | * 0 | 0000 | 0G (all zeros, omitted) 98 | * 1 | 0001 | G 99 | * 2 | 0010 | 2**64G 100 | * 3 | 0011 | 2**64G + G 101 | * 4 | 0100 | 2**128G 102 | * 5 | 0101 | 2**128G + G 103 | * 6 | 0110 | 2**128G + 2**64G 104 | * 7 | 0111 | 2**128G + 2**64G + G 105 | * 8 | 1000 | 2**192G 106 | * 9 | 1001 | 2**192G + G 107 | * 10 | 1010 | 2**192G + 2**64G 108 | * 11 | 1011 | 2**192G + 2**64G + G 109 | * 12 | 1100 | 2**192G + 2**128G 110 | * 13 | 1101 | 2**192G + 2**128G + G 111 | * 14 | 1110 | 2**192G + 2**128G + 2**64G 112 | * 15 | 1111 | 2**192G + 2**128G + 2**64G + G 113 | * 114 | * The second table follows the same style, but the terms are 2**32G, 115 | * 2**96G, 2**160G, 2**224G. 116 | * 117 | * This is ~2KB of data. */ 118 | static const limb kPrecomputed[NLIMBS * 2 * 15 * 2] = { 119 | 0x11522878, 0xe730d41, 0xdb60179, 0x4afe2ff, 0x12883add, 0xcaddd88, 0x119e7edc, 0xd4a6eab, 0x3120bee, 120 | 0x1d2aac15, 0xf25357c, 0x19e45cdd, 0x5c721d0, 0x1992c5a5, 0xa237487, 0x154ba21, 0x14b10bb, 0xae3fe3, 121 | 0xd41a576, 0x922fc51, 0x234994f, 0x60b60d3, 0x164586ae, 0xce95f18, 0x1fe49073, 0x3fa36cc, 0x5ebcd2c, 122 | 0xb402f2f, 0x15c70bf, 0x1561925c, 0x5a26704, 0xda91e90, 0xcdc1c7f, 0x1ea12446, 0xe1ade1e, 0xec91f22, 123 | 0x26f7778, 0x566847e, 0xa0bec9e, 0x234f453, 0x1a31f21a, 0xd85e75c, 0x56c7109, 0xa267a00, 0xb57c050, 124 | 0x98fb57, 0xaa837cc, 0x60c0792, 0xcfa5e19, 0x61bab9e, 0x589e39b, 0xa324c5, 0x7d6dee7, 0x2976e4b, 125 | 0x1fc4124a, 0xa8c244b, 0x1ce86762, 0xcd61c7e, 0x1831c8e0, 0x75774e1, 0x1d96a5a9, 0x843a649, 0xc3ab0fa, 126 | 0x6e2e7d5, 0x7673a2a, 0x178b65e8, 0x4003e9b, 0x1a1f11c2, 0x7816ea, 0xf643e11, 0x58c43df, 0xf423fc2, 127 | 0x19633ffa, 0x891f2b2, 0x123c231c, 0x46add8c, 0x54700dd, 0x59e2b17, 0x172db40f, 0x83e277d, 0xb0dd609, 128 | 0xfd1da12, 0x35c6e52, 0x19ede20c, 0xd19e0c0, 0x97d0f40, 0xb015b19, 0x449e3f5, 0xe10c9e, 0x33ab581, 129 | 0x56a67ab, 0x577734d, 0x1dddc062, 0xc57b10d, 0x149b39d, 0x26a9e7b, 0xc35df9f, 0x48764cd, 0x76dbcca, 130 | 0xca4b366, 0xe9303ab, 0x1a7480e7, 0x57e9e81, 0x1e13eb50, 0xf466cf3, 0x6f16b20, 0x4ba3173, 0xc168c33, 131 | 0x15cb5439, 0x6a38e11, 0x73658bd, 0xb29564f, 0x3f6dc5b, 0x53b97e, 0x1322c4c0, 0x65dd7ff, 0x3a1e4f6, 132 | 0x14e614aa, 0x9246317, 0x1bc83aca, 0xad97eed, 0xd38ce4a, 0xf82b006, 0x341f077, 0xa6add89, 0x4894acd, 133 | 0x9f162d5, 0xf8410ef, 0x1b266a56, 0xd7f223, 0x3e0cb92, 0xe39b672, 0x6a2901a, 0x69a8556, 0x7e7c0, 134 | 0x9b7d8d3, 0x309a80, 0x1ad05f7f, 0xc2fb5dd, 0xcbfd41d, 0x9ceb638, 0x1051825c, 0xda0cf5b, 0x812e881, 135 | 0x6f35669, 0x6a56f2c, 0x1df8d184, 0x345820, 0x1477d477, 0x1645db1, 0xbe80c51, 0xc22be3e, 0xe35e65a, 136 | 0x1aeb7aa0, 0xc375315, 0xf67bc99, 0x7fdd7b9, 0x191fc1be, 0x61235d, 0x2c184e9, 0x1c5a839, 0x47a1e26, 137 | 0xb7cb456, 0x93e225d, 0x14f3c6ed, 0xccc1ac9, 0x17fe37f3, 0x4988989, 0x1a90c502, 0x2f32042, 0xa17769b, 138 | 0xafd8c7c, 0x8191c6e, 0x1dcdb237, 0x16200c0, 0x107b32a1, 0x66c08db, 0x10d06a02, 0x3fc93, 0x5620023, 139 | 0x16722b27, 0x68b5c59, 0x270fcfc, 0xfad0ecc, 0xe5de1c2, 0xeab466b, 0x2fc513c, 0x407f75c, 0xbaab133, 140 | 0x9705fe9, 0xb88b8e7, 0x734c993, 0x1e1ff8f, 0x19156970, 0xabd0f00, 0x10469ea7, 0x3293ac0, 0xcdc98aa, 141 | 0x1d843fd, 0xe14bfe8, 0x15be825f, 0x8b5212, 0xeb3fb67, 0x81cbd29, 0xbc62f16, 0x2b6fcc7, 0xf5a4e29, 142 | 0x13560b66, 0xc0b6ac2, 0x51ae690, 0xd41e271, 0xf3e9bd4, 0x1d70aab, 0x1029f72, 0x73e1c35, 0xee70fbc, 143 | 0xad81baf, 0x9ecc49a, 0x86c741e, 0xfe6be30, 0x176752e7, 0x23d416, 0x1f83de85, 0x27de188, 0x66f70b8, 144 | 0x181cd51f, 0x96b6e4c, 0x188f2335, 0xa5df759, 0x17a77eb6, 0xfeb0e73, 0x154ae914, 0x2f3ec51, 0x3826b59, 145 | 0xb91f17d, 0x1c72949, 0x1362bf0a, 0xe23fddf, 0xa5614b0, 0xf7d8f, 0x79061, 0x823d9d2, 0x8213f39, 146 | 0x1128ae0b, 0xd095d05, 0xb85c0c2, 0x1ecb2ef, 0x24ddc84, 0xe35e901, 0x18411a4a, 0xf5ddc3d, 0x3786689, 147 | 0x52260e8, 0x5ae3564, 0x542b10d, 0x8d93a45, 0x19952aa4, 0x996cc41, 0x1051a729, 0x4be3499, 0x52b23aa, 148 | 0x109f307e, 0x6f5b6bb, 0x1f84e1e7, 0x77a0cfa, 0x10c4df3f, 0x25a02ea, 0xb048035, 0xe31de66, 0xc6ecaa3, 149 | 0x28ea335, 0x2886024, 0x1372f020, 0xf55d35, 0x15e4684c, 0xf2a9e17, 0x1a4a7529, 0xcb7beb1, 0xb2a78a1, 150 | 0x1ab21f1f, 0x6361ccf, 0x6c9179d, 0xb135627, 0x1267b974, 0x4408bad, 0x1cbff658, 0xe3d6511, 0xc7d76f, 151 | 0x1cc7a69, 0xe7ee31b, 0x54fab4f, 0x2b914f, 0x1ad27a30, 0xcd3579e, 0xc50124c, 0x50daa90, 0xb13f72, 152 | 0xb06aa75, 0x70f5cc6, 0x1649e5aa, 0x84a5312, 0x329043c, 0x41c4011, 0x13d32411, 0xb04a838, 0xd760d2d, 153 | 0x1713b532, 0xbaa0c03, 0x84022ab, 0x6bcf5c1, 0x2f45379, 0x18ae070, 0x18c9e11e, 0x20bca9a, 0x66f496b, 154 | 0x3eef294, 0x67500d2, 0xd7f613c, 0x2dbbeb, 0xb741038, 0xe04133f, 0x1582968d, 0xbe985f7, 0x1acbc1a, 155 | 0x1a6a939f, 0x33e50f6, 0xd665ed4, 0xb4b7bd6, 0x1e5a3799, 0x6b33847, 0x17fa56ff, 0x65ef930, 0x21dc4a, 156 | 0x2b37659, 0x450fe17, 0xb357b65, 0xdf5efac, 0x15397bef, 0x9d35a7f, 0x112ac15f, 0x624e62e, 0xa90ae2f, 157 | 0x107eecd2, 0x1f69bbe, 0x77d6bce, 0x5741394, 0x13c684fc, 0x950c910, 0x725522b, 0xdc78583, 0x40eeabb, 158 | 0x1fde328a, 0xbd61d96, 0xd28c387, 0x9e77d89, 0x12550c40, 0x759cb7d, 0x367ef34, 0xae2a960, 0x91b8bdc, 159 | 0x93462a9, 0xf469ef, 0xb2e9aef, 0xd2ca771, 0x54e1f42, 0x7aaa49, 0x6316abb, 0x2413c8e, 0x5425bf9, 160 | 0x1bed3e3a, 0xf272274, 0x1f5e7326, 0x6416517, 0xea27072, 0x9cedea7, 0x6e7633, 0x7c91952, 0xd806dce, 161 | 0x8e2a7e1, 0xe421e1a, 0x418c9e1, 0x1dbc890, 0x1b395c36, 0xa1dc175, 0x1dc4ef73, 0x8956f34, 0xe4b5cf2, 162 | 0x1b0d3a18, 0x3194a36, 0x6c2641f, 0xe44124c, 0xa2f4eaa, 0xa8c25ba, 0xf927ed7, 0x627b614, 0x7371cca, 163 | 0xba16694, 0x417bc03, 0x7c0a7e3, 0x9c35c19, 0x1168a205, 0x8b6b00d, 0x10e3edc9, 0x9c19bf2, 0x5882229, 164 | 0x1b2b4162, 0xa5cef1a, 0x1543622b, 0x9bd433e, 0x364e04d, 0x7480792, 0x5c9b5b3, 0xe85ff25, 0x408ef57, 165 | 0x1814cfa4, 0x121b41b, 0xd248a0f, 0x3b05222, 0x39bb16a, 0xc75966d, 0xa038113, 0xa4a1769, 0x11fbc6c, 166 | 0x917e50e, 0xeec3da8, 0x169d6eac, 0x10c1699, 0xa416153, 0xf724912, 0x15cd60b7, 0x4acbad9, 0x5efc5fa, 167 | 0xf150ed7, 0x122b51, 0x1104b40a, 0xcb7f442, 0xfbb28ff, 0x6ac53ca, 0x196142cc, 0x7bf0fa9, 0x957651, 168 | 0x4e0f215, 0xed439f8, 0x3f46bd5, 0x5ace82f, 0x110916b6, 0x6db078, 0xffd7d57, 0xf2ecaac, 0xca86dec, 169 | 0x15d6b2da, 0x965ecc9, 0x1c92b4c2, 0x1f3811, 0x1cb080f5, 0x2d8b804, 0x19d1c12d, 0xf20bd46, 0x1951fa7, 170 | 0xa3656c3, 0x523a425, 0xfcd0692, 0xd44ddc8, 0x131f0f5b, 0xaf80e4a, 0xcd9fc74, 0x99bb618, 0x2db944c, 171 | 0xa673090, 0x1c210e1, 0x178c8d23, 0x1474383, 0x10b8743d, 0x985a55b, 0x2e74779, 0x576138, 0x9587927, 172 | 0x133130fa, 0xbe05516, 0x9f4d619, 0xbb62570, 0x99ec591, 0xd9468fe, 0x1d07782d, 0xfc72e0b, 0x701b298, 173 | 0x1863863b, 0x85954b8, 0x121a0c36, 0x9e7fedf, 0xf64b429, 0x9b9d71e, 0x14e2f5d8, 0xf858d3a, 0x942eea8, 174 | 0xda5b765, 0x6edafff, 0xa9d18cc, 0xc65e4ba, 0x1c747e86, 0xe4ea915, 0x1981d7a1, 0x8395659, 0x52ed4e2, 175 | 0x87d43b7, 0x37ab11b, 0x19d292ce, 0xf8d4692, 0x18c3053f, 0x8863e13, 0x4c146c0, 0x6bdf55a, 0x4e4457d, 176 | 0x16152289, 0xac78ec2, 0x1a59c5a2, 0x2028b97, 0x71c2d01, 0x295851f, 0x404747b, 0x878558d, 0x7d29aa4, 177 | 0x13d8341f, 0x8daefd7, 0x139c972d, 0x6b7ea75, 0xd4a9dde, 0xff163d8, 0x81d55d7, 0xa5bef68, 0xb7b30d8, 178 | 0xbe73d6f, 0xaa88141, 0xd976c81, 0x7e7a9cc, 0x18beb771, 0xd773cbd, 0x13f51951, 0x9d0c177, 0x1c49a78, 179 | }; 180 | 181 | 182 | /* Field element operations: */ 183 | 184 | /* NON_ZERO_TO_ALL_ONES returns: 185 | * 0xffffffff for 0 < x <= 2**31 186 | * 0 for x == 0 or x > 2**31. 187 | * 188 | * x must be a u32 or an equivalent type such as limb. */ 189 | #define NON_ZERO_TO_ALL_ONES(x) ((((u32)(x) - 1) >> 31) - 1) 190 | 191 | /* felem_reduce_carry adds a multiple of p in order to cancel |carry|, 192 | * which is a term at 2**257. 193 | * 194 | * On entry: carry < 2**3, inout[0,2,...] < 2**29, inout[1,3,...] < 2**28. 195 | * On exit: inout[0,2,..] < 2**30, inout[1,3,...] < 2**29. */ 196 | static void felem_reduce_carry(felem inout, limb carry) { 197 | const u32 carry_mask = NON_ZERO_TO_ALL_ONES(carry); 198 | 199 | inout[0] += carry << 1; 200 | inout[3] += 0x10000000 & carry_mask; 201 | /* carry < 2**3 thus (carry << 11) < 2**14 and we added 2**28 in the 202 | * previous line therefore this doesn't underflow. */ 203 | inout[3] -= carry << 11; 204 | inout[4] += (0x20000000 - 1) & carry_mask; 205 | inout[5] += (0x10000000 - 1) & carry_mask; 206 | inout[6] += (0x20000000 - 1) & carry_mask; 207 | inout[6] -= carry << 22; 208 | /* This may underflow if carry is non-zero but, if so, we'll fix it in the 209 | * next line. */ 210 | inout[7] -= 1 & carry_mask; 211 | inout[7] += carry << 25; 212 | } 213 | 214 | /* felem_sum sets out = in+in2. 215 | * 216 | * On entry, in[i]+in2[i] must not overflow a 32-bit word. 217 | * On exit: out[0,2,...] < 2**30, out[1,3,...] < 2**29 */ 218 | static void felem_sum(felem out, const felem in, const felem in2) { 219 | limb carry = 0; 220 | unsigned i; 221 | 222 | for (i = 0;; i++) { 223 | out[i] = in[i] + in2[i]; 224 | out[i] += carry; 225 | carry = out[i] >> 29; 226 | out[i] &= kBottom29Bits; 227 | 228 | i++; 229 | if (i == NLIMBS) 230 | break; 231 | 232 | out[i] = in[i] + in2[i]; 233 | out[i] += carry; 234 | carry = out[i] >> 28; 235 | out[i] &= kBottom28Bits; 236 | } 237 | 238 | felem_reduce_carry(out, carry); 239 | } 240 | 241 | #define two31m3 (((limb)1) << 31) - (((limb)1) << 3) 242 | #define two30m2 (((limb)1) << 30) - (((limb)1) << 2) 243 | #define two30p13m2 (((limb)1) << 30) + (((limb)1) << 13) - (((limb)1) << 2) 244 | #define two31m2 (((limb)1) << 31) - (((limb)1) << 2) 245 | #define two31p24m2 (((limb)1) << 31) + (((limb)1) << 24) - (((limb)1) << 2) 246 | #define two30m27m2 (((limb)1) << 30) - (((limb)1) << 27) - (((limb)1) << 2) 247 | 248 | /* zero31 is 0 mod p. */ 249 | static const felem zero31 = { two31m3, two30m2, two31m2, two30p13m2, two31m2, two30m2, two31p24m2, two30m27m2, two31m2 }; 250 | 251 | /* felem_diff sets out = in-in2. 252 | * 253 | * On entry: in[0,2,...] < 2**30, in[1,3,...] < 2**29 and 254 | * in2[0,2,...] < 2**30, in2[1,3,...] < 2**29. 255 | * On exit: out[0,2,...] < 2**30, out[1,3,...] < 2**29. */ 256 | static void felem_diff(felem out, const felem in, const felem in2) { 257 | limb carry = 0; 258 | unsigned i; 259 | 260 | for (i = 0;; i++) { 261 | out[i] = in[i] - in2[i]; 262 | out[i] += zero31[i]; 263 | out[i] += carry; 264 | carry = out[i] >> 29; 265 | out[i] &= kBottom29Bits; 266 | 267 | i++; 268 | if (i == NLIMBS) 269 | break; 270 | 271 | out[i] = in[i] - in2[i]; 272 | out[i] += zero31[i]; 273 | out[i] += carry; 274 | carry = out[i] >> 28; 275 | out[i] &= kBottom28Bits; 276 | } 277 | 278 | felem_reduce_carry(out, carry); 279 | } 280 | 281 | /* felem_reduce_degree sets out = tmp/R mod p where tmp contains 64-bit words 282 | * with the same 29,28,... bit positions as an felem. 283 | * 284 | * The values in felems are in Montgomery form: x*R mod p where R = 2**257. 285 | * Since we just multiplied two Montgomery values together, the result is 286 | * x*y*R*R mod p. We wish to divide by R in order for the result also to be 287 | * in Montgomery form. 288 | * 289 | * On entry: tmp[i] < 2**64 290 | * On exit: out[0,2,...] < 2**30, out[1,3,...] < 2**29 */ 291 | static void felem_reduce_degree(felem out, u64 tmp[17]) { 292 | /* The following table may be helpful when reading this code: 293 | * 294 | * Limb number: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10... 295 | * Width (bits): 29| 28| 29| 28| 29| 28| 29| 28| 29| 28| 29 296 | * Start bit: 0 | 29| 57| 86|114|143|171|200|228|257|285 297 | * (odd phase): 0 | 28| 57| 85|114|142|171|199|228|256|285 */ 298 | limb tmp2[18], carry, x, xMask; 299 | unsigned i; 300 | 301 | /* tmp contains 64-bit words with the same 29,28,29-bit positions as an 302 | * felem. So the top of an element of tmp might overlap with another 303 | * element two positions down. The following loop eliminates this 304 | * overlap. */ 305 | tmp2[0] = (limb)(tmp[0] & kBottom29Bits); 306 | 307 | /* In the following we use "(limb) tmp[x]" and "(limb) (tmp[x]>>32)" to try 308 | * and hint to the compiler that it can do a single-word shift by selecting 309 | * the right register rather than doing a double-word shift and truncating 310 | * afterwards. */ 311 | tmp2[1] = ((limb) tmp[0]) >> 29; 312 | tmp2[1] |= (((limb)(tmp[0] >> 32)) << 3) & kBottom28Bits; 313 | tmp2[1] += ((limb) tmp[1]) & kBottom28Bits; 314 | carry = tmp2[1] >> 28; 315 | tmp2[1] &= kBottom28Bits; 316 | 317 | for (i = 2; i < 17; i++) { 318 | tmp2[i] = ((limb)(tmp[i - 2] >> 32)) >> 25; 319 | tmp2[i] += ((limb)(tmp[i - 1])) >> 28; 320 | tmp2[i] += (((limb)(tmp[i - 1] >> 32)) << 4) & kBottom29Bits; 321 | tmp2[i] += ((limb) tmp[i]) & kBottom29Bits; 322 | tmp2[i] += carry; 323 | carry = tmp2[i] >> 29; 324 | tmp2[i] &= kBottom29Bits; 325 | 326 | i++; 327 | if (i == 17) 328 | break; 329 | tmp2[i] = ((limb)(tmp[i - 2] >> 32)) >> 25; 330 | tmp2[i] += ((limb)(tmp[i - 1])) >> 29; 331 | tmp2[i] += (((limb)(tmp[i - 1] >> 32)) << 3) & kBottom28Bits; 332 | tmp2[i] += ((limb) tmp[i]) & kBottom28Bits; 333 | tmp2[i] += carry; 334 | carry = tmp2[i] >> 28; 335 | tmp2[i] &= kBottom28Bits; 336 | } 337 | 338 | tmp2[17] = ((limb)(tmp[15] >> 32)) >> 25; 339 | tmp2[17] += ((limb)(tmp[16])) >> 29; 340 | tmp2[17] += (((limb)(tmp[16] >> 32)) << 3); 341 | tmp2[17] += carry; 342 | 343 | /* Montgomery elimination of terms. 344 | * 345 | * Since R is 2**257, we can divide by R with a bitwise shift if we can 346 | * ensure that the right-most 257 bits are all zero. We can make that true by 347 | * adding multiplies of p without affecting the value. 348 | * 349 | * So we eliminate limbs from right to left. Since the bottom 29 bits of p 350 | * are all ones, then by adding tmp2[0]*p to tmp2 we'll make tmp2[0] == 0. 351 | * We can do that for 8 further limbs and then right shift to eliminate the 352 | * extra factor of R. */ 353 | for (i = 0;; i += 2) { 354 | tmp2[i + 1] += tmp2[i] >> 29; 355 | x = tmp2[i] & kBottom29Bits; 356 | xMask = NON_ZERO_TO_ALL_ONES(x); 357 | tmp2[i] = 0; 358 | 359 | /* The bounds calculations for this loop are tricky. Each iteration of 360 | * the loop eliminates two words by adding values to words to their 361 | * right. 362 | * 363 | * The following table contains the amounts added to each word (as an 364 | * offset from the value of i at the top of the loop). The amounts are 365 | * accounted for from the first and second half of the loop separately 366 | * and are written as, for example, 28 to mean a value <2**28. 367 | * 368 | * Word: 3 4 5 6 7 8 9 10 369 | * Added in top half: 28 11 29 21 29 28 370 | * 28 29 371 | * 29 372 | * Added in bottom half: 29 10 28 21 28 28 373 | * 29 374 | * 375 | * The value that is currently offset 7 will be offset 5 for the next 376 | * iteration and then offset 3 for the iteration after that. Therefore 377 | * the total value added will be the values added at 7, 5 and 3. 378 | * 379 | * The following table accumulates these values. The sums at the bottom 380 | * are written as, for example, 29+28, to mean a value < 2**29+2**28. 381 | * 382 | * Word: 3 4 5 6 7 8 9 10 11 12 13 383 | * 28 11 10 29 21 29 28 28 28 28 28 384 | * 29 28 11 28 29 28 29 28 29 28 385 | * 29 28 21 21 29 21 29 21 386 | * 10 29 28 21 28 21 28 387 | * 28 29 28 29 28 29 28 388 | * 11 10 29 10 29 10 389 | * 29 28 11 28 11 390 | * 29 29 391 | * -------------------------------------------- 392 | * 30+ 31+ 30+ 31+ 30+ 393 | * 28+ 29+ 28+ 29+ 21+ 394 | * 21+ 28+ 21+ 28+ 10 395 | * 10 21+ 10 21+ 396 | * 11 11 397 | * 398 | * So the greatest amount is added to tmp2[10] and tmp2[12]. If 399 | * tmp2[10/12] has an initial value of <2**29, then the maximum value 400 | * will be < 2**31 + 2**30 + 2**28 + 2**21 + 2**11, which is < 2**32, 401 | * as required. */ 402 | tmp2[i + 3] += (x << 10) & kBottom28Bits; 403 | tmp2[i + 4] += (x >> 18); 404 | 405 | tmp2[i + 6] += (x << 21) & kBottom29Bits; 406 | tmp2[i + 7] += x >> 8; 407 | 408 | /* At position 200, which is the starting bit position for word 7, we 409 | * have a factor of 0xf000000 = 2**28 - 2**24. */ 410 | tmp2[i + 7] += 0x10000000 & xMask; 411 | /* Word 7 is 28 bits wide, so the 2**28 term exactly hits word 8. */ 412 | tmp2[i + 8] += (x - 1) & xMask; 413 | tmp2[i + 7] -= (x << 24) & kBottom28Bits; 414 | tmp2[i + 8] -= x >> 4; 415 | 416 | tmp2[i + 8] += 0x20000000 & xMask; 417 | tmp2[i + 8] -= x; 418 | tmp2[i + 8] += (x << 28) & kBottom29Bits; 419 | tmp2[i + 9] += ((x >> 1) - 1) & xMask; 420 | 421 | if (i+1 == NLIMBS) 422 | break; 423 | tmp2[i + 2] += tmp2[i + 1] >> 28; 424 | x = tmp2[i + 1] & kBottom28Bits; 425 | xMask = NON_ZERO_TO_ALL_ONES(x); 426 | tmp2[i + 1] = 0; 427 | 428 | tmp2[i + 4] += (x << 11) & kBottom29Bits; 429 | tmp2[i + 5] += (x >> 18); 430 | 431 | tmp2[i + 7] += (x << 21) & kBottom28Bits; 432 | tmp2[i + 8] += x >> 7; 433 | 434 | /* At position 199, which is the starting bit of the 8th word when 435 | * dealing with a context starting on an odd word, we have a factor of 436 | * 0x1e000000 = 2**29 - 2**25. Since we have not updated i, the 8th 437 | * word from i+1 is i+8. */ 438 | tmp2[i + 8] += 0x20000000 & xMask; 439 | tmp2[i + 9] += (x - 1) & xMask; 440 | tmp2[i + 8] -= (x << 25) & kBottom29Bits; 441 | tmp2[i + 9] -= x >> 4; 442 | 443 | tmp2[i + 9] += 0x10000000 & xMask; 444 | tmp2[i + 9] -= x; 445 | tmp2[i + 10] += (x - 1) & xMask; 446 | } 447 | 448 | /* We merge the right shift with a carry chain. The words above 2**257 have 449 | * widths of 28,29,... which we need to correct when copying them down. */ 450 | carry = 0; 451 | for (i = 0; i < 8; i++) { 452 | /* The maximum value of tmp2[i + 9] occurs on the first iteration and 453 | * is < 2**30+2**29+2**28. Adding 2**29 (from tmp2[i + 10]) is 454 | * therefore safe. */ 455 | out[i] = tmp2[i + 9]; 456 | out[i] += carry; 457 | out[i] += (tmp2[i + 10] << 28) & kBottom29Bits; 458 | carry = out[i] >> 29; 459 | out[i] &= kBottom29Bits; 460 | 461 | i++; 462 | out[i] = tmp2[i + 9] >> 1; 463 | out[i] += carry; 464 | carry = out[i] >> 28; 465 | out[i] &= kBottom28Bits; 466 | } 467 | 468 | out[8] = tmp2[17]; 469 | out[8] += carry; 470 | carry = out[8] >> 29; 471 | out[8] &= kBottom29Bits; 472 | 473 | felem_reduce_carry(out, carry); 474 | } 475 | 476 | /* felem_square sets out=in*in. 477 | * 478 | * On entry: in[0,2,...] < 2**30, in[1,3,...] < 2**29. 479 | * On exit: out[0,2,...] < 2**30, out[1,3,...] < 2**29. */ 480 | static void felem_square(felem out, const felem in) { 481 | u64 tmp[17]; 482 | 483 | tmp[0] = ((u64) in[0]) * in[0]; 484 | tmp[1] = ((u64) in[0]) * (in[1] << 1); 485 | tmp[2] = ((u64) in[0]) * (in[2] << 1) + 486 | ((u64) in[1]) * (in[1] << 1); 487 | tmp[3] = ((u64) in[0]) * (in[3] << 1) + 488 | ((u64) in[1]) * (in[2] << 1); 489 | tmp[4] = ((u64) in[0]) * (in[4] << 1) + 490 | ((u64) in[1]) * (in[3] << 2) + ((u64) in[2]) * in[2]; 491 | tmp[5] = ((u64) in[0]) * (in[5] << 1) + ((u64) in[1]) * 492 | (in[4] << 1) + ((u64) in[2]) * (in[3] << 1); 493 | tmp[6] = ((u64) in[0]) * (in[6] << 1) + ((u64) in[1]) * 494 | (in[5] << 2) + ((u64) in[2]) * (in[4] << 1) + 495 | ((u64) in[3]) * (in[3] << 1); 496 | tmp[7] = ((u64) in[0]) * (in[7] << 1) + ((u64) in[1]) * 497 | (in[6] << 1) + ((u64) in[2]) * (in[5] << 1) + 498 | ((u64) in[3]) * (in[4] << 1); 499 | /* tmp[8] has the greatest value of 2**61 + 2**60 + 2**61 + 2**60 + 2**60, 500 | * which is < 2**64 as required. */ 501 | tmp[8] = ((u64) in[0]) * (in[8] << 1) + ((u64) in[1]) * 502 | (in[7] << 2) + ((u64) in[2]) * (in[6] << 1) + 503 | ((u64) in[3]) * (in[5] << 2) + ((u64) in[4]) * in[4]; 504 | tmp[9] = ((u64) in[1]) * (in[8] << 1) + ((u64) in[2]) * 505 | (in[7] << 1) + ((u64) in[3]) * (in[6] << 1) + 506 | ((u64) in[4]) * (in[5] << 1); 507 | tmp[10] = ((u64) in[2]) * (in[8] << 1) + ((u64) in[3]) * 508 | (in[7] << 2) + ((u64) in[4]) * (in[6] << 1) + 509 | ((u64) in[5]) * (in[5] << 1); 510 | tmp[11] = ((u64) in[3]) * (in[8] << 1) + ((u64) in[4]) * 511 | (in[7] << 1) + ((u64) in[5]) * (in[6] << 1); 512 | tmp[12] = ((u64) in[4]) * (in[8] << 1) + 513 | ((u64) in[5]) * (in[7] << 2) + ((u64) in[6]) * in[6]; 514 | tmp[13] = ((u64) in[5]) * (in[8] << 1) + 515 | ((u64) in[6]) * (in[7] << 1); 516 | tmp[14] = ((u64) in[6]) * (in[8] << 1) + 517 | ((u64) in[7]) * (in[7] << 1); 518 | tmp[15] = ((u64) in[7]) * (in[8] << 1); 519 | tmp[16] = ((u64) in[8]) * in[8]; 520 | 521 | felem_reduce_degree(out, tmp); 522 | } 523 | 524 | /* felem_mul sets out=in*in2. 525 | * 526 | * On entry: in[0,2,...] < 2**30, in[1,3,...] < 2**29 and 527 | * in2[0,2,...] < 2**30, in2[1,3,...] < 2**29. 528 | * On exit: out[0,2,...] < 2**30, out[1,3,...] < 2**29. */ 529 | static void felem_mul(felem out, const felem in, const felem in2) { 530 | u64 tmp[17]; 531 | 532 | tmp[0] = ((u64) in[0]) * in2[0]; 533 | tmp[1] = ((u64) in[0]) * (in2[1] << 0) + 534 | ((u64) in[1]) * (in2[0] << 0); 535 | tmp[2] = ((u64) in[0]) * (in2[2] << 0) + ((u64) in[1]) * 536 | (in2[1] << 1) + ((u64) in[2]) * (in2[0] << 0); 537 | tmp[3] = ((u64) in[0]) * (in2[3] << 0) + ((u64) in[1]) * 538 | (in2[2] << 0) + ((u64) in[2]) * (in2[1] << 0) + 539 | ((u64) in[3]) * (in2[0] << 0); 540 | tmp[4] = ((u64) in[0]) * (in2[4] << 0) + ((u64) in[1]) * 541 | (in2[3] << 1) + ((u64) in[2]) * (in2[2] << 0) + 542 | ((u64) in[3]) * (in2[1] << 1) + 543 | ((u64) in[4]) * (in2[0] << 0); 544 | tmp[5] = ((u64) in[0]) * (in2[5] << 0) + ((u64) in[1]) * 545 | (in2[4] << 0) + ((u64) in[2]) * (in2[3] << 0) + 546 | ((u64) in[3]) * (in2[2] << 0) + ((u64) in[4]) * 547 | (in2[1] << 0) + ((u64) in[5]) * (in2[0] << 0); 548 | tmp[6] = ((u64) in[0]) * (in2[6] << 0) + ((u64) in[1]) * 549 | (in2[5] << 1) + ((u64) in[2]) * (in2[4] << 0) + 550 | ((u64) in[3]) * (in2[3] << 1) + ((u64) in[4]) * 551 | (in2[2] << 0) + ((u64) in[5]) * (in2[1] << 1) + 552 | ((u64) in[6]) * (in2[0] << 0); 553 | tmp[7] = ((u64) in[0]) * (in2[7] << 0) + ((u64) in[1]) * 554 | (in2[6] << 0) + ((u64) in[2]) * (in2[5] << 0) + 555 | ((u64) in[3]) * (in2[4] << 0) + ((u64) in[4]) * 556 | (in2[3] << 0) + ((u64) in[5]) * (in2[2] << 0) + 557 | ((u64) in[6]) * (in2[1] << 0) + 558 | ((u64) in[7]) * (in2[0] << 0); 559 | /* tmp[8] has the greatest value but doesn't overflow. See logic in 560 | * felem_square. */ 561 | tmp[8] = ((u64) in[0]) * (in2[8] << 0) + ((u64) in[1]) * 562 | (in2[7] << 1) + ((u64) in[2]) * (in2[6] << 0) + 563 | ((u64) in[3]) * (in2[5] << 1) + ((u64) in[4]) * 564 | (in2[4] << 0) + ((u64) in[5]) * (in2[3] << 1) + 565 | ((u64) in[6]) * (in2[2] << 0) + ((u64) in[7]) * 566 | (in2[1] << 1) + ((u64) in[8]) * (in2[0] << 0); 567 | tmp[9] = ((u64) in[1]) * (in2[8] << 0) + ((u64) in[2]) * 568 | (in2[7] << 0) + ((u64) in[3]) * (in2[6] << 0) + 569 | ((u64) in[4]) * (in2[5] << 0) + ((u64) in[5]) * 570 | (in2[4] << 0) + ((u64) in[6]) * (in2[3] << 0) + 571 | ((u64) in[7]) * (in2[2] << 0) + 572 | ((u64) in[8]) * (in2[1] << 0); 573 | tmp[10] = ((u64) in[2]) * (in2[8] << 0) + ((u64) in[3]) * 574 | (in2[7] << 1) + ((u64) in[4]) * (in2[6] << 0) + 575 | ((u64) in[5]) * (in2[5] << 1) + ((u64) in[6]) * 576 | (in2[4] << 0) + ((u64) in[7]) * (in2[3] << 1) + 577 | ((u64) in[8]) * (in2[2] << 0); 578 | tmp[11] = ((u64) in[3]) * (in2[8] << 0) + ((u64) in[4]) * 579 | (in2[7] << 0) + ((u64) in[5]) * (in2[6] << 0) + 580 | ((u64) in[6]) * (in2[5] << 0) + ((u64) in[7]) * 581 | (in2[4] << 0) + ((u64) in[8]) * (in2[3] << 0); 582 | tmp[12] = ((u64) in[4]) * (in2[8] << 0) + ((u64) in[5]) * 583 | (in2[7] << 1) + ((u64) in[6]) * (in2[6] << 0) + 584 | ((u64) in[7]) * (in2[5] << 1) + 585 | ((u64) in[8]) * (in2[4] << 0); 586 | tmp[13] = ((u64) in[5]) * (in2[8] << 0) + ((u64) in[6]) * 587 | (in2[7] << 0) + ((u64) in[7]) * (in2[6] << 0) + 588 | ((u64) in[8]) * (in2[5] << 0); 589 | tmp[14] = ((u64) in[6]) * (in2[8] << 0) + ((u64) in[7]) * 590 | (in2[7] << 1) + ((u64) in[8]) * (in2[6] << 0); 591 | tmp[15] = ((u64) in[7]) * (in2[8] << 0) + 592 | ((u64) in[8]) * (in2[7] << 0); 593 | tmp[16] = ((u64) in[8]) * (in2[8] << 0); 594 | 595 | felem_reduce_degree(out, tmp); 596 | } 597 | 598 | static void felem_assign(felem out, const felem in) { 599 | memcpy(out, in, sizeof(felem)); 600 | } 601 | 602 | /* felem_inv calculates |out| = |in|^{-1} 603 | * 604 | * Based on Fermat's Little Theorem: 605 | * a^p = a (mod p) 606 | * a^{p-1} = 1 (mod p) 607 | * a^{p-2} = a^{-1} (mod p) 608 | */ 609 | static void felem_inv(felem out, const felem in) { 610 | felem ftmp, ftmp2; 611 | /* each e_I will hold |in|^{2^I - 1} */ 612 | felem e2, e4, e8, e16, e32, e64; 613 | unsigned i; 614 | 615 | felem_square(ftmp, in); /* 2^1 */ 616 | felem_mul(ftmp, in, ftmp); /* 2^2 - 2^0 */ 617 | felem_assign(e2, ftmp); 618 | felem_square(ftmp, ftmp); /* 2^3 - 2^1 */ 619 | felem_square(ftmp, ftmp); /* 2^4 - 2^2 */ 620 | felem_mul(ftmp, ftmp, e2); /* 2^4 - 2^0 */ 621 | felem_assign(e4, ftmp); 622 | felem_square(ftmp, ftmp); /* 2^5 - 2^1 */ 623 | felem_square(ftmp, ftmp); /* 2^6 - 2^2 */ 624 | felem_square(ftmp, ftmp); /* 2^7 - 2^3 */ 625 | felem_square(ftmp, ftmp); /* 2^8 - 2^4 */ 626 | felem_mul(ftmp, ftmp, e4); /* 2^8 - 2^0 */ 627 | felem_assign(e8, ftmp); 628 | for (i = 0; i < 8; i++) { 629 | felem_square(ftmp, ftmp); 630 | } /* 2^16 - 2^8 */ 631 | felem_mul(ftmp, ftmp, e8); /* 2^16 - 2^0 */ 632 | felem_assign(e16, ftmp); 633 | for (i = 0; i < 16; i++) { 634 | felem_square(ftmp, ftmp); 635 | } /* 2^32 - 2^16 */ 636 | felem_mul(ftmp, ftmp, e16); /* 2^32 - 2^0 */ 637 | felem_assign(e32, ftmp); 638 | for (i = 0; i < 32; i++) { 639 | felem_square(ftmp, ftmp); 640 | } /* 2^64 - 2^32 */ 641 | felem_assign(e64, ftmp); 642 | felem_mul(ftmp, ftmp, in); /* 2^64 - 2^32 + 2^0 */ 643 | for (i = 0; i < 192; i++) { 644 | felem_square(ftmp, ftmp); 645 | } /* 2^256 - 2^224 + 2^192 */ 646 | 647 | felem_mul(ftmp2, e64, e32); /* 2^64 - 2^0 */ 648 | for (i = 0; i < 16; i++) { 649 | felem_square(ftmp2, ftmp2); 650 | } /* 2^80 - 2^16 */ 651 | felem_mul(ftmp2, ftmp2, e16); /* 2^80 - 2^0 */ 652 | for (i = 0; i < 8; i++) { 653 | felem_square(ftmp2, ftmp2); 654 | } /* 2^88 - 2^8 */ 655 | felem_mul(ftmp2, ftmp2, e8); /* 2^88 - 2^0 */ 656 | for (i = 0; i < 4; i++) { 657 | felem_square(ftmp2, ftmp2); 658 | } /* 2^92 - 2^4 */ 659 | felem_mul(ftmp2, ftmp2, e4); /* 2^92 - 2^0 */ 660 | felem_square(ftmp2, ftmp2); /* 2^93 - 2^1 */ 661 | felem_square(ftmp2, ftmp2); /* 2^94 - 2^2 */ 662 | felem_mul(ftmp2, ftmp2, e2); /* 2^94 - 2^0 */ 663 | felem_square(ftmp2, ftmp2); /* 2^95 - 2^1 */ 664 | felem_square(ftmp2, ftmp2); /* 2^96 - 2^2 */ 665 | felem_mul(ftmp2, ftmp2, in); /* 2^96 - 3 */ 666 | 667 | felem_mul(out, ftmp2, ftmp); /* 2^256 - 2^224 + 2^192 + 2^96 - 3 */ 668 | } 669 | 670 | /* felem_scalar_3 sets out=3*out. 671 | * 672 | * On entry: out[0,2,...] < 2**30, out[1,3,...] < 2**29. 673 | * On exit: out[0,2,...] < 2**30, out[1,3,...] < 2**29. */ 674 | static void felem_scalar_3(felem out) { 675 | limb carry = 0; 676 | unsigned i; 677 | 678 | for (i = 0;; i++) { 679 | out[i] *= 3; 680 | out[i] += carry; 681 | carry = out[i] >> 29; 682 | out[i] &= kBottom29Bits; 683 | 684 | i++; 685 | if (i == NLIMBS) 686 | break; 687 | 688 | out[i] *= 3; 689 | out[i] += carry; 690 | carry = out[i] >> 28; 691 | out[i] &= kBottom28Bits; 692 | } 693 | 694 | felem_reduce_carry(out, carry); 695 | } 696 | 697 | /* felem_scalar_4 sets out=4*out. 698 | * 699 | * On entry: out[0,2,...] < 2**30, out[1,3,...] < 2**29. 700 | * On exit: out[0,2,...] < 2**30, out[1,3,...] < 2**29. */ 701 | static void felem_scalar_4(felem out) { 702 | limb carry = 0, next_carry; 703 | unsigned i; 704 | 705 | for (i = 0;; i++) { 706 | next_carry = out[i] >> 27; 707 | out[i] <<= 2; 708 | out[i] &= kBottom29Bits; 709 | out[i] += carry; 710 | carry = next_carry + (out[i] >> 29); 711 | out[i] &= kBottom29Bits; 712 | 713 | i++; 714 | if (i == NLIMBS) 715 | break; 716 | 717 | next_carry = out[i] >> 26; 718 | out[i] <<= 2; 719 | out[i] &= kBottom28Bits; 720 | out[i] += carry; 721 | carry = next_carry + (out[i] >> 28); 722 | out[i] &= kBottom28Bits; 723 | } 724 | 725 | felem_reduce_carry(out, carry); 726 | } 727 | 728 | /* felem_scalar_8 sets out=8*out. 729 | * 730 | * On entry: out[0,2,...] < 2**30, out[1,3,...] < 2**29. 731 | * On exit: out[0,2,...] < 2**30, out[1,3,...] < 2**29. */ 732 | static void felem_scalar_8(felem out) { 733 | limb carry = 0, next_carry; 734 | unsigned i; 735 | 736 | for (i = 0;; i++) { 737 | next_carry = out[i] >> 26; 738 | out[i] <<= 3; 739 | out[i] &= kBottom29Bits; 740 | out[i] += carry; 741 | carry = next_carry + (out[i] >> 29); 742 | out[i] &= kBottom29Bits; 743 | 744 | i++; 745 | if (i == NLIMBS) 746 | break; 747 | 748 | next_carry = out[i] >> 25; 749 | out[i] <<= 3; 750 | out[i] &= kBottom28Bits; 751 | out[i] += carry; 752 | carry = next_carry + (out[i] >> 28); 753 | out[i] &= kBottom28Bits; 754 | } 755 | 756 | felem_reduce_carry(out, carry); 757 | } 758 | 759 | /* felem_is_zero_vartime returns 1 iff |in| == 0. It takes a variable amount of 760 | * time depending on the value of |in|. */ 761 | static char felem_is_zero_vartime(const felem in) { 762 | limb carry; 763 | int i; 764 | limb tmp[NLIMBS]; 765 | 766 | felem_assign(tmp, in); 767 | 768 | /* First, reduce tmp to a minimal form. */ 769 | do { 770 | carry = 0; 771 | for (i = 0;; i++) { 772 | tmp[i] += carry; 773 | carry = tmp[i] >> 29; 774 | tmp[i] &= kBottom29Bits; 775 | 776 | i++; 777 | if (i == NLIMBS) 778 | break; 779 | 780 | tmp[i] += carry; 781 | carry = tmp[i] >> 28; 782 | tmp[i] &= kBottom28Bits; 783 | } 784 | 785 | felem_reduce_carry(tmp, carry); 786 | } while (carry); 787 | 788 | /* tmp < 2**257, so the only possible zero values are 0, p and 2p. */ 789 | return memcmp(tmp, kZero, sizeof(tmp)) == 0 || 790 | memcmp(tmp, kP, sizeof(tmp)) == 0 || 791 | memcmp(tmp, k2P, sizeof(tmp)) == 0; 792 | } 793 | 794 | 795 | /* Group operations: 796 | * 797 | * Elements of the elliptic curve group are represented in Jacobian 798 | * coordinates: (x, y, z). An affine point (x', y') is x'=x/z**2, y'=y/z**3 in 799 | * Jacobian form. */ 800 | 801 | /* point_double sets {x_out,y_out,z_out} = 2*{x,y,z}. 802 | * 803 | * See http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-dbl-2009-l */ 804 | static void point_double(felem x_out, felem y_out, felem z_out, const felem x, 805 | const felem y, const felem z) { 806 | felem delta, gamma, alpha, beta, tmp, tmp2; 807 | 808 | felem_square(delta, z); 809 | felem_square(gamma, y); 810 | felem_mul(beta, x, gamma); 811 | 812 | felem_sum(tmp, x, delta); 813 | felem_diff(tmp2, x, delta); 814 | felem_mul(alpha, tmp, tmp2); 815 | felem_scalar_3(alpha); 816 | 817 | felem_sum(tmp, y, z); 818 | felem_square(tmp, tmp); 819 | felem_diff(tmp, tmp, gamma); 820 | felem_diff(z_out, tmp, delta); 821 | 822 | felem_scalar_4(beta); 823 | felem_square(x_out, alpha); 824 | felem_diff(x_out, x_out, beta); 825 | felem_diff(x_out, x_out, beta); 826 | 827 | felem_diff(tmp, beta, x_out); 828 | felem_mul(tmp, alpha, tmp); 829 | felem_square(tmp2, gamma); 830 | felem_scalar_8(tmp2); 831 | felem_diff(y_out, tmp, tmp2); 832 | } 833 | 834 | /* point_add_mixed sets {x_out,y_out,z_out} = {x1,y1,z1} + {x2,y2,1}. 835 | * (i.e. the second point is affine.) 836 | * 837 | * See http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-add-2007-bl 838 | * 839 | * Note that this function does not handle P+P, infinity+P nor P+infinity 840 | * correctly. */ 841 | static void point_add_mixed(felem x_out, felem y_out, felem z_out, 842 | const felem x1, const felem y1, const felem z1, 843 | const felem x2, const felem y2) { 844 | felem z1z1, z1z1z1, s2, u2, h, i, j, r, rr, v, tmp; 845 | 846 | felem_square(z1z1, z1); 847 | felem_sum(tmp, z1, z1); 848 | 849 | felem_mul(u2, x2, z1z1); 850 | felem_mul(z1z1z1, z1, z1z1); 851 | felem_mul(s2, y2, z1z1z1); 852 | felem_diff(h, u2, x1); 853 | felem_sum(i, h, h); 854 | felem_square(i, i); 855 | felem_mul(j, h, i); 856 | felem_diff(r, s2, y1); 857 | felem_sum(r, r, r); 858 | felem_mul(v, x1, i); 859 | 860 | felem_mul(z_out, tmp, h); 861 | felem_square(rr, r); 862 | felem_diff(x_out, rr, j); 863 | felem_diff(x_out, x_out, v); 864 | felem_diff(x_out, x_out, v); 865 | 866 | felem_diff(tmp, v, x_out); 867 | felem_mul(y_out, tmp, r); 868 | felem_mul(tmp, y1, j); 869 | felem_diff(y_out, y_out, tmp); 870 | felem_diff(y_out, y_out, tmp); 871 | } 872 | 873 | /* point_add sets {x_out,y_out,z_out} = {x1,y1,z1} + {x2,y2,z2}. 874 | * 875 | * See http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-add-2007-bl 876 | * 877 | * Note that this function does not handle P+P, infinity+P nor P+infinity 878 | * correctly. */ 879 | static void point_add(felem x_out, felem y_out, felem z_out, const felem x1, 880 | const felem y1, const felem z1, const felem x2, 881 | const felem y2, const felem z2) { 882 | felem z1z1, z1z1z1, z2z2, z2z2z2, s1, s2, u1, u2, h, i, j, r, rr, v, tmp; 883 | 884 | felem_square(z1z1, z1); 885 | felem_square(z2z2, z2); 886 | felem_mul(u1, x1, z2z2); 887 | 888 | felem_sum(tmp, z1, z2); 889 | felem_square(tmp, tmp); 890 | felem_diff(tmp, tmp, z1z1); 891 | felem_diff(tmp, tmp, z2z2); 892 | 893 | felem_mul(z2z2z2, z2, z2z2); 894 | felem_mul(s1, y1, z2z2z2); 895 | 896 | felem_mul(u2, x2, z1z1); 897 | felem_mul(z1z1z1, z1, z1z1); 898 | felem_mul(s2, y2, z1z1z1); 899 | felem_diff(h, u2, u1); 900 | felem_sum(i, h, h); 901 | felem_square(i, i); 902 | felem_mul(j, h, i); 903 | felem_diff(r, s2, s1); 904 | felem_sum(r, r, r); 905 | felem_mul(v, u1, i); 906 | 907 | felem_mul(z_out, tmp, h); 908 | felem_square(rr, r); 909 | felem_diff(x_out, rr, j); 910 | felem_diff(x_out, x_out, v); 911 | felem_diff(x_out, x_out, v); 912 | 913 | felem_diff(tmp, v, x_out); 914 | felem_mul(y_out, tmp, r); 915 | felem_mul(tmp, s1, j); 916 | felem_diff(y_out, y_out, tmp); 917 | felem_diff(y_out, y_out, tmp); 918 | } 919 | 920 | /* point_add_or_double_vartime sets {x_out,y_out,z_out} = {x1,y1,z1} + 921 | * {x2,y2,z2}. 922 | * 923 | * See http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-add-2007-bl 924 | * 925 | * This function handles the case where {x1,y1,z1}={x2,y2,z2}. */ 926 | static void point_add_or_double_vartime( 927 | felem x_out, felem y_out, felem z_out, const felem x1, const felem y1, 928 | const felem z1, const felem x2, const felem y2, const felem z2) { 929 | felem z1z1, z1z1z1, z2z2, z2z2z2, s1, s2, u1, u2, h, i, j, r, rr, v, tmp; 930 | char x_equal, y_equal; 931 | 932 | felem_square(z1z1, z1); 933 | felem_square(z2z2, z2); 934 | felem_mul(u1, x1, z2z2); 935 | 936 | felem_sum(tmp, z1, z2); 937 | felem_square(tmp, tmp); 938 | felem_diff(tmp, tmp, z1z1); 939 | felem_diff(tmp, tmp, z2z2); 940 | 941 | felem_mul(z2z2z2, z2, z2z2); 942 | felem_mul(s1, y1, z2z2z2); 943 | 944 | felem_mul(u2, x2, z1z1); 945 | felem_mul(z1z1z1, z1, z1z1); 946 | felem_mul(s2, y2, z1z1z1); 947 | felem_diff(h, u2, u1); 948 | x_equal = felem_is_zero_vartime(h); 949 | felem_sum(i, h, h); 950 | felem_square(i, i); 951 | felem_mul(j, h, i); 952 | felem_diff(r, s2, s1); 953 | y_equal = felem_is_zero_vartime(r); 954 | if (x_equal && y_equal) { 955 | point_double(x_out, y_out, z_out, x1, y1, z1); 956 | return; 957 | } 958 | felem_sum(r, r, r); 959 | felem_mul(v, u1, i); 960 | 961 | felem_mul(z_out, tmp, h); 962 | felem_square(rr, r); 963 | felem_diff(x_out, rr, j); 964 | felem_diff(x_out, x_out, v); 965 | felem_diff(x_out, x_out, v); 966 | 967 | felem_diff(tmp, v, x_out); 968 | felem_mul(y_out, tmp, r); 969 | felem_mul(tmp, s1, j); 970 | felem_diff(y_out, y_out, tmp); 971 | felem_diff(y_out, y_out, tmp); 972 | } 973 | 974 | /* copy_conditional sets out=in if mask = 0xffffffff in constant time. 975 | * 976 | * On entry: mask is either 0 or 0xffffffff. */ 977 | static void copy_conditional(felem out, const felem in, limb mask) { 978 | int i; 979 | 980 | for (i = 0; i < NLIMBS; i++) { 981 | const limb tmp = mask & (in[i] ^ out[i]); 982 | out[i] ^= tmp; 983 | } 984 | } 985 | 986 | /* select_affine_point sets {out_x,out_y} to the index'th entry of table. 987 | * On entry: index < 16, table[0] must be zero. */ 988 | static void select_affine_point(felem out_x, felem out_y, const limb* table, 989 | limb index) { 990 | limb i, j; 991 | 992 | memset(out_x, 0, sizeof(felem)); 993 | memset(out_y, 0, sizeof(felem)); 994 | 995 | for (i = 1; i < 16; i++) { 996 | limb mask = i ^ index; 997 | mask |= mask >> 2; 998 | mask |= mask >> 1; 999 | mask &= 1; 1000 | mask--; 1001 | for (j = 0; j < NLIMBS; j++, table++) { 1002 | out_x[j] |= *table & mask; 1003 | } 1004 | for (j = 0; j < NLIMBS; j++, table++) { 1005 | out_y[j] |= *table & mask; 1006 | } 1007 | } 1008 | } 1009 | 1010 | /* select_jacobian_point sets {out_x,out_y,out_z} to the index'th entry of 1011 | * table. On entry: index < 16, table[0] must be zero. */ 1012 | static void select_jacobian_point(felem out_x, felem out_y, felem out_z, 1013 | const limb* table, limb index) { 1014 | limb i, j; 1015 | 1016 | memset(out_x, 0, sizeof(felem)); 1017 | memset(out_y, 0, sizeof(felem)); 1018 | memset(out_z, 0, sizeof(felem)); 1019 | 1020 | /* The implicit value at index 0 is all zero. We don't need to perform that 1021 | * iteration of the loop because we already set out_* to zero. */ 1022 | table += 3 * NLIMBS; 1023 | 1024 | // Hit all entries to obscure cache profiling. 1025 | for (i = 1; i < 16; i++) { 1026 | limb mask = i ^ index; 1027 | mask |= mask >> 2; 1028 | mask |= mask >> 1; 1029 | mask &= 1; 1030 | mask--; 1031 | for (j = 0; j < NLIMBS; j++, table++) { 1032 | out_x[j] |= *table & mask; 1033 | } 1034 | for (j = 0; j < NLIMBS; j++, table++) { 1035 | out_y[j] |= *table & mask; 1036 | } 1037 | for (j = 0; j < NLIMBS; j++, table++) { 1038 | out_z[j] |= *table & mask; 1039 | } 1040 | } 1041 | } 1042 | 1043 | /* scalar_base_mult sets {nx,ny,nz} = scalar*G where scalar is a little-endian 1044 | * number. Note that the value of scalar must be less than the order of the 1045 | * group. */ 1046 | static void scalar_base_mult(felem nx, felem ny, felem nz, 1047 | const p256_int* scalar) { 1048 | int i, j; 1049 | limb n_is_infinity_mask = -1, p_is_noninfinite_mask, mask; 1050 | u32 table_offset; 1051 | 1052 | felem px, py; 1053 | felem tx, ty, tz; 1054 | 1055 | memset(nx, 0, sizeof(felem)); 1056 | memset(ny, 0, sizeof(felem)); 1057 | memset(nz, 0, sizeof(felem)); 1058 | 1059 | /* The loop adds bits at positions 0, 64, 128 and 192, followed by 1060 | * positions 32,96,160 and 224 and does this 32 times. */ 1061 | for (i = 0; i < 32; i++) { 1062 | if (i) { 1063 | point_double(nx, ny, nz, nx, ny, nz); 1064 | } 1065 | table_offset = 0; 1066 | for (j = 0; j <= 32; j += 32) { 1067 | char bit0 = p256_get_bit(scalar, 31 - i + j); 1068 | char bit1 = p256_get_bit(scalar, 95 - i + j); 1069 | char bit2 = p256_get_bit(scalar, 159 - i + j); 1070 | char bit3 = p256_get_bit(scalar, 223 - i + j); 1071 | limb index = bit0 | (bit1 << 1) | (bit2 << 2) | (bit3 << 3); 1072 | 1073 | select_affine_point(px, py, kPrecomputed + table_offset, index); 1074 | table_offset += 30 * NLIMBS; 1075 | 1076 | /* Since scalar is less than the order of the group, we know that 1077 | * {nx,ny,nz} != {px,py,1}, unless both are zero, which we handle 1078 | * below. */ 1079 | point_add_mixed(tx, ty, tz, nx, ny, nz, px, py); 1080 | /* The result of point_add_mixed is incorrect if {nx,ny,nz} is zero 1081 | * (a.k.a. the point at infinity). We handle that situation by 1082 | * copying the point from the table. */ 1083 | copy_conditional(nx, px, n_is_infinity_mask); 1084 | copy_conditional(ny, py, n_is_infinity_mask); 1085 | copy_conditional(nz, kOne, n_is_infinity_mask); 1086 | 1087 | /* Equally, the result is also wrong if the point from the table is 1088 | * zero, which happens when the index is zero. We handle that by 1089 | * only copying from {tx,ty,tz} to {nx,ny,nz} if index != 0. */ 1090 | p_is_noninfinite_mask = NON_ZERO_TO_ALL_ONES(index); 1091 | mask = p_is_noninfinite_mask & ~n_is_infinity_mask; 1092 | copy_conditional(nx, tx, mask); 1093 | copy_conditional(ny, ty, mask); 1094 | copy_conditional(nz, tz, mask); 1095 | /* If p was not zero, then n is now non-zero. */ 1096 | n_is_infinity_mask &= ~p_is_noninfinite_mask; 1097 | } 1098 | } 1099 | } 1100 | 1101 | /* point_to_affine converts a Jacobian point to an affine point. If the input 1102 | * is the point at infinity then it returns (0, 0) in constant time. */ 1103 | static void point_to_affine(felem x_out, felem y_out, const felem nx, 1104 | const felem ny, const felem nz) { 1105 | felem z_inv, z_inv_sq; 1106 | felem_inv(z_inv, nz); 1107 | felem_square(z_inv_sq, z_inv); 1108 | felem_mul(x_out, nx, z_inv_sq); 1109 | felem_mul(z_inv, z_inv, z_inv_sq); 1110 | felem_mul(y_out, ny, z_inv); 1111 | } 1112 | 1113 | /* scalar_base_mult sets {nx,ny,nz} = scalar*{x,y}. */ 1114 | static void scalar_mult(felem nx, felem ny, felem nz, const felem x, 1115 | const felem y, const p256_int* scalar) { 1116 | int i; 1117 | felem px, py, pz, tx, ty, tz; 1118 | felem precomp[16][3]; 1119 | limb n_is_infinity_mask, index, p_is_noninfinite_mask, mask; 1120 | 1121 | /* We precompute 0,1,2,... times {x,y}. */ 1122 | memset(precomp, 0, sizeof(felem) * 3); 1123 | memcpy(&precomp[1][0], x, sizeof(felem)); 1124 | memcpy(&precomp[1][1], y, sizeof(felem)); 1125 | memcpy(&precomp[1][2], kOne, sizeof(felem)); 1126 | 1127 | for (i = 2; i < 16; i += 2) { 1128 | point_double(precomp[i][0], precomp[i][1], precomp[i][2], 1129 | precomp[i / 2][0], precomp[i / 2][1], precomp[i / 2][2]); 1130 | 1131 | point_add_mixed(precomp[i + 1][0], precomp[i + 1][1], precomp[i + 1][2], 1132 | precomp[i][0], precomp[i][1], precomp[i][2], x, y); 1133 | } 1134 | 1135 | memset(nx, 0, sizeof(felem)); 1136 | memset(ny, 0, sizeof(felem)); 1137 | memset(nz, 0, sizeof(felem)); 1138 | n_is_infinity_mask = -1; 1139 | 1140 | /* We add in a window of four bits each iteration and do this 64 times. */ 1141 | for (i = 0; i < 256; i += 4) { 1142 | if (i) { 1143 | point_double(nx, ny, nz, nx, ny, nz); 1144 | point_double(nx, ny, nz, nx, ny, nz); 1145 | point_double(nx, ny, nz, nx, ny, nz); 1146 | point_double(nx, ny, nz, nx, ny, nz); 1147 | } 1148 | 1149 | index = (p256_get_bit(scalar, 255 - i - 0) << 3) | 1150 | (p256_get_bit(scalar, 255 - i - 1) << 2) | 1151 | (p256_get_bit(scalar, 255 - i - 2) << 1) | 1152 | p256_get_bit(scalar, 255 - i - 3); 1153 | 1154 | /* See the comments in scalar_base_mult about handling infinities. */ 1155 | select_jacobian_point(px, py, pz, precomp[0][0], index); 1156 | point_add(tx, ty, tz, nx, ny, nz, px, py, pz); 1157 | copy_conditional(nx, px, n_is_infinity_mask); 1158 | copy_conditional(ny, py, n_is_infinity_mask); 1159 | copy_conditional(nz, pz, n_is_infinity_mask); 1160 | 1161 | p_is_noninfinite_mask = NON_ZERO_TO_ALL_ONES(index); 1162 | mask = p_is_noninfinite_mask & ~n_is_infinity_mask; 1163 | 1164 | copy_conditional(nx, tx, mask); 1165 | copy_conditional(ny, ty, mask); 1166 | copy_conditional(nz, tz, mask); 1167 | n_is_infinity_mask &= ~p_is_noninfinite_mask; 1168 | } 1169 | } 1170 | 1171 | #define kRDigits {2, 0, 0, 0xfffffffe, 0xffffffff, 0xffffffff, 0xfffffffd, 1} // 2^257 mod p256.p 1172 | 1173 | #define kRInvDigits {0x80000000, 1, 0xffffffff, 0, 0x80000001, 0xfffffffe, 1, 0x7fffffff} // 1 / 2^257 mod p256.p 1174 | 1175 | static const p256_int kR = { kRDigits }; 1176 | static const p256_int kRInv = { kRInvDigits }; 1177 | 1178 | /* to_montgomery sets out = R*in. */ 1179 | static void to_montgomery(felem out, const p256_int* in) { 1180 | p256_int in_shifted; 1181 | int i; 1182 | 1183 | p256_init(&in_shifted); 1184 | p256_modmul(&SECP256r1_p, in, 0, &kR, &in_shifted); 1185 | 1186 | for (i = 0; i < NLIMBS; i++) { 1187 | if ((i & 1) == 0) { 1188 | out[i] = P256_DIGIT(&in_shifted, 0) & kBottom29Bits; 1189 | p256_shr(&in_shifted, 29, &in_shifted); 1190 | } else { 1191 | out[i] = P256_DIGIT(&in_shifted, 0) & kBottom28Bits; 1192 | p256_shr(&in_shifted, 28, &in_shifted); 1193 | } 1194 | } 1195 | 1196 | p256_clear(&in_shifted); 1197 | } 1198 | 1199 | /* from_montgomery sets out=in/R. */ 1200 | static void from_montgomery(p256_int* out, const felem in) { 1201 | p256_int result, tmp; 1202 | int i, top; 1203 | 1204 | p256_init(&result); 1205 | p256_init(&tmp); 1206 | 1207 | p256_add_d(&tmp, in[NLIMBS - 1], &result); 1208 | for (i = NLIMBS - 2; i >= 0; i--) { 1209 | if ((i & 1) == 0) { 1210 | top = p256_shl(&result, 29, &tmp); 1211 | } else { 1212 | top = p256_shl(&result, 28, &tmp); 1213 | } 1214 | top |= p256_add_d(&tmp, in[i], &result); 1215 | } 1216 | 1217 | p256_modmul(&SECP256r1_p, &kRInv, top, &result, out); 1218 | 1219 | p256_clear(&result); 1220 | p256_clear(&tmp); 1221 | } 1222 | 1223 | /* p256_base_point_mul sets {out_x,out_y} = nG, where n is < the 1224 | * order of the group. */ 1225 | void p256_base_point_mul(const p256_int* n, p256_int* out_x, p256_int* out_y) { 1226 | felem x, y, z; 1227 | 1228 | scalar_base_mult(x, y, z, n); 1229 | 1230 | { 1231 | felem x_affine, y_affine; 1232 | 1233 | point_to_affine(x_affine, y_affine, x, y, z); 1234 | from_montgomery(out_x, x_affine); 1235 | from_montgomery(out_y, y_affine); 1236 | } 1237 | } 1238 | 1239 | /* p256_points_mul_vartime sets {out_x,out_y} = n1*G + n2*{in_x,in_y}, where 1240 | * n1 and n2 are < the order of the group. 1241 | * 1242 | * As indicated by the name, this function operates in variable time. This 1243 | * is safe because it's used for signature validation which doesn't deal 1244 | * with secrets. */ 1245 | void p256_points_mul_vartime( 1246 | const p256_int* n1, const p256_int* n2, const p256_int* in_x, 1247 | const p256_int* in_y, p256_int* out_x, p256_int* out_y) { 1248 | felem x1, y1, z1, x2, y2, z2, px, py; 1249 | 1250 | /* If both scalars are zero, then the result is the point at infinity. */ 1251 | if (p256_is_zero(n1) != 0 && p256_is_zero(n2) != 0) { 1252 | p256_clear(out_x); 1253 | p256_clear(out_y); 1254 | return; 1255 | } 1256 | 1257 | to_montgomery(px, in_x); 1258 | to_montgomery(py, in_y); 1259 | scalar_base_mult(x1, y1, z1, n1); 1260 | scalar_mult(x2, y2, z2, px, py, n2); 1261 | 1262 | if (p256_is_zero(n2) != 0) { 1263 | /* If n2 == 0, then {x2,y2,z2} is zero and the result is just 1264 | * {x1,y1,z1}. */ 1265 | } else if (p256_is_zero(n1) != 0) { 1266 | /* If n1 == 0, then {x1,y1,z1} is zero and the result is just 1267 | * {x2,y2,z2}. */ 1268 | memcpy(x1, x2, sizeof(x2)); 1269 | memcpy(y1, y2, sizeof(y2)); 1270 | memcpy(z1, z2, sizeof(z2)); 1271 | } else { 1272 | /* This function handles the case where {x1,y1,z1} == {x2,y2,z2}. */ 1273 | point_add_or_double_vartime(x1, y1, z1, x1, y1, z1, x2, y2, z2); 1274 | } 1275 | 1276 | point_to_affine(px, py, x1, y1, z1); 1277 | from_montgomery(out_x, px); 1278 | from_montgomery(out_y, py); 1279 | } 1280 | -------------------------------------------------------------------------------- /deps/libmincrypt/p256_ecdsa.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 The Android Open Source Project 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * * Redistributions of source code must retain the above copyright 7 | * notice, this list of conditions and the following disclaimer. 8 | * * Redistributions in binary form must reproduce the above copyright 9 | * notice, this list of conditions and the following disclaimer in the 10 | * documentation and/or other materials provided with the distribution. 11 | * * Neither the name of Google Inc. nor the names of its contributors may 12 | * be used to endorse or promote products derived from this software 13 | * without specific prior written permission. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR 16 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 17 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 18 | * EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 19 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 21 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 23 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 24 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | #include 28 | 29 | #include "mincrypt/p256_ecdsa.h" 30 | #include "mincrypt/p256.h" 31 | 32 | int p256_ecdsa_verify(const p256_int* key_x, const p256_int* key_y, 33 | const p256_int* message, 34 | const p256_int* r, const p256_int* s) { 35 | p256_int u, v; 36 | 37 | // Check public key. 38 | if (!p256_is_valid_point(key_x, key_y)) return 0; 39 | 40 | // Check r and s are != 0 % n. 41 | p256_mod(&SECP256r1_n, r, &u); 42 | p256_mod(&SECP256r1_n, s, &v); 43 | if (p256_is_zero(&u) || p256_is_zero(&v)) return 0; 44 | 45 | p256_modinv_vartime(&SECP256r1_n, s, &v); 46 | p256_modmul(&SECP256r1_n, message, 0, &v, &u); // message / s % n 47 | p256_modmul(&SECP256r1_n, r, 0, &v, &v); // r / s % n 48 | 49 | p256_points_mul_vartime(&u, &v, 50 | key_x, key_y, 51 | &u, &v); 52 | 53 | p256_mod(&SECP256r1_n, &u, &u); // (x coord % p) % n 54 | return p256_cmp(r, &u) == 0; 55 | } 56 | 57 | -------------------------------------------------------------------------------- /deps/libmincrypt/rsa.c: -------------------------------------------------------------------------------- 1 | /* rsa.c 2 | ** 3 | ** Copyright 2012, The Android Open Source Project 4 | ** 5 | ** Redistribution and use in source and binary forms, with or without 6 | ** modification, are permitted provided that the following conditions are met: 7 | ** * Redistributions of source code must retain the above copyright 8 | ** notice, this list of conditions and the following disclaimer. 9 | ** * Redistributions in binary form must reproduce the above copyright 10 | ** notice, this list of conditions and the following disclaimer in the 11 | ** documentation and/or other materials provided with the distribution. 12 | ** * Neither the name of Google Inc. nor the names of its contributors may 13 | ** be used to endorse or promote products derived from this software 14 | ** without specific prior written permission. 15 | ** 16 | ** THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR 17 | ** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 18 | ** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 19 | ** EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 | ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 | ** PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 22 | ** OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 23 | ** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 24 | ** OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 25 | ** ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #include "mincrypt/rsa.h" 29 | #include "mincrypt/sha.h" 30 | #include "mincrypt/sha256.h" 31 | 32 | // a[] -= mod 33 | static void subM(const RSAPublicKey* key, 34 | uint32_t* a) { 35 | int64_t A = 0; 36 | int i; 37 | for (i = 0; i < key->len; ++i) { 38 | A += (uint64_t)a[i] - key->n[i]; 39 | a[i] = (uint32_t)A; 40 | A >>= 32; 41 | } 42 | } 43 | 44 | // return a[] >= mod 45 | static int geM(const RSAPublicKey* key, 46 | const uint32_t* a) { 47 | int i; 48 | for (i = key->len; i;) { 49 | --i; 50 | if (a[i] < key->n[i]) return 0; 51 | if (a[i] > key->n[i]) return 1; 52 | } 53 | return 1; // equal 54 | } 55 | 56 | // montgomery c[] += a * b[] / R % mod 57 | static void montMulAdd(const RSAPublicKey* key, 58 | uint32_t* c, 59 | const uint32_t a, 60 | const uint32_t* b) { 61 | uint64_t A = (uint64_t)a * b[0] + c[0]; 62 | uint32_t d0 = (uint32_t)A * key->n0inv; 63 | uint64_t B = (uint64_t)d0 * key->n[0] + (uint32_t)A; 64 | int i; 65 | 66 | for (i = 1; i < key->len; ++i) { 67 | A = (A >> 32) + (uint64_t)a * b[i] + c[i]; 68 | B = (B >> 32) + (uint64_t)d0 * key->n[i] + (uint32_t)A; 69 | c[i - 1] = (uint32_t)B; 70 | } 71 | 72 | A = (A >> 32) + (B >> 32); 73 | 74 | c[i - 1] = (uint32_t)A; 75 | 76 | if (A >> 32) { 77 | subM(key, c); 78 | } 79 | } 80 | 81 | // montgomery c[] = a[] * b[] / R % mod 82 | static void montMul(const RSAPublicKey* key, 83 | uint32_t* c, 84 | const uint32_t* a, 85 | const uint32_t* b) { 86 | int i; 87 | for (i = 0; i < key->len; ++i) { 88 | c[i] = 0; 89 | } 90 | for (i = 0; i < key->len; ++i) { 91 | montMulAdd(key, c, a[i], b); 92 | } 93 | } 94 | 95 | // In-place public exponentiation. 96 | // Input and output big-endian byte array in inout. 97 | static void modpow(const RSAPublicKey* key, 98 | uint8_t* inout) { 99 | uint32_t a[RSANUMWORDS]; 100 | uint32_t aR[RSANUMWORDS]; 101 | uint32_t aaR[RSANUMWORDS]; 102 | uint32_t* aaa = 0; 103 | int i; 104 | 105 | // Convert from big endian byte array to little endian word array. 106 | for (i = 0; i < key->len; ++i) { 107 | uint32_t tmp = 108 | (inout[((key->len - 1 - i) * 4) + 0] << 24) | 109 | (inout[((key->len - 1 - i) * 4) + 1] << 16) | 110 | (inout[((key->len - 1 - i) * 4) + 2] << 8) | 111 | (inout[((key->len - 1 - i) * 4) + 3] << 0); 112 | a[i] = tmp; 113 | } 114 | 115 | if (key->exponent == 65537) { 116 | aaa = aaR; // Re-use location. 117 | montMul(key, aR, a, key->rr); // aR = a * RR / R mod M 118 | for (i = 0; i < 16; i += 2) { 119 | montMul(key, aaR, aR, aR); // aaR = aR * aR / R mod M 120 | montMul(key, aR, aaR, aaR); // aR = aaR * aaR / R mod M 121 | } 122 | montMul(key, aaa, aR, a); // aaa = aR * a / R mod M 123 | } else if (key->exponent == 3) { 124 | aaa = aR; // Re-use location. 125 | montMul(key, aR, a, key->rr); /* aR = a * RR / R mod M */ 126 | montMul(key, aaR, aR, aR); /* aaR = aR * aR / R mod M */ 127 | montMul(key, aaa, aaR, a); /* aaa = aaR * a / R mod M */ 128 | } 129 | 130 | // Make sure aaa < mod; aaa is at most 1x mod too large. 131 | if (geM(key, aaa)) { 132 | subM(key, aaa); 133 | } 134 | 135 | // Convert to bigendian byte array 136 | for (i = key->len - 1; i >= 0; --i) { 137 | uint32_t tmp = aaa[i]; 138 | *inout++ = tmp >> 24; 139 | *inout++ = tmp >> 16; 140 | *inout++ = tmp >> 8; 141 | *inout++ = tmp >> 0; 142 | } 143 | } 144 | 145 | // Expected PKCS1.5 signature padding bytes, for a keytool RSA signature. 146 | // Has the 0-length optional parameter encoded in the ASN1 (as opposed to the 147 | // other flavor which omits the optional parameter entirely). This code does not 148 | // accept signatures without the optional parameter. 149 | 150 | /* 151 | static const uint8_t sha_padding[RSANUMBYTES] = { 152 | 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 153 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 154 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 155 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 156 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 157 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 158 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 159 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 160 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 161 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 162 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 163 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 164 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 165 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 166 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 167 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 168 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 169 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 170 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 171 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 172 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 173 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 174 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 175 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 176 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 177 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 178 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 179 | 0xff, 0xff, 0xff, 0xff, 0x00, 0x30, 0x21, 0x30, 180 | 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 181 | 0x05, 0x00, 0x04, 0x14, 182 | 183 | // 20 bytes of hash go here. 184 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 185 | }; 186 | */ 187 | 188 | // SHA-1 of PKCS1.5 signature sha_padding for 2048 bit, as above. 189 | // At the location of the bytes of the hash all 00 are hashed. 190 | static const uint8_t kExpectedPadShaRsa2048[SHA_DIGEST_SIZE] = { 191 | 0xdc, 0xbd, 0xbe, 0x42, 0xd5, 0xf5, 0xa7, 0x2e, 192 | 0x6e, 0xfc, 0xf5, 0x5d, 0xaf, 0x9d, 0xea, 0x68, 193 | 0x7c, 0xfb, 0xf1, 0x67 194 | }; 195 | 196 | /* 197 | static const uint8_t sha256_padding[RSANUMBYTES] = { 198 | 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 199 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 200 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 201 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 202 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 203 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 204 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 205 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 206 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 207 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 208 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 209 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 210 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 211 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 212 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 213 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 214 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 215 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 216 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 217 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 218 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 219 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 220 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 221 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 222 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 223 | 0xff, 0xff, 0xff, 0xff, 0x00, 0x30, 0x31, 0x30, 224 | 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 225 | 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20, 226 | 227 | // 32 bytes of hash go here. 228 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 229 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 230 | }; 231 | */ 232 | 233 | // SHA-256 of PKCS1.5 signature sha256_padding for 2048 bit, as above. 234 | // At the location of the bytes of the hash all 00 are hashed. 235 | static const uint8_t kExpectedPadSha256Rsa2048[SHA256_DIGEST_SIZE] = { 236 | 0xab, 0x28, 0x8d, 0x8a, 0xd7, 0xd9, 0x59, 0x92, 237 | 0xba, 0xcc, 0xf8, 0x67, 0x20, 0xe1, 0x15, 0x2e, 238 | 0x39, 0x8d, 0x80, 0x36, 0xd6, 0x6f, 0xf0, 0xfd, 239 | 0x90, 0xe8, 0x7d, 0x8b, 0xe1, 0x7c, 0x87, 0x59, 240 | }; 241 | 242 | // Verify a 2048-bit RSA PKCS1.5 signature against an expected hash. 243 | // Both e=3 and e=65537 are supported. hash_len may be 244 | // SHA_DIGEST_SIZE (== 20) to indicate a SHA-1 hash, or 245 | // SHA256_DIGEST_SIZE (== 32) to indicate a SHA-256 hash. No other 246 | // values are supported. 247 | // 248 | // Returns 1 on successful verification, 0 on failure. 249 | int RSA_verify(const RSAPublicKey *key, 250 | const uint8_t *signature, 251 | const int len, 252 | const uint8_t *hash, 253 | const int hash_len) { 254 | uint8_t buf[RSANUMBYTES]; 255 | int i; 256 | const uint8_t* padding_hash; 257 | 258 | if (key->len != RSANUMWORDS) { 259 | return 0; // Wrong key passed in. 260 | } 261 | 262 | if (len != sizeof(buf)) { 263 | return 0; // Wrong input length. 264 | } 265 | 266 | if (hash_len != SHA_DIGEST_SIZE && 267 | hash_len != SHA256_DIGEST_SIZE) { 268 | return 0; // Unsupported hash. 269 | } 270 | 271 | if (key->exponent != 3 && key->exponent != 65537) { 272 | return 0; // Unsupported exponent. 273 | } 274 | 275 | for (i = 0; i < len; ++i) { // Copy input to local workspace. 276 | buf[i] = signature[i]; 277 | } 278 | 279 | modpow(key, buf); // In-place exponentiation. 280 | 281 | // Xor sha portion, so it all becomes 00 iff equal. 282 | for (i = len - hash_len; i < len; ++i) { 283 | buf[i] ^= *hash++; 284 | } 285 | 286 | // Hash resulting buf, in-place. 287 | switch (hash_len) { 288 | case SHA_DIGEST_SIZE: 289 | padding_hash = kExpectedPadShaRsa2048; 290 | SHA_hash(buf, len, buf); 291 | break; 292 | case SHA256_DIGEST_SIZE: 293 | padding_hash = kExpectedPadSha256Rsa2048; 294 | SHA256_hash(buf, len, buf); 295 | break; 296 | default: 297 | return 0; 298 | } 299 | 300 | // Compare against expected hash value. 301 | for (i = 0; i < hash_len; ++i) { 302 | if (buf[i] != padding_hash[i]) { 303 | return 0; 304 | } 305 | } 306 | 307 | return 1; // All checked out OK. 308 | } 309 | -------------------------------------------------------------------------------- /deps/libmincrypt/sha.c: -------------------------------------------------------------------------------- 1 | /* sha.c 2 | ** 3 | ** Copyright 2013, The Android Open Source Project 4 | ** 5 | ** Redistribution and use in source and binary forms, with or without 6 | ** modification, are permitted provided that the following conditions are met: 7 | ** * Redistributions of source code must retain the above copyright 8 | ** notice, this list of conditions and the following disclaimer. 9 | ** * Redistributions in binary form must reproduce the above copyright 10 | ** notice, this list of conditions and the following disclaimer in the 11 | ** documentation and/or other materials provided with the distribution. 12 | ** * Neither the name of Google Inc. nor the names of its contributors may 13 | ** be used to endorse or promote products derived from this software 14 | ** without specific prior written permission. 15 | ** 16 | ** THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR 17 | ** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 18 | ** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 19 | ** EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 | ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 | ** PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 22 | ** OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 23 | ** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 24 | ** OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 25 | ** ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | // Optimized for minimal code size. 29 | 30 | #include "mincrypt/sha.h" 31 | 32 | #include 33 | #include 34 | #include 35 | 36 | #define rol(bits, value) (((value) << (bits)) | ((value) >> (32 - (bits)))) 37 | 38 | static void SHA1_Transform(SHA_CTX* ctx) { 39 | uint32_t W[80]; 40 | uint32_t A, B, C, D, E; 41 | uint8_t* p = ctx->buf; 42 | int t; 43 | 44 | for(t = 0; t < 16; ++t) { 45 | uint32_t tmp = *p++ << 24; 46 | tmp |= *p++ << 16; 47 | tmp |= *p++ << 8; 48 | tmp |= *p++; 49 | W[t] = tmp; 50 | } 51 | 52 | for(; t < 80; t++) { 53 | W[t] = rol(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]); 54 | } 55 | 56 | A = ctx->state[0]; 57 | B = ctx->state[1]; 58 | C = ctx->state[2]; 59 | D = ctx->state[3]; 60 | E = ctx->state[4]; 61 | 62 | for(t = 0; t < 80; t++) { 63 | uint32_t tmp = rol(5,A) + E + W[t]; 64 | 65 | if (t < 20) 66 | tmp += (D^(B&(C^D))) + 0x5A827999; 67 | else if ( t < 40) 68 | tmp += (B^C^D) + 0x6ED9EBA1; 69 | else if ( t < 60) 70 | tmp += ((B&C)|(D&(B|C))) + 0x8F1BBCDC; 71 | else 72 | tmp += (B^C^D) + 0xCA62C1D6; 73 | 74 | E = D; 75 | D = C; 76 | C = rol(30,B); 77 | B = A; 78 | A = tmp; 79 | } 80 | 81 | ctx->state[0] += A; 82 | ctx->state[1] += B; 83 | ctx->state[2] += C; 84 | ctx->state[3] += D; 85 | ctx->state[4] += E; 86 | } 87 | 88 | static const HASH_VTAB SHA_VTAB = { 89 | SHA_init, 90 | SHA_update, 91 | SHA_final, 92 | SHA_hash, 93 | SHA_DIGEST_SIZE 94 | }; 95 | 96 | void SHA_init(SHA_CTX* ctx) { 97 | ctx->f = &SHA_VTAB; 98 | ctx->state[0] = 0x67452301; 99 | ctx->state[1] = 0xEFCDAB89; 100 | ctx->state[2] = 0x98BADCFE; 101 | ctx->state[3] = 0x10325476; 102 | ctx->state[4] = 0xC3D2E1F0; 103 | ctx->count = 0; 104 | } 105 | 106 | 107 | void SHA_update(SHA_CTX* ctx, const void* data, int len) { 108 | int i = (int) (ctx->count & 63); 109 | const uint8_t* p = (const uint8_t*)data; 110 | 111 | ctx->count += len; 112 | 113 | while (len--) { 114 | ctx->buf[i++] = *p++; 115 | if (i == 64) { 116 | SHA1_Transform(ctx); 117 | i = 0; 118 | } 119 | } 120 | } 121 | 122 | 123 | const uint8_t* SHA_final(SHA_CTX* ctx) { 124 | uint8_t *p = ctx->buf; 125 | uint64_t cnt = ctx->count * 8; 126 | int i; 127 | 128 | SHA_update(ctx, (uint8_t*)"\x80", 1); 129 | while ((ctx->count & 63) != 56) { 130 | SHA_update(ctx, (uint8_t*)"\0", 1); 131 | } 132 | for (i = 0; i < 8; ++i) { 133 | uint8_t tmp = (uint8_t) (cnt >> ((7 - i) * 8)); 134 | SHA_update(ctx, &tmp, 1); 135 | } 136 | 137 | for (i = 0; i < 5; i++) { 138 | uint32_t tmp = ctx->state[i]; 139 | *p++ = tmp >> 24; 140 | *p++ = tmp >> 16; 141 | *p++ = tmp >> 8; 142 | *p++ = tmp >> 0; 143 | } 144 | 145 | return ctx->buf; 146 | } 147 | 148 | /* Convenience function */ 149 | const uint8_t* SHA_hash(const void* data, int len, uint8_t* digest) { 150 | SHA_CTX ctx; 151 | SHA_init(&ctx); 152 | SHA_update(&ctx, data, len); 153 | memcpy(digest, SHA_final(&ctx), SHA_DIGEST_SIZE); 154 | return digest; 155 | } 156 | -------------------------------------------------------------------------------- /deps/libmincrypt/sha256.c: -------------------------------------------------------------------------------- 1 | /* sha256.c 2 | ** 3 | ** Copyright 2013, The Android Open Source Project 4 | ** 5 | ** Redistribution and use in source and binary forms, with or without 6 | ** modification, are permitted provided that the following conditions are met: 7 | ** * Redistributions of source code must retain the above copyright 8 | ** notice, this list of conditions and the following disclaimer. 9 | ** * Redistributions in binary form must reproduce the above copyright 10 | ** notice, this list of conditions and the following disclaimer in the 11 | ** documentation and/or other materials provided with the distribution. 12 | ** * Neither the name of Google Inc. nor the names of its contributors may 13 | ** be used to endorse or promote products derived from this software 14 | ** without specific prior written permission. 15 | ** 16 | ** THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR 17 | ** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 18 | ** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 19 | ** EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 | ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 | ** PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 22 | ** OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 23 | ** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 24 | ** OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 25 | ** ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | // Optimized for minimal code size. 29 | 30 | #include "mincrypt/sha256.h" 31 | 32 | #include 33 | #include 34 | #include 35 | 36 | #define ror(value, bits) (((value) >> (bits)) | ((value) << (32 - (bits)))) 37 | #define shr(value, bits) ((value) >> (bits)) 38 | 39 | static const uint32_t K[64] = { 40 | 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 41 | 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 42 | 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 43 | 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 44 | 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 45 | 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 46 | 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 47 | 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 48 | 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 49 | 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 50 | 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 51 | 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 52 | 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 53 | 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, 54 | 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 55 | 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 }; 56 | 57 | static void SHA256_Transform(SHA256_CTX* ctx) { 58 | uint32_t W[64]; 59 | uint32_t A, B, C, D, E, F, G, H; 60 | uint8_t* p = ctx->buf; 61 | int t; 62 | 63 | for(t = 0; t < 16; ++t) { 64 | uint32_t tmp = *p++ << 24; 65 | tmp |= *p++ << 16; 66 | tmp |= *p++ << 8; 67 | tmp |= *p++; 68 | W[t] = tmp; 69 | } 70 | 71 | for(; t < 64; t++) { 72 | uint32_t s0 = ror(W[t-15], 7) ^ ror(W[t-15], 18) ^ shr(W[t-15], 3); 73 | uint32_t s1 = ror(W[t-2], 17) ^ ror(W[t-2], 19) ^ shr(W[t-2], 10); 74 | W[t] = W[t-16] + s0 + W[t-7] + s1; 75 | } 76 | 77 | A = ctx->state[0]; 78 | B = ctx->state[1]; 79 | C = ctx->state[2]; 80 | D = ctx->state[3]; 81 | E = ctx->state[4]; 82 | F = ctx->state[5]; 83 | G = ctx->state[6]; 84 | H = ctx->state[7]; 85 | 86 | for(t = 0; t < 64; t++) { 87 | uint32_t s0 = ror(A, 2) ^ ror(A, 13) ^ ror(A, 22); 88 | uint32_t maj = (A & B) ^ (A & C) ^ (B & C); 89 | uint32_t t2 = s0 + maj; 90 | uint32_t s1 = ror(E, 6) ^ ror(E, 11) ^ ror(E, 25); 91 | uint32_t ch = (E & F) ^ ((~E) & G); 92 | uint32_t t1 = H + s1 + ch + K[t] + W[t]; 93 | 94 | H = G; 95 | G = F; 96 | F = E; 97 | E = D + t1; 98 | D = C; 99 | C = B; 100 | B = A; 101 | A = t1 + t2; 102 | } 103 | 104 | ctx->state[0] += A; 105 | ctx->state[1] += B; 106 | ctx->state[2] += C; 107 | ctx->state[3] += D; 108 | ctx->state[4] += E; 109 | ctx->state[5] += F; 110 | ctx->state[6] += G; 111 | ctx->state[7] += H; 112 | } 113 | 114 | static const HASH_VTAB SHA256_VTAB = { 115 | SHA256_init, 116 | SHA256_update, 117 | SHA256_final, 118 | SHA256_hash, 119 | SHA256_DIGEST_SIZE 120 | }; 121 | 122 | void SHA256_init(SHA256_CTX* ctx) { 123 | ctx->f = &SHA256_VTAB; 124 | ctx->state[0] = 0x6a09e667; 125 | ctx->state[1] = 0xbb67ae85; 126 | ctx->state[2] = 0x3c6ef372; 127 | ctx->state[3] = 0xa54ff53a; 128 | ctx->state[4] = 0x510e527f; 129 | ctx->state[5] = 0x9b05688c; 130 | ctx->state[6] = 0x1f83d9ab; 131 | ctx->state[7] = 0x5be0cd19; 132 | ctx->count = 0; 133 | } 134 | 135 | 136 | void SHA256_update(SHA256_CTX* ctx, const void* data, int len) { 137 | int i = (int) (ctx->count & 63); 138 | const uint8_t* p = (const uint8_t*)data; 139 | 140 | ctx->count += len; 141 | 142 | while (len--) { 143 | ctx->buf[i++] = *p++; 144 | if (i == 64) { 145 | SHA256_Transform(ctx); 146 | i = 0; 147 | } 148 | } 149 | } 150 | 151 | 152 | const uint8_t* SHA256_final(SHA256_CTX* ctx) { 153 | uint8_t *p = ctx->buf; 154 | uint64_t cnt = ctx->count * 8; 155 | int i; 156 | 157 | SHA256_update(ctx, (uint8_t*)"\x80", 1); 158 | while ((ctx->count & 63) != 56) { 159 | SHA256_update(ctx, (uint8_t*)"\0", 1); 160 | } 161 | for (i = 0; i < 8; ++i) { 162 | uint8_t tmp = (uint8_t) (cnt >> ((7 - i) * 8)); 163 | SHA256_update(ctx, &tmp, 1); 164 | } 165 | 166 | for (i = 0; i < 8; i++) { 167 | uint32_t tmp = ctx->state[i]; 168 | *p++ = tmp >> 24; 169 | *p++ = tmp >> 16; 170 | *p++ = tmp >> 8; 171 | *p++ = tmp >> 0; 172 | } 173 | 174 | return ctx->buf; 175 | } 176 | 177 | /* Convenience function */ 178 | const uint8_t* SHA256_hash(const void* data, int len, uint8_t* digest) { 179 | SHA256_CTX ctx; 180 | SHA256_init(&ctx); 181 | SHA256_update(&ctx, data, len); 182 | memcpy(digest, SHA256_final(&ctx), SHA256_DIGEST_SIZE); 183 | return digest; 184 | } 185 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var gulp = require('gulp'), 4 | Promise = require('bluebird').Promise, 5 | exec = Promise.promisify(require('child_process').exec), 6 | boilerplate = require('appium-gulp-plugins').boilerplate.use(gulp); 7 | 8 | gulp.task('node-gyp', function () { 9 | return exec('node-gyp configure build'); 10 | }); 11 | boilerplate({build: 'node-adb-client', jscs: false, postTranspile: ['node-gyp']}); 12 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | import ADBDevice from './lib/adb-device'; 2 | 3 | function connectToDevice (type, device) { 4 | return new ADBDevice(type, device); 5 | } 6 | 7 | export { connectToDevice }; -------------------------------------------------------------------------------- /lib/adb-device.js: -------------------------------------------------------------------------------- 1 | import { CONNECTION_TYPES, ADB_COMMANDS, CONNECT_VALUES 2 | , ADB_KEY, ADB_SUBCOMMANDS } from './constants'; 3 | import { getFileName, parseFileData, logExceptOnTest } from './helpers'; 4 | import USBDevice from './usb-device'; 5 | 6 | import { fs } from 'appium-support'; 7 | import path from 'path'; 8 | import _fs from 'fs'; 9 | import Promise from 'bluebird'; 10 | import * as signLib from '../Release/binding'; 11 | 12 | // local constants 13 | const homedir = process.platform === 'win32' ? process.env.HOMEPATH 14 | : process.env.HOME; 15 | const publickeyPath = path.join(homedir, ADB_KEY.PUBLIC_KEY); 16 | const privateKeyPath = path.join(homedir, ADB_KEY.PRIVATE_KEY); 17 | // we need all of this file before anything can happen with ADB 18 | const publicKeyString = _fs.readFileSync(publickeyPath); 19 | const installLocation = "/data/local/tmp/"; 20 | const uninstallString = "pm uninstall -k"; 21 | 22 | const MAX_DATA_SIZE = 65536; 23 | const MAX_READ_SIZE = 4000; 24 | const dataIndicator = new Buffer("DATA"); 25 | 26 | // create one of these to interface with a device 27 | class ADBDevice { 28 | constructor (connectionType, device) { 29 | this.connectionType = connectionType; 30 | if (connectionType === CONNECTION_TYPES.USB) { 31 | logExceptOnTest("Creating a usb device."); 32 | // let foundDevice = findAdbDevices(); 33 | // this.serialNumber = device.serialNumber; 34 | this.device = new USBDevice(device.device, device.deviceInterface); 35 | } else if (connectionType === CONNECTION_TYPES.TCP) { 36 | // insert tcp things 37 | } else { 38 | // errors yo 39 | throw new Error("Invalid connection type."); 40 | } 41 | } 42 | 43 | // recv a packet from the device and respond with okay so we can recv again 44 | async recvAndOkay (localId, remoteId) { 45 | let packet = await this.device._recvMsg(CONNECT_VALUES.CONNECT_MAXDATA); 46 | await this.device._sendMsg(ADB_COMMANDS.CMD_OKAY 47 | , localId 48 | , remoteId 49 | , ""); 50 | return packet; 51 | } 52 | 53 | // this function calls _send message and then tries to 54 | // recv an OKAY back from the device, use when sending 55 | // lots of packets to the device to instead of straight 56 | // _sendMsg and _recvMsg calls 57 | async sendAndOkay (cmd, arg1, arg2, payload) { 58 | await this.device._sendMsg(cmd, arg1, arg2, payload); 59 | let packet = await this.device._recvMsg(CONNECT_VALUES.CONNECT_MAXDATA); 60 | if (packet.command !== ADB_COMMANDS.CMD_OKAY) { 61 | // TODO: fix this so the error message returns the command name, not a number 62 | throw new Error(`sendAndOkay did not recv CMD_OKAY back from device: ${packet.command.toString()}`, -1); 63 | } 64 | return packet; 65 | } 66 | 67 | // ask the device for a file's stats 68 | async stat (remotePath, localId, remoteId) { 69 | // tell the device we're going to want stats about a file 70 | let statBuffer = new Buffer(8); 71 | statBuffer.writeUInt32LE(ADB_SUBCOMMANDS.CMD_STAT, 0); 72 | statBuffer.writeUInt32LE(remotePath.length, 4); 73 | let packet = await this.sendAndOkay(ADB_COMMANDS.CMD_WRTE 74 | , localId 75 | , remoteId 76 | , statBuffer); 77 | // investigate why this needs be sent twice in order to get past 78 | // this step in the flow 79 | packet = await this.sendAndOkay(ADB_COMMANDS.CMD_WRTE 80 | , localId 81 | , remoteId 82 | , remotePath); 83 | packet = await this.recvAndOkay(localId, remoteId); 84 | return packet; 85 | } 86 | 87 | async fileLoop (filePath, fileStats, devicePath, localId, remoteId) { 88 | let sendBuffer = new Buffer(`${devicePath},${fileStats.mode}`); 89 | let fd = await fs.open(filePath, 'r'); 90 | let remaining = fileStats.size; 91 | let currentPosition = 0; 92 | let appendDataSize = true; 93 | // DATA can only be 64k or less 94 | let dataAmount = remaining > MAX_DATA_SIZE ? MAX_DATA_SIZE : remaining; 95 | while (remaining > 0) { 96 | // if we need to send a DATA in this next packet 97 | if (appendDataSize) { 98 | let sizeBuffer = new Buffer(4); 99 | sizeBuffer.writeUInt32LE(dataAmount); 100 | sendBuffer = Buffer.concat([sendBuffer, dataIndicator, sizeBuffer]); 101 | appendDataSize = false; 102 | } 103 | let amountToRead = null; 104 | // amountToRead should either be MAX_READ_SIZE, the remaining amount of dataAmount, 105 | // or MAX_READ_SIZE - sendBuffer.length which is a case where we've got some data 106 | // from a previous DATA in sendBuffer and there is still data in the file 107 | // meaning we need to insert another DATA in the current packet we're 108 | // building plus more file data 109 | if (sendBuffer.length === 0) { 110 | amountToRead = dataAmount > MAX_READ_SIZE ? MAX_READ_SIZE : dataAmount; 111 | } else { 112 | amountToRead = remaining > MAX_READ_SIZE ? MAX_READ_SIZE - sendBuffer.length : remaining; 113 | } 114 | let readBuffer = new Buffer(amountToRead); 115 | await fs.read(fd, readBuffer, 0, amountToRead, currentPosition); 116 | sendBuffer = Buffer.concat([sendBuffer, readBuffer]); 117 | remaining -= amountToRead; 118 | dataAmount -= amountToRead; 119 | currentPosition += amountToRead; 120 | // if dataAmount is 0 and there is still some data in the file that means 121 | // we're in the case where we need to write another DATA + some file data 122 | // to sendBuffer, so we continue the loop in order to keep sendBuffer's current 123 | // contents, and to write to it again before we send the packet out to the device 124 | if (dataAmount === 0 & remaining !== 0) { 125 | appendDataSize = true; 126 | dataAmount = remaining > MAX_DATA_SIZE ? MAX_DATA_SIZE : remaining; 127 | continue; 128 | } 129 | if (remaining === 0) { 130 | logExceptOnTest("sending done"); 131 | let doneBuffer = new Buffer("DONE"); 132 | let mTimeBuffer = new Buffer(4); 133 | mTimeBuffer.writeUInt32LE(fileStats.mtime.getTime() / 1000, 0); 134 | sendBuffer = Buffer.concat([sendBuffer, doneBuffer, mTimeBuffer]); 135 | } 136 | let packet = await this.sendAndOkay(ADB_COMMANDS.CMD_WRTE 137 | , localId 138 | , remoteId 139 | , sendBuffer); 140 | if (packet.data) { 141 | logExceptOnTest("packet data: ", packet.data.toString()); 142 | } 143 | sendBuffer = new Buffer(""); 144 | } 145 | logExceptOnTest("fileLoop finished"); 146 | } 147 | 148 | // function to send a file to the device, part of _push flow gets some stats 149 | // about the file, calls fileLoop, and then finishes off the push flow and 150 | // closes the stream 151 | async sendFile (filePath, destination, localId, remoteId) { 152 | let fileName = getFileName(filePath); 153 | // path where the file will end up on the device, including the file name 154 | let devicePath = `${destination}/${fileName}`; 155 | let stats = await fs.stat(filePath); 156 | // await this.device._fileLoop(filePath, stats, devicePath, localId, remoteId); 157 | await this.fileLoop(filePath, stats, devicePath, localId, remoteId); 158 | logExceptOnTest("File sending is finished, cleanup time"); 159 | // the device is going to send us a WRTE containing an OKAY as the data 160 | let packet = await this.device._recvMsg(CONNECT_VALUES.CONNECT_MAXDATA); 161 | // now we send it the same thing back 162 | await this.device._sendMsg(ADB_COMMANDS.CMD_WRTE 163 | , localId 164 | , remoteId 165 | , ADB_COMMANDS.CMD_OKAY); 166 | // send QUIT and get an OKAY back 167 | await this.device._sendMsg(ADB_COMMANDS.CMD_WRTE 168 | , localId 169 | , remoteId 170 | , ADB_SUBCOMMANDS.CMD_QUIT); 171 | packet = await this.device._recvMsg(CONNECT_VALUES.CONNECT_MAXDATA); 172 | // send CLSE and then recv CLSE back from the device 173 | await this.close(localId, remoteId); 174 | } 175 | 176 | // recv chunks of a file from the device until we read DONE at the end of a msg 177 | async recvFile(localId, remoteId) { 178 | let run = true; 179 | let data = new Buffer(""); 180 | do { 181 | let packet = await this.recvAndOkay(localId, remoteId); 182 | let done = packet.data.readUInt32LE(packet.data.length - 8); 183 | if (done === ADB_SUBCOMMANDS.CMD_DONE) { 184 | run = false; 185 | } 186 | if (data !== null) { 187 | data = Buffer.concat([data, packet.data]); 188 | } 189 | } while (run === true); 190 | return data; 191 | } 192 | 193 | // Receive a file listing and parse it into an array of file objects. 194 | async recvList(localId, remoteId) { 195 | // This is the structure of each directory entry returned by LIST 196 | // see https://android.googlesource.com/platform/system/core/+/master/adb/SYNC.TXT#39 197 | const props = [ 198 | 'cmd', 199 | 'mode', 200 | 'size', 201 | 'modified', 202 | 'length', 203 | 'filename' 204 | ]; 205 | const files = []; 206 | let file = {}; 207 | let i = 0; 208 | 209 | // Keep requesting new packets until we receive 'DONE' 210 | // TODO: Do we need a timeout in case 'DONE' is never sent? Shouldn't happen 211 | while (true) { 212 | let packet = await this.recvAndOkay(localId, remoteId); 213 | let pos = 0; 214 | do { 215 | if (props[i] === 'filename') { 216 | file.filename = packet.data.slice(pos, pos + file.length).toString(); 217 | pos += file.length; 218 | delete file.length; 219 | files.push(file); 220 | file = {}; 221 | } else { 222 | let chunk = packet.data.readUInt32LE(pos); 223 | switch (props[i]) { 224 | case 'cmd': 225 | if (chunk === ADB_SUBCOMMANDS.CMD_DONE) { 226 | // Break the loop and return the files 227 | return files; 228 | } 229 | break; 230 | case 'modified': 231 | file.modified = new Date(chunk * 1000); 232 | break; 233 | case 'mode': 234 | file.type = chunk >> 13; 235 | // Just get the 9-bits that signify the UNIX file mode 236 | file.mode = chunk & ~0b1111111000000000; 237 | break; 238 | default: 239 | file[props[i]] = chunk; 240 | } 241 | // Move to the next chunk to process from the packet 242 | pos += 4; 243 | } 244 | // Keep cycling through the props in order 245 | i = (i + 1) % props.length; 246 | // continue parsing through the packet until we reach the end of the packet 247 | } while (pos < packet.data.length); 248 | } 249 | } 250 | 251 | // runs ADB push to push a file to the device 252 | async push (source, destination) { 253 | let syncBuf = new Buffer("sync:."); 254 | // open a SYNC stream on the device for pushing the file 255 | let packet = await this.sendAndOkay(ADB_COMMANDS.CMD_OPEN 256 | , 12345 257 | , 0 258 | , syncBuf); 259 | // this is our local id, the devices remote id 260 | let localId = packet.arg2; 261 | // this is our remote id, the devices local id 262 | let remoteId = packet.arg1; 263 | await this.stat(destination, localId, remoteId); 264 | let devicePath = `${destination}/${getFileName(source)}`; 265 | let sendBuffer = new Buffer(8); 266 | sendBuffer.writeUInt32LE(ADB_SUBCOMMANDS.CMD_SEND, 0); 267 | sendBuffer.writeUInt32LE(devicePath.length + 6, 4); 268 | packet = await this.sendAndOkay(ADB_COMMANDS.CMD_WRTE 269 | , localId 270 | , remoteId 271 | , sendBuffer); 272 | await this.sendFile(source, destination, localId, remoteId); 273 | } 274 | 275 | // runs LIST sync request to list files in a folder 276 | // If remotePath does not exist or is not a folder will return an empty array. 277 | // returns an array of file listing objects with properties: 278 | // type {number} - one of `0b100` (file), `0b010` (directory), `0b101` (symlink) 279 | // mode {number} - `chmod` mode e.g. file permissions as per unix standard. 280 | // modified {date} - file modification date 281 | // filename {string} - filename 282 | async list (remotePath) { 283 | let syncBuf = new Buffer("sync:."); 284 | // open a SYNC stream on the device for listing files in a folder 285 | let packet = await this.sendAndOkay(ADB_COMMANDS.CMD_OPEN 286 | , 12345 287 | , 0 288 | , syncBuf); 289 | // this is our local id, the devices remote id 290 | let localId = packet.arg2; 291 | // this is our remote id, the devices local id 292 | let remoteId = packet.arg1; 293 | let listBuffer = new Buffer(8); 294 | listBuffer.writeUInt32LE(ADB_SUBCOMMANDS.CMD_LIST, 0); 295 | listBuffer.writeUInt32LE(remotePath.length, 4); 296 | packet = await this.sendAndOkay(ADB_COMMANDS.CMD_WRTE 297 | , localId 298 | , remoteId 299 | , listBuffer); 300 | // Send the path to the folder to list files within 301 | packet = await this.sendAndOkay(ADB_COMMANDS.CMD_WRTE 302 | , localId 303 | , remoteId 304 | , remotePath); 305 | logExceptOnTest("sent remote path to list"); 306 | // recv the file data from the device 307 | let files = await this.recvList(localId, remoteId); 308 | // remove `.` and `..` file entries 309 | files = files.filter(file => file.filename !== '.' && file.filename !== '..'); 310 | return files; 311 | } 312 | 313 | // runs ADB pull to pull a file from the device to the local machine 314 | async pull (source, destination) { 315 | let syncBuf = new Buffer("sync:."); 316 | // open a SYNC stream on the device for pulling a file from the device 317 | let packet = await this.sendAndOkay(ADB_COMMANDS.CMD_OPEN 318 | , 12345 319 | , 0 320 | , syncBuf); 321 | // this is our local id, the devices remote id 322 | let localId = packet.arg2; 323 | // this is our remote id, the devnices local id 324 | let remoteId = packet.arg1; 325 | // tell the device we're going to want stats about a file 326 | packet = await this.stat(source, localId, remoteId); 327 | let mode = packet.data.readUInt32LE(4); 328 | if (mode === 0) { // file doesn't exist 329 | logExceptOnTest("The file you're trying to pull doesn't exist."); 330 | await this.close(localId, remoteId); 331 | return -1; 332 | } 333 | let fileSize = packet.data.readUInt32LE(8); 334 | // tell the device we want to recv the file 335 | let recvBuffer = new Buffer(8); 336 | recvBuffer.writeUInt32LE(ADB_SUBCOMMANDS.CMD_RECV, 0); 337 | recvBuffer.writeUInt32LE(source.length, 4); 338 | packet = await this.sendAndOkay(ADB_COMMANDS.CMD_WRTE 339 | , localId 340 | , remoteId 341 | , recvBuffer); 342 | // send the path to the file want to pull again 343 | packet = await this.sendAndOkay(ADB_COMMANDS.CMD_WRTE 344 | , localId 345 | , remoteId 346 | , source); 347 | logExceptOnTest("sent final source"); 348 | // recv the file data from the device 349 | let rawData = await this.recvFile(localId, remoteId); 350 | // pull the file data out (there's data related to the protocol in rawData) 351 | let fileData = parseFileData(rawData); 352 | // write data to a local file 353 | let writeAsync = Promise.promisify(fs.writeFile); 354 | await writeAsync(destination, fileData); // do we need to await this line? 355 | return fileSize; 356 | } 357 | 358 | // install an APK on the device, uses push and shell 359 | async install (apkSource) { 360 | await this.push(apkSource, installLocation); 361 | let fileName = getFileName(apkSource); 362 | logExceptOnTest("filename: ", fileName); 363 | let shellString = `pm install ${installLocation}${fileName}`; 364 | logExceptOnTest("shellString: ", shellString); 365 | await this.shell(shellString); 366 | } 367 | 368 | async uninstall (packageName) { 369 | let shellString = `${uninstallString} ${packageName}`; 370 | return await this.shell(shellString); 371 | } 372 | 373 | // runs an ADB shell command on the device, such as shell ls -al 374 | async shell (commandString, print) { 375 | let shellString = `shell:${commandString}.`; 376 | let packet = await this.sendAndOkay(ADB_COMMANDS.CMD_OPEN 377 | , 12345 378 | , 0 379 | , shellString); 380 | // this is our local id, the devices remote id 381 | let localId = packet.arg2; 382 | // this is our remote id, the devices local id 383 | let remoteId = packet.arg1; 384 | let command = packet.command; 385 | let output = ""; 386 | if (command !== ADB_COMMANDS.CMD_OKAY) { 387 | throw new Error("OPEN response was not OKAY"); 388 | } 389 | // we want to read packets from the device unti we get one with a command 390 | // of CLSE, which signals the end of the transmission for the shell command 391 | do { 392 | packet = await this.device._recvMsg(CONNECT_VALUES.CONNECT_MAXDATA); 393 | command = packet.command; 394 | if (command === ADB_COMMANDS.CMD_WRTE) { 395 | if (print) { // the data we recv back from the device will already contain newlines 396 | process.stdout.write(packet.data.toString()); 397 | } else { 398 | output += packet.data.toString(); 399 | } 400 | // send and okay so the device knows it can send us more data 401 | await this.device._sendMsg(ADB_COMMANDS.CMD_OKAY 402 | , localId 403 | , remoteId 404 | , ""); 405 | } 406 | } while (command !== ADB_COMMANDS.CMD_CLSE); 407 | logExceptOnTest("Shell read loop has finished"); 408 | // we got a CLSE, now we send a CLSE to close off the connection 409 | await this.device._sendMsg(ADB_COMMANDS.CMD_CLSE 410 | , localId 411 | , remoteId 412 | , ""); 413 | logExceptOnTest("Sent CLSE."); 414 | return output; 415 | } 416 | 417 | // pretty simple, just reboots the device via it's own OPEN string 418 | async reboot () { 419 | let rebootBuffer = new Buffer("reboot:."); 420 | await this.sendAndOkay(ADB_COMMANDS.CMD_OPEN 421 | , 12345 422 | , 0 423 | , rebootBuffer); 424 | } 425 | 426 | // open a stream to a certain path on the device 427 | // as an example, shell: opens a shell into the device 428 | async open (command) { 429 | let output = null; 430 | logExceptOnTest("open"); 431 | switch (command.type) { 432 | case "shell": 433 | output = await this.shell(command.string, command.print); 434 | break; 435 | case "push": 436 | try { 437 | await fs.stat(command.source); 438 | } catch (err) { 439 | logExceptOnTest("The file you're trying to push doesn't exist."); 440 | output = -1; 441 | break; 442 | } 443 | await this.push(command.source, command.destination); 444 | break; 445 | case "pull": 446 | output = await this.pull(command.source, command.destination); 447 | break; 448 | case "list": 449 | output = await this.list(command.remotePath); 450 | break; 451 | case "install": 452 | await this.install(command.source); 453 | break; 454 | case "uninstall": 455 | output = await this.uninstall(command.packageName); 456 | break; 457 | case "reboot": 458 | await this.reboot(); 459 | break; 460 | default: 461 | // TODO: change this to throw an error, test that the error is thrown? 462 | logExceptOnTest("Sorry, that command type isn't supported yet: ", command.type); 463 | break; 464 | } 465 | // console.log("returning from open: ", output); 466 | return output; 467 | } 468 | 469 | // calls claim device (if usb) and then performs the ADB usb handshake 470 | // returns a promise, will have the error value if an error is thrown 471 | async initConnection () { 472 | if (this.connectionType === CONNECTION_TYPES.USB) { 473 | this.device.claimDevice(); 474 | logExceptOnTest("claimed device"); 475 | } 476 | logExceptOnTest("Trying to establish a connection with the device"); 477 | await this.device._sendMsg(ADB_COMMANDS.CMD_CNXN 478 | , CONNECT_VALUES.CONNECT_VERSION 479 | , CONNECT_VALUES.CONNECT_MAXDATA 480 | , CONNECT_VALUES.CONNECT_PAYLOAD); 481 | logExceptOnTest("Sent connect message."); 482 | } 483 | 484 | // after we send a connect message we should recv AUTH back from the device 485 | async waitForAuth () { 486 | let packet = await this.device._recvMsg(CONNECT_VALUES.CONNECT_MAXDATA); 487 | if (packet.command === ADB_COMMANDS.CMD_AUTH) { 488 | return packet; 489 | } 490 | return false; 491 | } 492 | 493 | // see if the device will accept the token from it's AUTH packet 494 | // signed with our private key 495 | async sendSignedToken (token) { 496 | let signedToken = signLib.sign(new Buffer(privateKeyPath + "\0"), token); 497 | // see if the device will accept our signed token 498 | await this.device._sendMsg(ADB_COMMANDS.CMD_AUTH, 2, 0, signedToken); 499 | let packet = await this.device._recvMsg(CONNECT_VALUES.CONNECT_MAXDATA); 500 | return packet.command === ADB_COMMANDS.CMD_CNXN; 501 | } 502 | 503 | // device didn't accept signed token, send it our public key 504 | async sendPublicKey () { 505 | let publicKeyBuf = new Buffer(publicKeyString.length + 1); 506 | publicKeyString.copy(publicKeyBuf); 507 | publicKeyBuf[-1] = 0; 508 | await this.device._sendMsg(ADB_COMMANDS.CMD_AUTH, 3, 0, publicKeyBuf); 509 | let packet = await this.device._recvMsg(CONNECT_VALUES.CONNECT_MAXDATA); 510 | logExceptOnTest("Sent auth message and public key"); 511 | return packet.command === ADB_COMMANDS.CMD_CNXN; 512 | } 513 | 514 | // send a close to the device and recv an clse back from it 515 | // this should only be necessary if we open a stream to the device 516 | async close (localId, remoteId) { 517 | await this.device._sendMsg(ADB_COMMANDS.CMD_CLSE 518 | , localId 519 | , remoteId 520 | , ""); 521 | // it seems like sometimes we read an OKAY here 522 | while (1) { 523 | let packet = await this.device._recvMsg(localId, remoteId); 524 | if (packet.command === ADB_COMMANDS.CMD_CLSE) { 525 | return; 526 | } else { 527 | continue; 528 | } 529 | } 530 | } 531 | 532 | async closeConnection () { 533 | await this.device.releaseDevice(); 534 | } 535 | } 536 | 537 | export default ADBDevice; 538 | -------------------------------------------------------------------------------- /lib/constants.js: -------------------------------------------------------------------------------- 1 | //ID of device manufacturers 2 | const USB_VENDOR_IDS = [ 3 | 0x18d1, //VENDOR_ID_GOOGLE 4 | 0x8087, //VENDOR_ID_INTEL 5 | 0x0bb4, //VENDOR_ID_HTC 6 | 0x04e8, //VENDOR_ID_SAMSUNG 7 | 0x22b8, //VENDOR_ID_MOTOROLA 8 | 0x1004, //VENDOR_ID_LGE 9 | 0x12D1, //VENDOR_ID_HUAWEI 10 | 0x0502, //VENDOR_ID_ACER 11 | 0x0FCE, //VENDOR_ID_SONY_ERICSSON 12 | 0x0489, //VENDOR_ID_FOXCONN 13 | 0x413c, //VENDOR_ID_DELL 14 | 0x0955, //VENDOR_ID_NVIDIA 15 | 0x091E, //VENDOR_ID_GARMIN_ASUS 16 | 0x04dd, //VENDOR_ID_SHARP 17 | 0x19D2, //VENDOR_ID_ZTE 18 | 0x0482, //VENDOR_ID_KYOCERA 19 | 0x10A9, //VENDOR_ID_PANTECH 20 | 0x05c6, //VENDOR_ID_QUALCOMM 21 | 0x2257, //VENDOR_ID_OTGV 22 | 0x0409, //VENDOR_ID_NEC 23 | 0x04DA, //VENDOR_ID_PMC 24 | 0x0930, //VENDOR_ID_TOSHIBA 25 | 0x1F53, //VENDOR_ID_SK_TELESYS 26 | 0x2116, //VENDOR_ID_KT_TECH 27 | 0x0b05, //VENDOR_ID_ASUS 28 | 0x0471, //VENDOR_ID_PHILIPS 29 | 0x0451, //VENDOR_ID_TI 30 | 0x0F1C, //VENDOR_ID_FUNAI 31 | 0x0414, //VENDOR_ID_GIGABYTE 32 | 0x2420, //VENDOR_ID_IRIVER 33 | 0x1219, //VENDOR_ID_COMPAL 34 | 0x1BBB, //VENDOR_ID_T_AND_A 35 | 0x2006, //VENDOR_ID_LENOVOMOBILE 36 | 0x17EF, //VENDOR_ID_LENOVO 37 | 0xE040, //VENDOR_ID_VIZIO 38 | 0x24E3, //VENDOR_ID_K_TOUCH 39 | 0x1D4D, //VENDOR_ID_PEGATRON 40 | 0x0E79, //VENDOR_ID_ARCHOS 41 | 0x1662, //VENDOR_ID_POSITIVO 42 | 0x04C5, //VENDOR_ID_FUJITSU 43 | 0x25E3, //VENDOR_ID_LUMIGON 44 | 0x0408, //VENDOR_ID_QUANTA 45 | 0x2314, //VENDOR_ID_INQ_MOBILE 46 | 0x054C, //VENDOR_ID_SONY 47 | 0x1949, //VENDOR_ID_LAB126 48 | 0x1EBF, //VENDOR_ID_YULONG_COOLPAD 49 | 0x2237, //VENDOR_ID_KOBO 50 | 0x2340 //VENDOR_ID_TELEEPOCH 51 | ]; 52 | 53 | const ADB_VALUES = { 54 | ADB_CLASS: 0xff 55 | , ADB_SUBCLASS: 0x42 56 | , ADB_PROTOCOL: 0x01 57 | , ADB_HEADER_LENGTH: 24 58 | }; 59 | 60 | const CONNECT_VALUES = { 61 | CONNECT_VERSION: 0x01000000 62 | , CONNECT_MAXDATA: 4096 63 | , CONNECT_PAYLOAD: "host::" 64 | }; 65 | 66 | const ADB_COMMANDS = { 67 | CMD_CNXN: 0x4e584e43 68 | , CMD_AUTH: 0x48545541 69 | , CMD_OPEN: 0x4e45504f 70 | , CMD_OKAY: 0x59414b4f 71 | , CMD_WRTE: 0x45545257 72 | , CMD_SYNC: 0x434e5953 73 | , CMD_CLSE: 0x45534c43 74 | }; 75 | 76 | const ADB_SUBCOMMANDS = { 77 | CMD_STAT: 0x54415453 78 | , CMD_SEND: 0x444E4553 79 | , CMD_RECV: 0x56434552 80 | , CMD_QUIT: 0x54495551 81 | , CMD_FAIL: 0x4c494146 82 | , CMD_DONE: 0x454e4f44 83 | , CMD_DATA: 0x41544144 84 | , CMD_LIST: 0x5453494c 85 | }; 86 | 87 | const FILE_TYPES = { 88 | FILE: 0b100 89 | , DIRECTORY: 0b010 90 | , SYMLINK: 0b101 91 | }; 92 | 93 | //TODO: detect these or command line arguement? 94 | const ADB_KEY = { 95 | PUBLIC_KEY: ".android/adbkey.pub" 96 | , PRIVATE_KEY: ".android/adbkey" 97 | }; 98 | 99 | const CONNECTION_TYPES = { 100 | USB: 0 101 | , TCP: 1 102 | }; 103 | 104 | const LIBUSB_VALUES = { 105 | LIBUSB_ENDPOINT_IN: 128 106 | , LIBUSB_ENDPOINT_OUT: 0 107 | , LIBUSB_TRANSFER_TYPE_BULK: 2 108 | }; 109 | 110 | export { USB_VENDOR_IDS, ADB_VALUES, CONNECT_VALUES, ADB_COMMANDS 111 | , ADB_SUBCOMMANDS, ADB_KEY, CONNECTION_TYPES, LIBUSB_VALUES, FILE_TYPES }; 112 | -------------------------------------------------------------------------------- /lib/examples/install.js: -------------------------------------------------------------------------------- 1 | // transpile:main 2 | import ADB from '../../adb'; 3 | import { CONNECTION_TYPES } from '../constants'; 4 | import { asyncify } from 'asyncbox'; 5 | import path from 'path'; 6 | 7 | async function start () { 8 | let availableDevices = await ADB.findAdbDevices(); 9 | if (availableDevices.length > 0) { 10 | let device = new ADB(CONNECTION_TYPES.USB, availableDevices[0]); 11 | await device.connect(); 12 | console.log("connected"); 13 | let apkSource = path.resolve(__dirname 14 | , ".." 15 | , ".." 16 | , ".." 17 | , "test" 18 | , "fixtures" 19 | , "contactManager.apk"); 20 | let command = { 21 | type: "install" 22 | , source: apkSource 23 | }; 24 | await device.runCommand(command); 25 | await device.closeConnection(); 26 | console.log("closed"); 27 | } 28 | } 29 | 30 | console.log("Starting!"); 31 | asyncify(start); -------------------------------------------------------------------------------- /lib/examples/list.es5.js: -------------------------------------------------------------------------------- 1 | var ADB = require('./build/adb'); 2 | var CONNECTION_TYPES = require('./build/lib/constants').CONNECTION_TYPES; 3 | 4 | console.log("Starting."); 5 | var device; 6 | 7 | ADB.findAdbDevices().then(function (availableDevices) { 8 | if (availableDevices.length === 0) return; 9 | device = new ADB(CONNECTION_TYPES.USB, availableDevices[0]); 10 | return device.connect(); 11 | }).then(function () { 12 | console.log("connected"); 13 | var command = { 14 | type: "list" 15 | , remotePath: "sdcard" 16 | }; 17 | return device.runCommand(command); 18 | }).then(function (output) { 19 | console.log(output); 20 | return device.closeConnection(); 21 | }).then(function () { 22 | console.log('closed'); 23 | }).catch(function (err) { 24 | console.log(err); 25 | }); 26 | -------------------------------------------------------------------------------- /lib/examples/list.js: -------------------------------------------------------------------------------- 1 | // transpile:main 2 | import ADB from '../../adb'; 3 | import { CONNECTION_TYPES } from '../constants'; 4 | import { asyncify } from 'asyncbox'; 5 | 6 | async function start () { 7 | let availableDevices = await ADB.findAdbDevices(); 8 | if (availableDevices.length > 0) { 9 | // just select the first device 10 | let device = new ADB(CONNECTION_TYPES.USB, availableDevices[0]); 11 | await device.connect(); 12 | console.log("connected"); 13 | let command = { 14 | type: "list" 15 | , remotePath: "sdcard" 16 | }; 17 | let output = await device.runCommand(command); 18 | await device.closeConnection(); 19 | console.log(output); 20 | } 21 | } 22 | 23 | console.log("Starting."); 24 | asyncify(start); 25 | -------------------------------------------------------------------------------- /lib/examples/pull.js: -------------------------------------------------------------------------------- 1 | // transpile:main 2 | import ADB from '../../adb'; 3 | import { CONNECTION_TYPES } from '../constants'; 4 | import { asyncify } from 'asyncbox'; 5 | import path from 'path'; 6 | 7 | async function start () { 8 | let availableDevices = await ADB.findAdbDevices(); 9 | if (availableDevices.length > 0) { 10 | // just select the first device 11 | let device = new ADB(CONNECTION_TYPES.USB, availableDevices[0]); 12 | await device.connect(); 13 | console.log("connected"); 14 | let destinationFile = path.resolve(__dirname 15 | , ".." 16 | , ".." 17 | , "largeFile"); 18 | let command = { 19 | type: "pull" 20 | , source: "sdcard/largeFile" 21 | , destination: destinationFile 22 | }; 23 | await device.runCommand(command); 24 | await device.closeConnection(); 25 | console.log("closed"); 26 | } 27 | } 28 | 29 | console.log("Starting!"); 30 | asyncify(start); -------------------------------------------------------------------------------- /lib/examples/push.js: -------------------------------------------------------------------------------- 1 | // transpile:main 2 | import ADB from '../../adb'; 3 | import { CONNECTION_TYPES } from '../constants'; 4 | import { asyncify } from 'asyncbox'; 5 | import path from 'path'; 6 | 7 | async function start () { 8 | let availableDevices = await ADB.findAdbDevices(); 9 | if (availableDevices.length > 0) { 10 | // just select the first device 11 | let device = new ADB(CONNECTION_TYPES.USB, availableDevices[0]); 12 | await device.connect(); 13 | console.log("connected"); 14 | let fileSource = path.resolve(__dirname 15 | , ".." 16 | , ".." 17 | , ".." 18 | , "test" 19 | , "fixtures" 20 | , "largeFile"); 21 | let command = { 22 | type: "push" 23 | , source: fileSource 24 | , destination: "sdcard/" 25 | }; 26 | await device.runCommand(command); 27 | await device.closeConnection(); 28 | console.log("closed"); 29 | } 30 | } 31 | 32 | console.log("Starting!"); 33 | asyncify(start); 34 | -------------------------------------------------------------------------------- /lib/examples/reboot.js: -------------------------------------------------------------------------------- 1 | // transpile:main 2 | import ADB from '../../adb'; 3 | import { CONNECTION_TYPES } from '../constants'; 4 | import { asyncify } from 'asyncbox'; 5 | 6 | async function start () { 7 | let availableDevices = await ADB.findAdbDevices(); 8 | if (availableDevices.length > 0) { 9 | // just select the first device 10 | let device = new ADB(CONNECTION_TYPES.USB, availableDevices[0]); 11 | await device.connect(); 12 | console.log("connected"); 13 | let command = { 14 | type: "reboot" 15 | }; 16 | await device.runCommand(command); 17 | await device.closeConnection(); 18 | console.log("closed"); 19 | } 20 | } 21 | 22 | console.log("starting"); 23 | asyncify(start); -------------------------------------------------------------------------------- /lib/examples/shell.js: -------------------------------------------------------------------------------- 1 | // transpile:main 2 | import ADB from '../../adb'; 3 | import { CONNECTION_TYPES } from '../constants'; 4 | import { asyncify } from 'asyncbox'; 5 | 6 | async function start () { 7 | let availableDevices = await ADB.findAdbDevices(); 8 | if (availableDevices.length > 0) { 9 | // just select the first device 10 | let device = new ADB(CONNECTION_TYPES.USB, availableDevices[0]); 11 | await device.connect(); 12 | console.log("connected"); 13 | let command = { 14 | type: "shell" 15 | , string: "getprop ro.build.version.sdk" 16 | }; 17 | await device.runCommand(command); 18 | await device.closeConnection(); 19 | console.log("closed"); 20 | } 21 | } 22 | 23 | console.log("Starting."); 24 | asyncify(start); -------------------------------------------------------------------------------- /lib/examples/shellBySerial.js: -------------------------------------------------------------------------------- 1 | // transpile:main 2 | import ADB from '../../adb'; 3 | import { CONNECTION_TYPES } from '../constants'; 4 | import { asyncify } from 'asyncbox'; 5 | import { selectBySerialNumber } from '../../lib/helpers'; 6 | 7 | async function start () { 8 | let availableDevices = await ADB.findAdbDevices(); 9 | if (availableDevices.length > 0) { 10 | // select device by serial number: 4d00a90c4f041119 11 | let serial = "4d00a90c4f041119"; 12 | let selectedDevice = selectBySerialNumber(availableDevices, serial); 13 | let device = new ADB(CONNECTION_TYPES.USB, selectedDevice); 14 | await device.connect(); 15 | console.log("connected"); 16 | let command = { 17 | type: "shell" 18 | , string: "getprop ro.build.version.sdk" 19 | }; 20 | await device.runCommand(command); 21 | await device.closeConnection(); 22 | console.log("closed"); 23 | } 24 | } 25 | 26 | console.log("Starting."); 27 | asyncify(start); -------------------------------------------------------------------------------- /lib/examples/uninstall.js: -------------------------------------------------------------------------------- 1 | // transpile:main 2 | import ADB from '../../adb'; 3 | import { CONNECTION_TYPES } from '../constants'; 4 | import { asyncify } from 'asyncbox'; 5 | 6 | async function start () { 7 | let availableDevices = await ADB.findAdbDevices(); 8 | if (availableDevices.length > 0) { 9 | let device = new ADB(CONNECTION_TYPES.USB, availableDevices[0]); 10 | await device.connect(); 11 | console.log("connected"); 12 | let command = { 13 | type: "uninstall" 14 | , packageName: "com.example.android.contactmanager" 15 | }; 16 | await device.runCommand(command); 17 | await device.closeConnection(); 18 | console.log("closed"); 19 | } 20 | } 21 | 22 | console.log("Starting!"); 23 | asyncify(start); -------------------------------------------------------------------------------- /lib/helpers.js: -------------------------------------------------------------------------------- 1 | import { CONNECTION_TYPES, ADB_COMMANDS, ADB_SUBCOMMANDS } from './constants'; 2 | import _ from 'underscore'; 3 | const ADB_HEADER_LENGTH = 24; 4 | 5 | function crc (buf) { 6 | if (!buf) return 0; 7 | let crcResult = 0; 8 | // this loop doesn't want to be a let item of object loop 9 | for (let i = 0; i < buf.length; i++) { 10 | crcResult = (crcResult + buf[i]) & 0xFFFFFFFF; 11 | } 12 | return crcResult; 13 | } 14 | 15 | // generates a message according to the ADB packet specifications 16 | // noTte that we don't append the actual data payload to the message 17 | // unless we're on tcp, and if you want to pass no payload use "" 18 | function generateMessage (cmd, arg1, arg2, payload, connectionType) { 19 | // default connectionType to usb since tha's what we expect 20 | // the connection to be most of the time 21 | connectionType = typeof connectionType !== 'undefined' ? connectionType 22 | : CONNECTION_TYPES.USB; 23 | // cmd needs to be an ADB command 24 | if (_.contains(_.values(ADB_COMMANDS), cmd) === false) { 25 | throw new Error("generateMessage: invalid command type"); 26 | } 27 | // connection type can only be USB or TCP 28 | if (_.contains(_.values(CONNECTION_TYPES), connectionType) === false) { 29 | throw new Error("generateMessage: invalid connection type"); 30 | } 31 | if (_.isNumber(payload)) { 32 | payload = payload.toString(); 33 | } 34 | 35 | let payloadBuffer = !Buffer.isBuffer(payload) ? new Buffer(payload) 36 | : payload; 37 | 38 | let msgLength = ADB_HEADER_LENGTH; 39 | // only allocate space for data payload if we're going to fill that field 40 | if (connectionType === CONNECTION_TYPES.TCP) { 41 | msgLength = msgLength + payloadBuffer.length; 42 | } 43 | 44 | let message = new Buffer(msgLength); 45 | message.writeUInt32LE(cmd, 0); 46 | message.writeUInt32LE(arg1, 4); 47 | message.writeUInt32LE(arg2, 8); 48 | 49 | if (payload !== null) { 50 | message.writeUInt32LE(payloadBuffer.length, 12); 51 | message.writeUInt32LE(crc(payloadBuffer), 16); 52 | } 53 | let magic = 0xFFFFFFFF - cmd; 54 | message.writeUInt32LE(magic, 20); 55 | //connection type TCP 56 | if (connectionType === CONNECTION_TYPES.TCP) { 57 | payloadBuffer.copy(message, 24); 58 | } 59 | return message; 60 | } 61 | 62 | // block console logging when tests are being run 63 | function logExceptOnTest (string) { 64 | if (process.env.NODE_ENV !== 'test') { 65 | console.log(string); 66 | } 67 | } 68 | 69 | // select a device from the list of available devices by serial number 70 | function selectBySerialNumber (devices, serialNumber) { 71 | for (let device of devices) { 72 | if (serialNumber === device.serialNumber) { 73 | return device; 74 | } 75 | } 76 | throw new Error("No device available with the serial number: ", serialNumber); 77 | } 78 | 79 | 80 | // takes a buffer from an inputEndpoint read and 81 | // creates the packet structure from the data 82 | function packetFromBuffer (buf) { 83 | //set the fields we are guaranteed to have 84 | let packet = { 85 | "command": buf.readUInt32LE(0) 86 | , "arg1": buf.readUInt32LE(4) 87 | , "arg2": buf.readUInt32LE(8) 88 | , "dataLen": buf.readUInt32LE(12) 89 | , "dataCrc": buf.readUInt32LE(16) 90 | , "magic": buf.readUInt32LE(20) 91 | }; 92 | if (packet.dataLen > 0) { 93 | packet.data = buf.slice(24, (24 + packet.dataLen)); 94 | } 95 | return packet; 96 | } 97 | 98 | // takes a file path (seperated by /'s') and gets the file name from 99 | // the end of the path, returns the file name 100 | function getFileName (path) { 101 | let splitArray = path.split("/"); 102 | return splitArray[splitArray.length - 1]; 103 | } 104 | 105 | // copy the actual file data out of the mess of ADB protocol information 106 | function parseFileData (rawData) { 107 | let currentPosition = 0; 108 | let fileData = new Buffer(""); 109 | while (true) { 110 | // get the length (DATA) so we know how much to copy 111 | let length = rawData.readUInt32LE(currentPosition + 4); 112 | currentPosition += 8; 113 | let chunk = new Buffer(length); 114 | rawData.copy(chunk, 0, currentPosition, currentPosition + length); 115 | currentPosition += length; 116 | fileData = Buffer.concat([fileData, chunk]); 117 | if (rawData.readUInt32LE(currentPosition) === ADB_SUBCOMMANDS.CMD_DONE) { 118 | break; 119 | } 120 | } 121 | return fileData; 122 | } 123 | 124 | export { generateMessage, packetFromBuffer 125 | , selectBySerialNumber, getFileName 126 | , parseFileData, logExceptOnTest }; 127 | -------------------------------------------------------------------------------- /lib/usb-device.js: -------------------------------------------------------------------------------- 1 | // import constants 2 | import { LIBUSB_VALUES } from './constants'; 3 | import { generateMessage, packetFromBuffer, logExceptOnTest } from './helpers'; 4 | 5 | // required libraries 6 | import _ from 'underscore'; 7 | import Promise from 'bluebird'; 8 | // local constants 9 | const LIBUSB_TRANSFER_TYPE_BULK = LIBUSB_VALUES.LIBUSB_TRANSFER_TYPE_BULK; 10 | 11 | class USBDevice { 12 | constructor (device, deviceInterface) { 13 | this.device = device; 14 | this.deviceInterface = deviceInterface; 15 | } 16 | 17 | // opens the device and sets up the endpoints for out object 18 | claimDevice () { 19 | logExceptOnTest("Trying to claim the device."); 20 | // we need to call these in OSX, see nonolith/nodeusb issue#61 21 | if (process.platform === 'darwin') { 22 | this.device.__open(); 23 | this.device.__claimInterface(0); 24 | } 25 | this.device.open(); 26 | logExceptOnTest("Device opened."); 27 | this.deviceInterface = Promise.promisifyAll(this.deviceInterface); 28 | this.deviceInterface.claim(); 29 | // this line causes LIBUSB_ERROR_OTHER on S4s, but S4s and S5s work without it 30 | // await this.deviceInterface.setAltSettingAsync(0); 31 | let endpoints = this.deviceInterface.endpoints; 32 | this.setEndpoints(endpoints); 33 | } 34 | 35 | setEndpoints (endpoints) { 36 | if (endpoints[0].direction === "out") { 37 | this.inputEndpoint = endpoints[1]; 38 | this.outputEndpoint = endpoints[0]; 39 | } else { 40 | this.inputEndpoint = endpoints[0]; 41 | this.outputEndpoint = endpoints[1]; 42 | } 43 | this.inputEndpoint.transferType = LIBUSB_TRANSFER_TYPE_BULK; 44 | this.outputEndpoint.transferType = LIBUSB_TRANSFER_TYPE_BULK; 45 | this.inputEndpoint.timeout = 2000; 46 | this.outputEndpoint = Promise.promisifyAll(this.outputEndpoint); 47 | this.inputEndpoint = Promise.promisifyAll(this.inputEndpoint); 48 | } 49 | 50 | // sends a message as an adb packet followed by the payload if necessary 51 | async _sendMsg (cmd, arg1, arg2, payload) { 52 | let adbPacket = generateMessage(cmd, arg1, arg2, payload); 53 | await this.outputEndpoint.transferAsync(adbPacket); 54 | if (payload !== "") { 55 | if (_.isNumber(payload)) { 56 | payload = payload.toString(); 57 | } else if (typeof payload !== Buffer) { 58 | payload = new Buffer(payload); 59 | } 60 | await this.outputEndpoint.transferAsync(payload); 61 | } 62 | } 63 | 64 | // receives a message from a device 65 | // handles reading the adb packet and if necessarry the data payload 66 | async _recvMsg (amount) { 67 | let data = await this.inputEndpoint.transferAsync(amount); 68 | let dataLen = data.readUInt32LE(12); 69 | if (dataLen > 0) { 70 | let additionalData = await this.getPacketData(amount, dataLen); 71 | data = Buffer.concat([data, additionalData]); 72 | } 73 | let packet = packetFromBuffer(data); 74 | return packet; 75 | } 76 | 77 | async getPacketData (maxRead, amount) { 78 | let dataLen = amount; 79 | let data = new Buffer(""); 80 | while (dataLen > 0) { 81 | let readData = await this.inputEndpoint.transferAsync(maxRead); 82 | dataLen = dataLen - readData.length; 83 | data = Buffer.concat([data, readData]); 84 | } 85 | return data; 86 | } 87 | 88 | async releaseDevice () { 89 | await this.deviceInterface.releaseAsync(true); 90 | this.device.close(); 91 | } 92 | } 93 | 94 | export default USBDevice; 95 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "node-adb-client", 3 | "description": "Description goes here.", 4 | "keywords": [ 5 | "appium" 6 | ], 7 | "version": "0.0.0", 8 | "author": "appium", 9 | "license": "Apache-2.0", 10 | "repository": { 11 | "type": "git", 12 | "url": "https://github.com/appium/node-adb-client.git" 13 | }, 14 | "bugs": { 15 | "url": "https://github.com/appium/node-adb-client/issues" 16 | }, 17 | "engines": [ 18 | "node" 19 | ], 20 | "main": "./build/index.js", 21 | "bin": {}, 22 | "directories": { 23 | "lib": "lib" 24 | }, 25 | "dependencies": { 26 | "appium-support": "^2.2.1", 27 | "asyncbox": "^2.0.4", 28 | "babel-runtime": "=6.6.1", 29 | "bluebird": "^3.3.4", 30 | "nan": "^2.1.0", 31 | "source-map-support": "^0.4.0", 32 | "underscore": "^1.8.3", 33 | "usb": "^1.1.2" 34 | }, 35 | "scripts": { 36 | "prepublish": "./node_modules/.bin/gulp prepublish", 37 | "test": "./node_modules/.bin/gulp once", 38 | "watch": "./node_modules/.bin/gulp" 39 | }, 40 | "devDependencies": { 41 | "appium-gulp-plugins": "^1.4.5", 42 | "appium-test-support": "0.0.5", 43 | "chai": "^3.0.0", 44 | "chai-as-promised": "^5.1.0", 45 | "gulp": "^3.8.11", 46 | "mochawait": "^2.0.0", 47 | "proxyquire": "^1.6.0", 48 | "yargs": "^4.3.2" 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /test/.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "laxcomma": true, 3 | "undef": true, 4 | "unused": true, 5 | "trailing": true, 6 | "node": true, 7 | "eqeqeq": true, 8 | "trailing": true, 9 | "expr": true, 10 | "white": true, 11 | "indent": 2, 12 | "esnext": true, 13 | "experimental": ["asyncawait"], 14 | "globals": { 15 | "describe": true, 16 | "it": true, 17 | "before": true, 18 | "after": true, 19 | "beforeEach": true, 20 | "afterEach": true 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /test/fixtures/ContactManager.apk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/appium/node-adb-client/4549760ca6f79f0f7dae5d41b2b1d1502774e20d/test/fixtures/ContactManager.apk -------------------------------------------------------------------------------- /test/fixtures/smallFile: -------------------------------------------------------------------------------- 1 | 0a0d 0d0a 6c00 0000 4d3c 2b1a 0100 0000 2 | ffff ffff ffff ffff 0300 1700 4c69 6e75 3 | 7820 332e 3136 2e30 2d33 302d 6765 6e65 4 | 7269 6300 0400 2900 4475 6d70 6361 7020 5 | 312e 3130 2e36 2028 7631 2e31 302e 3620 6 | 6672 6f6d 206d 6173 7465 722d 312e 3130 7 | 2900 0000 0000 0000 6c00 0000 0100 0000 8 | 4800 0000 dc00 0000 ffff 0000 0200 0700 9 | 7573 626d 6f6e 3100 0900 0100 0600 0000 10 | 0c00 1700 4c69 6e75 7820 332e 3136 2e30 11 | 2d33 302d 6765 6e65 7269 6300 0000 0000 12 | 4800 0000 0600 0000 6000 0000 0000 0000 13 | f41b 0500 2654 b6d9 4000 0000 4000 0000 14 | 8047 18c8 0088 ffff 5302 800f 0100 003c 15 | 2ade b755 0000 0000 a6f5 0100 8dff ffff 16 | 2800 0000 0000 0000 8006 0001 0000 2800 17 | 0000 0000 0000 0000 0002 0000 0000 0000 18 | 6000 0000 0600 0000 7400 0000 0000 0000 19 | f41b 0500 b070 b6d9 5200 0000 5200 0000 20 | 8047 18c8 0088 ffff 4302 800f 0100 2d00 21 | 2ade b755 0000 0000 3012 0200 0000 0000 22 | 1200 0000 1200 0000 0000 0000 0000 0000 23 | 0000 0000 0000 0000 0002 0000 0000 0000 24 | 1201 1002 0000 0040 e804 6068 0004 0102 25 | 0301 0000 7400 0000 0600 0000 6000 0000 26 | 0000 0000 f41b 0500 f870 b6d9 4000 0000 27 | 4000 0000 8047 18c8 0088 ffff 5302 8001 28 | 0100 003c 2ade b755 0000 0000 7812 0200 29 | 8dff ffff 2800 0000 0000 0000 8006 0001 30 | 0a0d 0d0a 6c00 0000 4d3c 2b1a 0100 0000 31 | ffff ffff ffff ffff 0300 1700 4c69 6e75 32 | 7820 332e 3136 2e30 2d33 302d 6765 6e65 33 | 7269 6300 0400 2900 4475 6d70 6361 7020 34 | 312e 3130 2e36 2028 7631 2e31 302e 3620 35 | 6672 6f6d 206d 6173 7465 722d 312e 3130 36 | 2900 0000 0000 0000 6c00 0000 0100 0000 37 | 4800 0000 dc00 0000 ffff 0000 0200 0700 38 | 7573 626d 6f6e 3100 0900 0100 0600 0000 39 | 0c00 1700 4c69 6e75 7820 332e 3136 2e30 40 | 2d33 302d 6765 6e65 7269 6300 0000 0000 41 | 4800 0000 0600 0000 6000 0000 0000 0000 42 | f41b 0500 2654 b6d9 4000 0000 4000 0000 43 | 8047 18c8 0088 ffff 5302 800f 0100 003c 44 | 2ade b755 0000 0000 a6f5 0100 8dff ffff 45 | 2800 0000 0000 0000 8006 0001 0000 2800 46 | 0000 0000 0000 0000 0002 0000 0000 0000 47 | 6000 0000 0600 0000 7400 0000 0000 0000 48 | f41b 0500 b070 b6d9 5200 0000 5200 0000 49 | 8047 18c8 0088 ffff 4302 800f 0100 2d00 50 | 2ade b755 0000 0000 3012 0200 0000 0000 51 | 1200 0000 1200 0000 0000 0000 0000 0000 52 | 0000 0000 0000 0000 0002 0000 0000 0000 53 | 1201 1002 0000 0040 e804 6068 0004 0102 54 | 0301 0000 7400 0000 0600 0000 6000 0000 55 | 0000 0000 f41b 0500 f870 b6d9 4000 0000 56 | 4000 0000 8047 18c8 0088 ffff 5302 8001 57 | 0100 003c 2ade b755 0000 0000 7812 0200 58 | 8dff ffff 2800 0000 0000 0000 8006 0001 59 | 0a0d 0d0a 6c00 0000 4d3c 2b1a 0100 0000 60 | ffff ffff ffff ffff 0300 1700 4c69 6e75 61 | 7820 332e 3136 2e30 2d33 302d 6765 6e65 62 | 7269 6300 0400 2900 4475 6d70 6361 7020 63 | 312e 3130 2e36 2028 7631 2e31 302e 3620 64 | 6672 6f6d 206d 6173 7465 722d 312e 3130 65 | 2900 0000 0000 0000 6c00 0000 0100 0000 66 | 4800 0000 dc00 0000 ffff 0000 0200 0700 67 | 7573 626d 6f6e 3100 0900 0100 0600 0000 68 | 0c00 1700 4c69 6e75 7820 332e 3136 2e30 69 | 2d33 302d 6765 6e65 7269 6300 0000 0000 70 | 4800 0000 0600 0000 6000 0000 0000 0000 71 | f41b 0500 2654 b6d9 4000 0000 4000 0000 72 | 8047 18c8 0088 ffff 5302 800f 0100 003c 73 | 2ade b755 0000 0000 a6f5 0100 8dff ffff 74 | 2800 0000 0000 0000 8006 0001 0000 2800 75 | 0000 0000 0000 0000 0002 0000 0000 0000 76 | 6000 0000 0600 0000 7400 0000 0000 0000 77 | f41b 0500 b070 b6d9 5200 0000 5200 0000 78 | 8047 18c8 0088 ffff 4302 800f 0100 2d00 79 | 2ade b755 0000 0000 3012 0200 0000 0000 80 | 1200 0000 1200 0000 0000 0000 0000 0000 81 | 0000 0000 0000 0000 0002 0000 0000 0000 82 | 1201 1002 0000 0040 e804 6068 0004 0102 83 | 0301 0000 7400 0000 0600 0000 6000 0000 84 | 0000 0000 f41b 0500 f870 b6d9 4000 0000 85 | 4000 0000 8047 18c8 0088 ffff 5302 8001 86 | 0100 003c 2ade b755 0000 0000 7812 0200 87 | 8dff ffff 2800 0000 0000 0000 8006 0001 -------------------------------------------------------------------------------- /test/functional/adb-e2e-specs.js: -------------------------------------------------------------------------------- 1 | // transpile:mocha 2 | 3 | import ADB from "../../adb"; 4 | import path from 'path'; 5 | import chai from 'chai'; 6 | import chaiAsPromised from 'chai-as-promised'; 7 | import { fs } from 'appium-support'; 8 | import { CONNECTION_TYPES, FILE_TYPES } from '../../lib/constants'; 9 | import { sleep } from 'asyncbox'; 10 | 11 | process.env.NODE_ENV = 'test'; 12 | 13 | chai.use(chaiAsPromised); 14 | chai.should(); 15 | 16 | // these test require a device connected via usb 17 | describe('adb-e2e', () => { 18 | let device = null; 19 | let availableDevices = null; 20 | const packageName = "com.example.android.contactmanager"; 21 | const activityName = ".ContactManager"; 22 | before(async () => { 23 | availableDevices = await ADB.findAdbDevices(); 24 | // just select the first device 25 | device = new ADB(CONNECTION_TYPES.USB, availableDevices[0]); 26 | await device.connect(); 27 | }); 28 | after(async () => { 29 | await device.closeConnection(); 30 | }); 31 | 32 | describe('shell', async () => { 33 | it('should return a not found message for an unknown command', async () => { 34 | let commandString = "asdf"; 35 | let expectedReturnString = `/system/bin/sh: ${commandString}: not found`; 36 | let command = { // set print to false so we get the data back as a string 37 | type: "shell" 38 | , string: commandString 39 | , print: false 40 | }; 41 | let output = await device.runCommand(command); 42 | output.indexOf(expectedReturnString).should.not.equal(-1); 43 | }); 44 | it('should return an error message if we run a shell command incorrectly', async () => { 45 | let commandString = "touch"; 46 | let expectedReturnString = "touch: no file specified"; 47 | let command = { // set print to false so we get the data back as a string 48 | type: "shell" 49 | , string: commandString 50 | , print: false 51 | }; 52 | let output = await device.runCommand(command); 53 | output.indexOf(expectedReturnString).should.not.equal(-1); 54 | }); 55 | it('should return successful output if we run a shell command correctly', async () => { 56 | let commandString = "cd sdcard; pwd"; 57 | let expectedReturnString = "/sdcard"; 58 | let command = { // set print to false so we get the data back as a string 59 | type: "shell" 60 | , string: commandString 61 | , print: false 62 | }; 63 | let output = await device.runCommand(command); 64 | output.indexOf(expectedReturnString).should.not.equal(-1); 65 | }); 66 | }); 67 | describe('push', () => { 68 | const smallFile = path.resolve(__dirname 69 | , '..' 70 | , '..' 71 | , '..' 72 | , 'test' 73 | , 'fixtures' 74 | , 'smallFile'); 75 | const largeFile = path.resolve(__dirname 76 | , '..' 77 | , '..' 78 | , '..' 79 | , 'test' 80 | , 'fixtures' 81 | , 'largeFile'); 82 | const destination = "sdcard/"; 83 | 84 | it('should upload smallFile to device', async () => { 85 | const stats = await fs.stat(smallFile); 86 | const smallFileSize = stats.size.toString(); 87 | 88 | let command = { 89 | type: "push" 90 | , source: smallFile 91 | , destination: destination 92 | }; 93 | await device.runCommand(command); 94 | let lsCommand = { 95 | type: "shell" 96 | , string: "ls -al sdcard/ | grep smallFile" 97 | , print: false 98 | }; 99 | let output = await device.runCommand(lsCommand); 100 | output.indexOf(smallFileSize).should.not.equal(-1); 101 | }); 102 | it('should upload largeFile to device', async () => { 103 | const stats = await fs.stat(largeFile); 104 | const largeFileSize = stats.size.toString(); 105 | 106 | let command = { 107 | type: "push" 108 | , source: largeFile 109 | , destination: destination 110 | }; 111 | await device.runCommand(command); 112 | let lsCommand = { 113 | type: "shell" 114 | , string: "ls -al sdcard/ | grep largeFile" 115 | , print: false 116 | }; 117 | let output = await device.runCommand(lsCommand); 118 | output.indexOf(largeFileSize).should.not.equal(-1); 119 | }); 120 | it('should return -1 if the source file does not exist', async () => { 121 | let command = { 122 | type: "push" 123 | , source: path.resolve(__dirname, 'nonExistantFile') 124 | , destination: destination 125 | }; 126 | let retValue = await device.runCommand(command); 127 | retValue.should.equal(-1); 128 | }); 129 | }); 130 | describe('pull', () => { 131 | const smallFile = path.resolve(__dirname, '..', '..', '..', 'test', 'fixtures', 'smallFile'); 132 | const largeFile = path.resolve(__dirname, '..', '..', '..', 'test', 'fixtures', 'largeFile'); 133 | const tempTestPath = path.resolve(__dirname, '..', '..', '..', 'tempTest'); 134 | const push_destination = "sdcard/"; 135 | 136 | before(async () => { 137 | await fs.mkdir(tempTestPath); 138 | }); 139 | after(async () => { 140 | await fs.rimraf(tempTestPath); 141 | }); 142 | 143 | it('should pull down all of smallFile', async () => { 144 | // push smallfile before trying to pull it 145 | let push_command = { 146 | type: "push" 147 | , source: smallFile 148 | , destination: push_destination 149 | }; 150 | await device.runCommand(push_command); 151 | 152 | let destination = `${tempTestPath}/smallFile`; 153 | let command = { 154 | type: "pull" 155 | , source: "sdcard/smallFile" 156 | , destination: destination 157 | }; 158 | let fileSize = await device.runCommand(command); 159 | let stats = await fs.stat(destination); 160 | fileSize.should.equal(stats.size); 161 | }); 162 | it('should pull down all of largeFile', async () => { 163 | // push largefile before trying to pull it 164 | let push_command = { 165 | type: "push" 166 | , source: largeFile 167 | , destination: push_destination 168 | }; 169 | await device.runCommand(push_command); 170 | 171 | let destination = `${tempTestPath}/largeFile`; 172 | let command = { 173 | type: "pull" 174 | , source: "sdcard/largeFile" 175 | , destination: destination 176 | }; 177 | let fileSize = await device.runCommand(command); 178 | let stats = await fs.stat(destination); 179 | fileSize.should.equal(stats.size); 180 | }); 181 | it('should return a filesize of -1 if the file does not exist', async () => { 182 | // try and pull a file we just pushed to the device 183 | // except leave off the file extension 184 | let command = { 185 | type: "pull" 186 | , source: "sdcard/adbCapture" 187 | , destination: path.resolve(__dirname, '..', '..', '..') 188 | }; 189 | let output = await device.runCommand(command); 190 | output.should.equal(-1); 191 | }); 192 | }); 193 | describe('list', () => { 194 | it('should return a list of files in a folder', async () => { 195 | // Hard to test symlinks because we can't create them on an un-rooted phone 196 | let commandString = "cd sdcard; mkdir tmp; cd tmp; touch file1; touch file2; mkdir folder1"; 197 | let command = { // set print to false so we get the data back as a string 198 | type: "shell" 199 | , string: commandString 200 | , print: false 201 | }; 202 | await device.runCommand(command); 203 | command = { 204 | type: "list" 205 | , remotePath: "sdcard/tmp" 206 | }; 207 | let output = await device.runCommand(command); 208 | let filenames = output.map(file => file.filename); 209 | filenames.should.deep.equal(['file1', 'file2', 'folder1']); 210 | let filetypes = output.map(file => file.type); 211 | filetypes.should.deep.equal([ 212 | FILE_TYPES.FILE 213 | , FILE_TYPES.FILE 214 | , FILE_TYPES.DIRECTORY 215 | ]); 216 | }); 217 | it('should return an empty array for an empty folder', async () => { 218 | let command = { 219 | type: "list" 220 | , remotePath: "sdcard/tmp/folder1" 221 | }; 222 | let output = await device.runCommand(command); 223 | output.length.should.equal(0); 224 | }); 225 | it('should return an empty array when called on a file', async () => { 226 | let command = { 227 | type: "list" 228 | , remotePath: "sdcard/tmp/file1" 229 | }; 230 | let output = await device.runCommand(command); 231 | output.length.should.equal(0); 232 | }); 233 | it('should return an empty array when called on a non-existent remote path', async () => { 234 | let command = { 235 | type: "list" 236 | , remotePath: "sdcard/tmp/" + Date.now() 237 | }; 238 | let output = await device.runCommand(command); 239 | output.length.should.equal(0); 240 | }); 241 | }); 242 | describe('install', () => { 243 | it('should be able to install and run an app', async function () { 244 | this.timeout(8000); 245 | const source = path.resolve(__dirname, '..', '..', '..', 'test', 'fixtures', 'ContactManager.apk'); 246 | const runApp = `${packageName}/${activityName}`; 247 | await device.runCommand({ type: "install", source: source }); 248 | let output = await device.runCommand({ type: "shell" 249 | , string: runApp 250 | , print: false }); 251 | let errorMsg = `Error: Activity class {${packageName}/${packageName}.${activityName}} does not exist.`; 252 | output.indexOf(errorMsg).should.equal(-1); 253 | }); 254 | }); 255 | describe('uninstall', () => { 256 | before(async () => { 257 | const source = path.resolve(__dirname, '..', '..', '..', 'test', 'fixtures', 'ContactManager.apk'); 258 | const runApp = `${packageName}/${activityName}`; 259 | await device.runCommand({ type: "install", source: source }); 260 | await device.runCommand({ type: "shell" 261 | , string: runApp 262 | , print: false }); 263 | }); 264 | it('should uninstall the app we have installed', async () => { 265 | let output = await device.runCommand({ type: "uninstall", packageName: packageName }); 266 | output.indexOf(`Success`).should.not.equal(-1); 267 | }); 268 | }); 269 | describe('reboot', () => { 270 | // not using an arrow function so that the this context is correct for this.timeout 271 | it('should (the device) be available for commands after reboot', async function () { 272 | // override default timeout since we need to wait for the device to reboot 273 | this.timeout(30000); 274 | let command = { 275 | type: "reboot" 276 | }; 277 | await device.runCommand(command); 278 | // sleep then connect to the device again 279 | await sleep(20000); // time required before an S4 running Android 5 is available 280 | availableDevices = await ADB.findAdbDevices(); 281 | // just select the first device 282 | device = new ADB(CONNECTION_TYPES.USB, availableDevices[0]); 283 | await device.connect(); 284 | // run a very basic command to confirm device is okay 285 | let commandString = "cd sdcard/ ; pwd"; 286 | let expectedReturnString = "/sdcard"; 287 | let checkCommand = { // set print to false so we get the data back as a string 288 | type: "shell" 289 | , string: commandString 290 | , print: false 291 | }; 292 | let output = await device.runCommand(checkCommand); 293 | output.trim().should.equal(expectedReturnString); 294 | }); 295 | }); 296 | }); 297 | -------------------------------------------------------------------------------- /test/unit/adb-device-specs.js: -------------------------------------------------------------------------------- 1 | import chai from 'chai'; 2 | import { fs } from 'appium-support'; 3 | import chaiAsPromised from 'chai-as-promised'; 4 | import { withMocks, verify } from 'appium-test-support'; 5 | import USBDevice from '../../lib/usb-device'; 6 | import ADBDevice from '../../lib/adb-device'; 7 | import { CONNECT_VALUES 8 | , ADB_COMMANDS 9 | , CONNECTION_TYPES } from '../../lib/constants'; 10 | import { generateMessage, packetFromBuffer } from '../../lib/helpers'; 11 | 12 | process.env.NODE_ENV = 'test'; 13 | 14 | chai.should(); 15 | chai.use(chaiAsPromised); 16 | let expect = chai.expect; 17 | 18 | describe('adb-device', () => { 19 | let inputEndpoint = { transferAsync: () => { return "nothing"; } }; 20 | let outputEndpoint = { transferAsync: () => { return "nothing"; } }; 21 | let usbDevice = new USBDevice(); 22 | usbDevice.inputEndpoint = inputEndpoint; 23 | usbDevice.outputEndpoint = outputEndpoint; 24 | let adbDevice = new ADBDevice(CONNECTION_TYPES.USB, usbDevice); 25 | adbDevice.device = usbDevice; 26 | let localId, remoteId = 12345; 27 | 28 | describe('recvAndOkay', withMocks({ usbDevice }, (mocks) => { 29 | it('should call _sendMsg with command okay', async () => { 30 | mocks.usbDevice.expects('_recvMsg') 31 | .once() 32 | .withExactArgs(CONNECT_VALUES.CONNECT_MAXDATA); 33 | mocks.usbDevice.expects('_sendMsg') 34 | .once() 35 | .withExactArgs(ADB_COMMANDS.CMD_OKAY, localId, remoteId, ""); 36 | await adbDevice.recvAndOkay(localId, remoteId); 37 | mocks.usbDevice.verify(); 38 | }); 39 | })); 40 | describe('sendAndOkay', withMocks({ usbDevice }, (mocks) => { 41 | it('should throw an error containing the command type if the command was not OKAY', async () => { 42 | let fakePacket = packetFromBuffer(generateMessage(ADB_COMMANDS.CMD_CLSE, localId, remoteId, "")); 43 | mocks.usbDevice.expects('_sendMsg') 44 | .once() 45 | .withExactArgs(ADB_COMMANDS.CMD_WRTE, localId, remoteId, "test"); 46 | mocks.usbDevice.expects('_recvMsg') 47 | .once() 48 | .withExactArgs(CONNECT_VALUES.CONNECT_MAXDATA) 49 | .returns(fakePacket); 50 | await adbDevice.sendAndOkay(ADB_COMMANDS.CMD_WRTE, localId, remoteId, "test") 51 | .should.be.rejected; 52 | mocks.usbDevice.verify(); 53 | }); 54 | it('should return a packet with command type OKAY if command was OKAY', async () => { 55 | let fakePacket = packetFromBuffer(generateMessage(ADB_COMMANDS.CMD_OKAY, localId, remoteId, "")); 56 | mocks.usbDevice.expects('_sendMsg') 57 | .once() 58 | .withExactArgs(ADB_COMMANDS.CMD_WRTE, localId, remoteId, "test"); 59 | mocks.usbDevice.expects('_recvMsg') 60 | .once() 61 | .withExactArgs(CONNECT_VALUES.CONNECT_MAXDATA) 62 | .returns(fakePacket); 63 | await adbDevice.sendAndOkay(ADB_COMMANDS.CMD_WRTE, localId, remoteId, "test") 64 | .should.be.fulfilled; 65 | mocks.usbDevice.verify(); 66 | }); 67 | })); 68 | describe('shell', withMocks({ adbDevice }, (mocks) => { 69 | it('should be rejected if open response is not okay', async () => { 70 | let shellString = "shell:test."; 71 | mocks.adbDevice.expects('sendAndOkay') 72 | .once() 73 | .withExactArgs(ADB_COMMANDS.CMD_OPEN 74 | , 12345 75 | , 0 76 | , shellString) 77 | .returns({ command: "not okay" }); 78 | adbDevice.shell("test", false).should.be.rejected; 79 | verify(mocks); 80 | }); 81 | })); 82 | describe('open', withMocks({ adbDevice, fs }, (mocks) => { 83 | it('should call shell if command.type is shell', async () => { 84 | let command = { 85 | type: "shell" 86 | , string: "ls -al" 87 | , print: false 88 | }; 89 | mocks.adbDevice.expects('shell') 90 | .once() 91 | .withExactArgs(command.string, command.print); 92 | await adbDevice.open(command); 93 | verify(mocks); 94 | }); 95 | it('should not call push if fs.stat errors because the file does not exist', async () => { 96 | let command = { 97 | type: "push" 98 | , source: "nonExistantFile" 99 | , destination: "doesntMatter" 100 | }; 101 | mocks.fs.expects('stat') 102 | .once() 103 | .withExactArgs(command.source) 104 | .throws(); 105 | mocks.adbDevice.expects('push') 106 | .never(); 107 | await adbDevice.open(command); 108 | verify(mocks); 109 | }); 110 | it('should call push if fs.stat does not error', async () => { 111 | let command = { 112 | type: "push" 113 | , source: "existantFile" 114 | , destination: "doesntMatter" 115 | }; 116 | mocks.fs.expects('stat') 117 | .once() 118 | .withExactArgs(command.source) 119 | .returns("nothing"); 120 | mocks.adbDevice.expects('push') 121 | .once(); 122 | await adbDevice.open(command); 123 | verify(mocks); 124 | }); 125 | it('should call pull if command.type is pull', async () => { 126 | let command = { 127 | type: "pull" 128 | , source: "test" 129 | , destination: "testTwo" 130 | }; 131 | mocks.adbDevice.expects('pull') 132 | .once() 133 | .withExactArgs(command.source, command.destination); 134 | await adbDevice.open(command); 135 | verify(mocks); 136 | }); 137 | it('should call list if command.type is pull', async () => { 138 | let command = { 139 | type: "list" 140 | , remotePath: "test" 141 | }; 142 | mocks.adbDevice.expects('list') 143 | .once() 144 | .withExactArgs(command.remotePath); 145 | await adbDevice.open(command); 146 | verify(mocks); 147 | }); 148 | it('should call install if command.type is install', async () => { 149 | let command = { 150 | type: "install" 151 | , source: "test.apk" 152 | }; 153 | mocks.adbDevice.expects('install') 154 | .once() 155 | .withExactArgs(command.source); 156 | await adbDevice.open(command); 157 | verify(mocks); 158 | }); 159 | it('should call uninstall if command.type is uninstall', async () => { 160 | let command = { 161 | type: "uninstall" 162 | , packageName: "testPackage" 163 | }; 164 | mocks.adbDevice.expects('uninstall') 165 | .once() 166 | .withExactArgs(command.packageName); 167 | await adbDevice.open(command); 168 | verify(mocks); 169 | }); 170 | it('should call reboot if command.type is reboot', async () => { 171 | let command = { 172 | type: "reboot" 173 | }; 174 | mocks.adbDevice.expects('reboot') 175 | .once(); 176 | await adbDevice.open(command); 177 | verify(mocks); 178 | }); 179 | })); 180 | describe('sendPublicKey', withMocks({ usbDevice }, mocks => { 181 | it('should return true if response was CNXN', async () => { 182 | mocks.usbDevice.expects('_sendMsg') 183 | .once() 184 | .withArgs(ADB_COMMANDS.CMD_AUTH, 3, 0); 185 | mocks.usbDevice.expects('_recvMsg') 186 | .once() 187 | .withExactArgs(CONNECT_VALUES.CONNECT_MAXDATA) 188 | .returns({ command: ADB_COMMANDS.CMD_CNXN }); 189 | expect(await adbDevice.sendPublicKey()).to.be.true; 190 | verify(mocks); 191 | }); 192 | it('should return false if response was not CNXN', async () => { 193 | mocks.usbDevice.expects('_sendMsg') 194 | .once() 195 | .withArgs(ADB_COMMANDS.CMD_AUTH, 3, 0); 196 | mocks.usbDevice.expects('_recvMsg') 197 | .once() 198 | .withExactArgs(CONNECT_VALUES.CONNECT_MAXDATA) 199 | .returns({ command: "not cnxn" }); 200 | expect(await adbDevice.sendPublicKey()).to.be.false; 201 | verify(mocks); 202 | }); 203 | })); 204 | }); 205 | -------------------------------------------------------------------------------- /test/unit/adb-specs.js: -------------------------------------------------------------------------------- 1 | // transpile:mocha 2 | 3 | import chai from 'chai'; 4 | import chaiAsPromised from 'chai-as-promised'; 5 | import 'mochawait'; 6 | import proxyquire from 'proxyquire'; 7 | import { verify, withMocks } from 'appium-test-support'; 8 | import { ADB_VALUES 9 | , LIBUSB_VALUES 10 | , CONNECTION_TYPES } from '../../lib/constants'; 11 | import ADBDevice from '../../lib/adb-device'; 12 | import USBDevice from '../../lib/usb-device'; 13 | 14 | process.env.NODE_ENV = 'test'; 15 | 16 | // for proxyquire 17 | let usbStub = { '@noCallThru': true }; 18 | let signLibStub = { '@noCallThru': true }; 19 | let adbDeviceStub = proxyquire('../../lib/adb-device', { 'signLib': signLibStub }); 20 | let adb = proxyquire('../../adb', { 'usb': usbStub, 'adb-device': adbDeviceStub }); 21 | const LIBUSB_ENDPOINT_IN = LIBUSB_VALUES.LIBUSB_ENDPOINT_IN 22 | , LIBUSB_ENDPOINT_OUT = LIBUSB_VALUES.LIBUSB_ENDPOINT_OUT; 23 | 24 | chai.should(); 25 | let expect = chai.expect; 26 | chai.use(chaiAsPromised); 27 | 28 | describe('static functions', () => { 29 | // fake device setup 30 | let endpoints = [LIBUSB_ENDPOINT_IN, LIBUSB_ENDPOINT_OUT ]; 31 | let deviceDescriptor = { idVendor: null 32 | , iSerialNumber: "12345" }; 33 | let interfaceDescriptor = { bInterfaceClass: ADB_VALUES.ADB_CLASS 34 | , bInterfaceSubClass: ADB_VALUES.ADB_SUBCLASS 35 | , bInterfaceProtocol: ADB_VALUES.ADB_PROTOCOL }; 36 | let iface = { descriptor: interfaceDescriptor 37 | , endpoints: endpoints }; 38 | let device = { interfaces: [iface] 39 | , deviceDescriptor: deviceDescriptor 40 | , open: () => { return "nothing"; } }; 41 | describe('_getAdbInterface', () => { 42 | it('should return null if the descriptors are null', () => { 43 | device.deviceDescriptor = null; 44 | device.interfaces[0].descrptor = null; 45 | expect(adb._getAdbInterface(device)).to.be.a('null'); 46 | device.deviceDescriptor = deviceDescriptor; 47 | device.interfaces[0].descrptor = interfaceDescriptor; 48 | }); 49 | it('should return null if the device descriptor is null', () => { 50 | device.deviceDescriptor = null; 51 | expect(adb._getAdbInterface(device)).to.be.a('null'); 52 | device.interfaces[0].descrptor = interfaceDescriptor; 53 | }); 54 | it('should return null if the interface descriptor is null', () => { 55 | device.interfaces[0].descrptor = null; 56 | expect(adb._getAdbInterface(device)).to.be.a('null'); 57 | device.deviceDescriptor = deviceDescriptor; 58 | }); 59 | it('should return an interface if there is one for ADB comms', () => { 60 | deviceDescriptor.idVendor = 0x04e8; // samsung 61 | adb._getAdbInterface(device).should.not.be.null; 62 | }); 63 | it('should return null if there are interfaces but no ADB interface', () => { 64 | iface.descriptor.bInterfaceClass = 100; 65 | expect(adb._getAdbInterface(device)).to.be.a('null'); 66 | }); 67 | it('should return null if there are no interfaces at all', () => { 68 | device.interfaces = null; 69 | expect(adb._getAdbInterface(device)).to.be.a('null'); 70 | }); 71 | }); 72 | describe('findAdbDevices', withMocks({ usbStub, adb }, (mocks) => { 73 | usbStub.getDeviceList = () => { return "nothing"; }; 74 | it('should throw an error if there are no usb devices', () => { 75 | async () => { 76 | mocks.usbStub.expects('getDeviceList') 77 | .once() 78 | .returns([]); 79 | await adb.findAdbDevices().should.be.rejected(); 80 | verify(mocks); 81 | } 82 | }); 83 | it('should throw an error if none of the usb devices have ADB interfaces', () => { 84 | async () => { 85 | mocks.usbStub.expects('getDeviceList') 86 | .once() 87 | .returns([device]); 88 | await adb.findAdbDevices().should.be.rejected(); 89 | verify(mocks); 90 | } 91 | }); 92 | it('should return an object if there was a device with an adb interface', async () => { 93 | device.interfaces = [iface]; 94 | iface.descriptor.bInterfaceClass = 255; 95 | mocks.usbStub.expects('getDeviceList') 96 | .once() 97 | .returns([device]); 98 | mocks.adb.expects('_getSerialNo') 99 | .once() 100 | .returns("12345"); 101 | let availableDevices = await adb.findAdbDevices(); 102 | expect(availableDevices).to.not.be.empty; 103 | verify(mocks); 104 | }); 105 | })); 106 | }); 107 | 108 | describe('adb', () => { 109 | let usbDevice = new USBDevice(); 110 | let adbObj = new adb(CONNECTION_TYPES.USB, usbDevice); // state: NOT_CONNECTED 111 | let adbDevice = new ADBDevice(CONNECTION_TYPES.USB, usbDevice); 112 | adbObj.device = adbDevice; 113 | const NOT_CONNECTED = 0; 114 | const CONNECTED = 4; 115 | 116 | describe('runCommand', withMocks({ adbDevice }, (mocks) => { 117 | it('should reject with an error if state is not connected', async () => { 118 | let command = "test"; 119 | mocks.adbDevice.expects('open') 120 | .never(); 121 | await adbObj.runCommand(command).should.be.rejected; 122 | verify(mocks); 123 | }); 124 | it('should resolve if state is connected', async () => { 125 | let command = "test"; 126 | adbObj.state = CONNECTED; 127 | mocks.adbDevice.expects('open') 128 | .once() 129 | .withExactArgs(command); 130 | await adbObj.runCommand(command).should.be.resolved; 131 | verify(mocks); 132 | }); 133 | it('should return some output if device.open returned some output', async () => { 134 | const CONNECTED = 4; 135 | let command = "test"; 136 | adbObj.state = CONNECTED; 137 | mocks.adbDevice.expects('open') 138 | .once() 139 | .withExactArgs(command) 140 | .returns(command); 141 | let output = await adbObj.runCommand(command); 142 | output.should.equal(command); 143 | verify(mocks); 144 | }); 145 | it('should return undefined if device.open returned undefined', async () => { 146 | const CONNECTED = 4; 147 | let command = "test"; 148 | adbObj.state = CONNECTED; 149 | mocks.adbDevice.expects('open') 150 | .once() 151 | .withExactArgs(command) 152 | .returns(undefined); 153 | let output = await adbObj.runCommand(command); 154 | expect(output).to.be.an('undefined'); 155 | verify(mocks); 156 | }); 157 | })); 158 | describe('closeConnection', withMocks({ adbDevice }, (mocks) => { 159 | it('should call device.closeConnection if state is CONNECTED', async () => { 160 | adbObj.state = CONNECTED; 161 | mocks.adbDevice.expects('closeConnection') 162 | .once(); 163 | await adbObj.closeConnection(); 164 | adbObj.state.should.equal(NOT_CONNECTED); 165 | verify(mocks); 166 | }); 167 | it('should not call device.closeConnection if state is NOT_CONNECTED', async () => { 168 | adbObj.state = NOT_CONNECTED; 169 | mocks.adbDevice.expects('closeConnection') 170 | .never(); 171 | await adbObj.closeConnection(); 172 | adbObj.state.should.equal(NOT_CONNECTED); 173 | verify(mocks); 174 | }); 175 | })); 176 | describe('connect', withMocks({ adbDevice }, (mocks) => { 177 | it('should call device.initConnection twice if first waitForAuth returns false', async () => { 178 | adbObj.state = NOT_CONNECTED; 179 | mocks.adbDevice.expects('initConnection') 180 | .twice(); 181 | mocks.adbDevice.expects('waitForAuth') 182 | .twice() 183 | .onFirstCall() 184 | .returns(false) 185 | .onSecondCall() 186 | .returns(true); 187 | mocks.adbDevice.expects('sendSignedToken') 188 | .once() 189 | .returns(true); 190 | await adbObj.connect(); 191 | adbObj.state.should.equal(CONNECTED); 192 | verify(mocks); 193 | }); 194 | it('should call device.sendPublicKey if device.sendSignedToken returns false', async () => { 195 | adbObj.state = NOT_CONNECTED; 196 | mocks.adbDevice.expects('initConnection') 197 | .once(); 198 | mocks.adbDevice.expects('waitForAuth') 199 | .once() 200 | .returns(true); 201 | mocks.adbDevice.expects('sendSignedToken') 202 | .once() 203 | .returns(false); 204 | mocks.adbDevice.expects('sendPublicKey') 205 | .once() 206 | .returns(true); 207 | await adbObj.connect(); 208 | adbObj.state.should.equal(CONNECTED); 209 | verify(mocks); 210 | }); 211 | it('should call device.sendPublicKey twice if device.sendSignedToken returns false', async () => { 212 | adbObj.state = NOT_CONNECTED; 213 | mocks.adbDevice.expects('initConnection') 214 | .twice(); 215 | mocks.adbDevice.expects('waitForAuth') 216 | .twice() 217 | .returns(true); 218 | mocks.adbDevice.expects('sendSignedToken') 219 | .twice() 220 | .returns(false); 221 | mocks.adbDevice.expects('sendPublicKey') 222 | .twice() 223 | .onFirstCall() 224 | .returns(false) 225 | .onSecondCall() 226 | .returns(true); 227 | await adbObj.connect(); 228 | adbObj.state.should.equal(CONNECTED); 229 | verify(mocks); 230 | }); 231 | it('should restart the entire loop if waitForAuth times out', async () => { 232 | adbObj.state = NOT_CONNECTED; 233 | mocks.adbDevice.expects('initConnection') 234 | .twice(); 235 | mocks.adbDevice.expects('waitForAuth') 236 | .twice() 237 | .onFirstCall() 238 | .throws({errno: 2}) 239 | .onSecondCall() 240 | .returns(true); 241 | mocks.adbDevice.expects('sendSignedToken') 242 | .once() 243 | .returns(true); 244 | await adbObj.connect(); 245 | adbObj.state.should.equal(CONNECTED); 246 | verify(mocks); 247 | }); 248 | it('should restart the entire loop if sendSignedToken times out', async () => { 249 | adbObj.state = NOT_CONNECTED; 250 | mocks.adbDevice.expects('initConnection') 251 | .twice(); 252 | mocks.adbDevice.expects('waitForAuth') 253 | .twice() 254 | .returns(true); 255 | mocks.adbDevice.expects('sendSignedToken') 256 | .twice() 257 | .onFirstCall() 258 | .throws({errno: 2}) 259 | .onSecondCall() 260 | .returns(true); 261 | await adbObj.connect(); 262 | adbObj.state.should.equal(CONNECTED); 263 | verify(mocks); 264 | }); 265 | it('should restart the entire loop if sendPublicKey times out', async () => { 266 | adbObj.state = NOT_CONNECTED; 267 | mocks.adbDevice.expects('initConnection') 268 | .twice(); 269 | mocks.adbDevice.expects('waitForAuth') 270 | .twice() 271 | .returns(true); 272 | mocks.adbDevice.expects('sendSignedToken') 273 | .twice() 274 | .returns(false); 275 | mocks.adbDevice.expects('sendPublicKey') 276 | .twice() 277 | .onFirstCall() 278 | .throws({errno: 2}) 279 | .onSecondCall() 280 | .returns(true); 281 | await adbObj.connect(); 282 | adbObj.state.should.equal(CONNECTED); 283 | verify(mocks); 284 | }); 285 | })); 286 | }); 287 | 288 | 289 | -------------------------------------------------------------------------------- /test/unit/helpers-specs.js: -------------------------------------------------------------------------------- 1 | // transpile:mocha 2 | 3 | import chai from 'chai'; 4 | import chaiAsPromised from 'chai-as-promised'; 5 | import 'mochawait'; 6 | import { generateMessage 7 | , packetFromBuffer 8 | , getFileName 9 | , parseFileData 10 | , selectBySerialNumber } from '../../lib/helpers'; 11 | import { ADB_COMMANDS, CONNECTION_TYPES } from '../../lib/constants'; 12 | 13 | process.env.NODE_ENV = 'test'; 14 | 15 | chai.should(); 16 | chai.use(chaiAsPromised); 17 | 18 | describe('helpers', () => { 19 | describe('selectBySerialNumber', () => { 20 | it('should return a device if one can be found for a given serial number', () => { 21 | let serial = 12345; 22 | let devices = [{ device: "test", serialNumber: 54321 } 23 | , { device: "test", serialNumber: serial}]; 24 | let returnedDevice = selectBySerialNumber(devices, serial); 25 | returnedDevice.should.equal(devices[1]); 26 | }); 27 | it('should throw if no device can be found for a given serial number', () => { 28 | let serial = 54321; 29 | let devices = [{ device: "test", serialNumber: 12345}]; 30 | () => { 31 | selectBySerialNumber(devices, serial); 32 | }.should.throw("No device available with the serial number: ", serial); 33 | 34 | }); 35 | }); 36 | describe('generateMessage', () => { 37 | let cnxn = ADB_COMMANDS.CMD_CNXN; 38 | it('should throw error when invalid command is passed', () => { 39 | () => { 40 | generateMessage(1, 0, 0, "payload", CONNECTION_TYPES.USB); 41 | }.should.throw("generateMessage: invalid command type"); 42 | }); 43 | it('should throw error when invalid connection type is passed', () => { 44 | () => { 45 | generateMessage(ADB_COMMANDS.CMD_CNXN, 0, 0, "payload", 3); 46 | }.should.throw("generateMessage: invalid connection type"); 47 | }); 48 | it('should append data payload if connection type is tcp', () => { 49 | let tcpMsg = generateMessage(cnxn, 0, 0, "payload", CONNECTION_TYPES.TCP); 50 | tcpMsg.length.should.not.equal(24); 51 | }); 52 | it('should not append data payload if connection type is usb', () => { 53 | let usbMsg = generateMessage(cnxn, 0, 0, "payload", CONNECTION_TYPES.USB); 54 | usbMsg.length.should.equal(24); 55 | }); 56 | it('should set dataLen and crc to 0 if no payload', () => { 57 | let tcpMsg = generateMessage(cnxn, 0, 0, "", CONNECTION_TYPES.TCP); 58 | let dataLen = tcpMsg.readUInt32LE(12); 59 | let dataCrc = tcpMsg.readUInt32LE(16); 60 | dataLen.should.equal(0); 61 | dataCrc.should.equal(0); 62 | }); 63 | }); 64 | describe('packtFromBuffer', () => { 65 | // fake packet buffer 66 | let payloadBuffer = new Buffer("payload"); 67 | let packetBuffer = new Buffer(30); 68 | packetBuffer.writeUInt32LE(ADB_COMMANDS.CMD_CNXN, 0); 69 | packetBuffer.writeUInt32LE(0, 4); 70 | packetBuffer.writeUInt32LE(0, 8); 71 | packetBuffer.writeUInt32LE(payloadBuffer.length, 12); 72 | packetBuffer.writeUInt32LE(0, 16); 73 | packetBuffer.writeUInt32LE(0, 20); 74 | packetBuffer.write("payload", 24, 7); 75 | it('should throw an error if we pass less than 24 bytes of data', () => { 76 | () => { 77 | let buf = new Buffer(23); 78 | packetFromBuffer(buf); 79 | }.should.throw(Error); 80 | }); 81 | it('should fill data field if data length was > 0', () => { 82 | let packet = packetFromBuffer(packetBuffer); 83 | (typeof packet.data).should.not.equal('undefined'); 84 | }); 85 | it('should not fill the data field if data length was 0', () => { 86 | // overwrite the dataLen field 87 | packetBuffer.writeUInt32LE(0, 12); 88 | let packet = packetFromBuffer(packetBuffer); 89 | (typeof packet.data).should.equal('undefined'); 90 | }); 91 | }); 92 | describe('getFileName', () => { 93 | it('should return a string with no /\'s', () => { 94 | let filePath = "a/test/path"; 95 | let fileName = getFileName(filePath); 96 | fileName.should.equal('path'); 97 | }); 98 | }); 99 | describe('parseFileData', () => { 100 | it('should return a buffer with none of the ADB protocol info', () => { 101 | // this test is not great, but better than nothing 102 | // lazy buffer creation 103 | let oneSize = 512, twoSize = 496; 104 | let dataIndicator = new Buffer("DATA"), doneIndicator = new Buffer("DONE"); 105 | let dataOne = new Buffer(oneSize).fill('a'), dataTwo = new Buffer(twoSize).fill('b'); 106 | let sizeOne = new Buffer(4), sizeTwo = new Buffer(4); 107 | sizeOne.writeUInt32LE(oneSize); 108 | sizeTwo.writeUInt32LE(twoSize); 109 | let fakeBuffer = new Buffer(""); 110 | // concat them all 111 | fakeBuffer = Buffer.concat([dataIndicator 112 | , sizeOne 113 | , dataOne 114 | , dataIndicator 115 | , sizeTwo 116 | , dataTwo 117 | , doneIndicator]); 118 | let parsedData = parseFileData(fakeBuffer); 119 | fakeBuffer.length.should.be.above(parsedData.length); 120 | parsedData.toString().indexOf('DATA').should.equal(-1); 121 | parsedData.toString().indexOf('DONE').should.equal(-1); 122 | }); 123 | }); 124 | }); 125 | -------------------------------------------------------------------------------- /test/unit/usb-specs.js: -------------------------------------------------------------------------------- 1 | import chai from 'chai'; 2 | import chaiAsPromised from 'chai-as-promised'; 3 | import { verify, withMocks } from 'appium-test-support'; 4 | import USBDevice from '../../lib/usb-device'; 5 | import { CONNECT_VALUES 6 | , ADB_COMMANDS 7 | , LIBUSB_VALUES } from '../../lib/constants'; 8 | import { generateMessage } from '../../lib/helpers'; 9 | 10 | const LIBUSB_TRANSFER_TYPE_BULK = LIBUSB_VALUES.LIBUSB_TRANSFER_TYPE_BULK; 11 | 12 | chai.should(); 13 | chai.use(chaiAsPromised); 14 | 15 | describe('usb-device unit tests', () => { 16 | let inputEndpoint = { transferAsync: () => { return "nothing"; } }; 17 | let outputEndpoint = { transferAsync: () => { return "nothing"; } }; 18 | let usbDevice = new USBDevice(); 19 | beforeEach(() => { 20 | usbDevice.inputEndpoint = inputEndpoint; 21 | usbDevice.outputEndpoint = outputEndpoint; 22 | }); 23 | describe('setEndpoints', () => { 24 | it('should set inputEndpoint to endpoints[0] if endpoints[0].direction is in', () => { 25 | let endpoints = [ { direction: 'in', transferType: null } 26 | , { direction: 'out', transferType: null }]; 27 | usbDevice.setEndpoints(endpoints); 28 | usbDevice.inputEndpoint.direction.should.equal(endpoints[0].direction); 29 | usbDevice.inputEndpoint.transferType.should.equal(LIBUSB_TRANSFER_TYPE_BULK); 30 | }); 31 | it('should set inputEndpoint to endpoints[1] if endpoints[1].direction is in', () => { 32 | let endpoints = [ { direction: 'out', transferType: null } 33 | , { direction: 'in', transferType: null }]; 34 | usbDevice.setEndpoints(endpoints); 35 | usbDevice.inputEndpoint.direction.should.equal(endpoints[1].direction); 36 | usbDevice.inputEndpoint.transferType.should.equal(LIBUSB_TRANSFER_TYPE_BULK); 37 | }); 38 | }); 39 | describe('_sendMsg', withMocks({ usbDevice, outputEndpoint}, (mocks) => { 40 | it('should call outputEndpoint.transferAsync once if no payload', async () => { 41 | mocks.outputEndpoint.expects('transferAsync') 42 | .once() 43 | .returns(); 44 | await usbDevice._sendMsg(ADB_COMMANDS.CMD_OKAY, 12345, 12345, ""); 45 | verify(mocks); 46 | }); 47 | it('should call outputEndpoint.transferAsync twice if there is a data payload', async () => { 48 | mocks.outputEndpoint.expects('transferAsync') 49 | .twice() 50 | .returns(); 51 | await usbDevice._sendMsg(ADB_COMMANDS.CMD_OKAY, 12345, 12345, "test"); 52 | verify(mocks); 53 | }); 54 | })); 55 | describe('_recvMsg', withMocks({ usbDevice, inputEndpoint }, (mocks) => { 56 | it('should return a packet with the correct command that came in on the wire', async () => { 57 | let fakePacket = generateMessage(ADB_COMMANDS.CMD_OKAY, 12345, 12345, ""); 58 | mocks.inputEndpoint.expects('transferAsync') 59 | .withExactArgs(CONNECT_VALUES.CONNECT_MAXDATA) 60 | .returns(fakePacket); 61 | let packet = await usbDevice._recvMsg(CONNECT_VALUES.CONNECT_MAXDATA); 62 | packet.command.should.equal(ADB_COMMANDS.CMD_OKAY); 63 | }); 64 | it('should return a packet with the dataLen 0 when there was no data payload', async () => { 65 | // set up the buffer, we don't really care about the crc at byte 16-19 66 | let initialBuffer = new Buffer(24); 67 | initialBuffer.writeUInt32LE(ADB_COMMANDS.CMD_OKAY, 0); 68 | initialBuffer.writeUInt32LE(12345, 4); 69 | initialBuffer.writeUInt32LE(12345, 8); 70 | initialBuffer.writeUInt32LE(0, 12); 71 | 72 | mocks.inputEndpoint.expects('transferAsync') 73 | .withExactArgs(CONNECT_VALUES.CONNECT_MAXDATA) 74 | .returns(initialBuffer); 75 | mocks.usbDevice.expects('getPacketData') 76 | .never(); 77 | let packet = await usbDevice._recvMsg(CONNECT_VALUES.CONNECT_MAXDATA); 78 | packet.dataLen.should.equal(0); 79 | verify(mocks); 80 | }); 81 | it('should return a packet with the correct dataLen when there was a data payload', async () => { 82 | // set up the buffer, we don't really care about the crc at byte 16-19 83 | let payloadSize = 4; 84 | let payloadBuffer = new Buffer("test"); 85 | let initialBuffer = new Buffer(24); 86 | initialBuffer.writeUInt32LE(ADB_COMMANDS.CMD_OKAY, 0); 87 | initialBuffer.writeUInt32LE(12345, 4); 88 | initialBuffer.writeUInt32LE(12345, 8); 89 | initialBuffer.writeUInt32LE(payloadSize, 12); 90 | 91 | mocks.inputEndpoint.expects('transferAsync') 92 | .withExactArgs(CONNECT_VALUES.CONNECT_MAXDATA) 93 | .returns(initialBuffer); 94 | mocks.usbDevice.expects('getPacketData') 95 | .withExactArgs(CONNECT_VALUES.CONNECT_MAXDATA, payloadSize) 96 | .returns(payloadBuffer); 97 | let packet = await usbDevice._recvMsg(CONNECT_VALUES.CONNECT_MAXDATA); 98 | packet.data.length.should.equal(packet.dataLen); 99 | verify(mocks); 100 | }); 101 | })); 102 | describe('getPacketData', withMocks({ usbDevice, inputEndpoint }, (mocks) => { 103 | it('should only call transferAsync once if dataLen < maxdata (4096)', async () => { 104 | let dataLen = 4000; 105 | let testBuffer = new Buffer(dataLen); 106 | mocks.inputEndpoint.expects('transferAsync') 107 | .once() 108 | .withExactArgs(CONNECT_VALUES.CONNECT_MAXDATA) 109 | .returns(testBuffer); 110 | let packetData = await usbDevice.getPacketData(CONNECT_VALUES.CONNECT_MAXDATA, dataLen); 111 | packetData.length.should.equal(dataLen); 112 | verify(mocks); 113 | }); 114 | it('should call transferAsync at least twice if dataLen > maxdata (4096)', async () => { 115 | let dataLen = 8000; 116 | // let testBuffer = new Buffer(dataLen); 117 | mocks.inputEndpoint.expects('transferAsync') 118 | .twice() 119 | .withExactArgs(CONNECT_VALUES.CONNECT_MAXDATA) 120 | .onFirstCall() 121 | .returns(new Buffer(CONNECT_VALUES.CONNECT_MAXDATA)) 122 | .onSecondCall() 123 | .returns(new Buffer(dataLen - CONNECT_VALUES.CONNECT_MAXDATA)); 124 | let packetData = await usbDevice.getPacketData(CONNECT_VALUES.CONNECT_MAXDATA, dataLen); 125 | packetData.length.should.equal(dataLen); 126 | verify(mocks); 127 | }); 128 | })); 129 | }); 130 | --------------------------------------------------------------------------------