├── .DS_Store ├── .gitignore ├── .npmignore ├── LICENSE ├── README.md ├── android ├── build.gradle ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── src │ └── main │ ├── AndroidManifest.xml │ └── java │ └── com │ └── pedrouid │ └── crypto │ ├── RNSCAes.java │ ├── RNSCCryptoPackage.java │ ├── RNSCHmac.java │ ├── RNSCPbkdf2.java │ ├── RNSCRandomBytes.java │ ├── RNSCRsa.java │ ├── RNSCSha.java │ ├── RSA.java │ └── Util.java ├── index.d.ts ├── index.js ├── ios ├── RNSCCrypto.xcodeproj │ ├── project.pbxproj │ └── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist └── RNSCCrypto │ ├── RNSCAes.h │ ├── RNSCAes.m │ ├── RNSCHmac.h │ ├── RNSCHmac.m │ ├── RNSCPbkdf2.h │ ├── RNSCPbkdf2.m │ ├── RNSCRandomBytes.h │ ├── RNSCRandomBytes.m │ ├── RNSCRsa.h │ ├── RNSCRsa.m │ ├── RNSCSha.h │ ├── RNSCSha.m │ └── lib │ ├── Aes.h │ ├── Aes.m │ ├── Hmac.h │ ├── Hmac.m │ ├── Pbkdf2.h │ ├── Pbkdf2.m │ ├── Rsa.h │ ├── Rsa.m │ ├── RsaFormatter.h │ ├── RsaFormatter.m │ ├── Sha.h │ ├── Sha.m │ ├── Shared.h │ └── Shared.m ├── package.json ├── react-native-simple-crypto.podspec └── yarn.lock /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ghbutton/react-native-simple-crypto/fe14572cba418c9fa2be03929a9a1075ffce8318/.DS_Store -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # OSX 2 | # 3 | .DS_Store 4 | 5 | # npm / yarn 6 | node_modules/ 7 | npm-debug.log 8 | yarn-error.log 9 | 10 | # Xcode 11 | # 12 | build/ 13 | *.pbxuser 14 | !default.pbxuser 15 | *.mode1v3 16 | !default.mode1v3 17 | *.mode2v3 18 | !default.mode2v3 19 | *.perspectivev3 20 | !default.perspectivev3 21 | xcuserdata 22 | *.xccheckout 23 | *.moved-aside 24 | DerivedData 25 | *.hmap 26 | *.ipa 27 | *.xcuserstate 28 | 29 | # Android/IntelliJ 30 | # 31 | android/build 32 | .idea 33 | .gradle 34 | local.properties 35 | *.iml -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | ### gitignore ### 2 | 3 | # OSX 4 | # 5 | .DS_Store 6 | 7 | 8 | # node.js 9 | # 10 | node_modules/ 11 | npm-debug.log 12 | yarn-error.log 13 | 14 | # Xcode 15 | # 16 | ios/build 17 | *.pbxuser 18 | !default.pbxuser 19 | *.mode1v3 20 | !default.mode1v3 21 | *.mode2v3 22 | !default.mode2v3 23 | *.perspectivev3 24 | !default.perspectivev3 25 | xcuserdata 26 | *.xccheckout 27 | *.moved-aside 28 | DerivedData 29 | *.hmap 30 | *.ipa 31 | *.xcuserstate 32 | project.xcworkspace 33 | 34 | 35 | # Android/IntelliJ 36 | # 37 | android/build 38 | .idea 39 | .gradle 40 | local.properties 41 | *.iml 42 | 43 | 44 | ### npmignore ### 45 | example -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Pedro Gomes 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Not maintained, looking for maintainer. Contact @ghbutton if you want take charge. 2 | 3 | # React Native Simple Crypto [![npm version](https://badge.fury.io/js/react-native-simple-crypto.svg)](https://badge.fury.io/js/react-native-simple-crypto) 4 | 5 | A simpler React-Native crypto library 6 | 7 | ## Features 8 | 9 | - AES-128-CBC 10 | - HMAC-SHA256 11 | - SHA1 12 | - SHA256 13 | - SHA512 14 | - PBKDF2 15 | - RSA 16 | 17 | ## Installation 18 | 19 | ```bash 20 | npm install react-native-simple-crypto 21 | 22 | # OR 23 | 24 | yarn add react-native-simple-crypto 25 | ``` 26 | 27 | ### Linking Automatically 28 | 29 | ```bash 30 | react-native link react-native-simple-crypto 31 | ``` 32 | 33 | ### Linking Manually 34 | 35 | #### iOS 36 | 37 | - See [Linking Libraries](http://facebook.github.io/react-native/docs/linking-libraries-ios.html) 38 | OR 39 | - Drag RCTCrypto.xcodeproj to your project on Xcode. 40 | - Click on your main project file (the one that represents the .xcodeproj) select Build Phases and drag libRCTCrypto.a from the Products folder inside the RCTCrypto.xcodeproj. 41 | 42 | #### (Android) 43 | 44 | - In `android/settings.gradle` 45 | 46 | ```gradle 47 | ... 48 | include ':react-native-simple-crypto' 49 | project(':react-native-simple-crypto').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-simple-crypto/android') 50 | ``` 51 | 52 | - In `android/app/build.gradle` 53 | 54 | ```gradle 55 | ... 56 | dependencies { 57 | ... 58 | compile project(':react-native-simple-crypto') 59 | } 60 | ``` 61 | 62 | - register module (in MainApplication.java) 63 | 64 | ```java 65 | ...... 66 | import com.pedrouid.crypto.RNSCCryptoPackage; 67 | 68 | ...... 69 | 70 | @Override 71 | protected List getPackages() { 72 | ...... 73 | new RNSCCryptoPackage(), 74 | ...... 75 | } 76 | ``` 77 | 78 | ## API 79 | 80 | All methods are asynchronous and return promises (except for convert utils) 81 | 82 | ```typescript 83 | - AES 84 | - encrypt(text: ArrayBuffer, key: ArrayBuffer, iv: ArrayBuffer) 85 | - decrypt(cipherText: ArrayBuffer, key: ArrayBuffer, iv: ArrayBuffer) 86 | - SHA 87 | - sha1(text: string) 88 | - sha1(text: ArrayBuffer) 89 | - sha256(text: string) 90 | - sha256(text: ArrayBuffer) 91 | - sha512(text: string) 92 | - sha512(text: ArrayBuffer) 93 | - HMAC 94 | - hmac256(text: ArrayBuffer, key: ArrayBuffer) 95 | - PBKDF2 96 | - hash(password: string, salt: ArrayBuffer, iterations: number, keyLength: number, hash: string) 97 | - RSA 98 | - generateKeys(keySize: number) 99 | - sign(data: string, key: string, hash: string) 100 | - verify(data: string, secretToVerify: string, hash: string) 101 | - encrypt(data: string, key: string) (Expects UTF8 string data inputs) 102 | - decrypt(data: string, key: string) (Returns UTF8 string) 103 | - encrypt64(data: string, key: string) (Expects Base64 string data inputs) 104 | - decrypt64(data: string, key: string) (Returns Base64 string) 105 | - utils 106 | - randomBytes(bytes: number) 107 | - convertArrayBufferToUtf8(input: ArrayBuffer) 108 | - convertUtf8ToArrayBuffer(input: string) 109 | - convertArrayBufferToBase64(input: ArrayBuffer) 110 | - convertBase64ToArrayBuffer(input: string) 111 | - convertArrayBufferToHex(input: ArrayBuffer) 112 | - convertHexToArrayBuffer(input: string) 113 | ``` 114 | 115 | > _NOTE:_ Supported hashing algorithms for RSA and PBKDF2 are: 116 | > 117 | > `"Raw" (RSA-only) | "SHA1" | "SHA224" | "SHA256" | "SHA384" | "SHA512"` 118 | 119 | ## Example 120 | 121 | Testing [repository](https://github.com/ghbutton/react-native-simple-crypto-test). 122 | 123 | ```javascript 124 | import RNSimpleCrypto from "react-native-simple-crypto"; 125 | 126 | const toHex = RNSimpleCrypto.utils.convertArrayBufferToHex 127 | const toUtf8 = RNSimpleCrypto.utils.convertArrayBufferToUtf8 128 | 129 | // -- AES ------------------------------------------------------------- // 130 | const message = "data to encrypt"; 131 | const messageArrayBuffer = RNSimpleCrypto.utils.convertUtf8ToArrayBuffer( 132 | message 133 | ); 134 | 135 | const keyArrayBuffer = await RNSimpleCrypto.utils.randomBytes(32); 136 | console.log("randomBytes key", toHex(keyArrayBuffer)); 137 | 138 | const ivArrayBuffer = await RNSimpleCrypto.utils.randomBytes(16); 139 | console.log("randomBytes iv", toHex(ivArrayBuffer)); 140 | 141 | const cipherTextArrayBuffer = await RNSimpleCrypto.AES.encrypt( 142 | messageArrayBuffer, 143 | keyArrayBuffer, 144 | ivArrayBuffer 145 | ); 146 | console.log("AES encrypt", toHex(cipherTextArrayBuffer)) 147 | 148 | const decryptedArrayBuffer = await RNSimpleCrypto.AES.decrypt( 149 | cipherTextArrayBuffer, 150 | keyArrayBuffer, 151 | ivArrayBuffer 152 | ); 153 | console.log("AES decrypt", toUtf8(decryptedArrayBuffer)); 154 | if (toUtf8(decryptedArrayBuffer) !== message) { 155 | console.error('AES decrypt returned unexpected results') 156 | } 157 | 158 | // -- HMAC ------------------------------------------------------------ // 159 | 160 | const keyHmac = await RNSimpleCrypto.utils.randomBytes(32); 161 | const signatureArrayBuffer = await RNSimpleCrypto.HMAC.hmac256(messageArrayBuffer, keyHmac); 162 | console.log("HMAC signature", toHex(signatureArrayBuffer)); 163 | 164 | // -- SHA ------------------------------------------------------------- // 165 | 166 | const sha1Hash = await RNSimpleCrypto.SHA.sha1("test"); 167 | console.log("SHA1 hash", sha1Hash); 168 | 169 | const sha256Hash = await RNSimpleCrypto.SHA.sha256("test"); 170 | console.log("SHA256 hash", sha256Hash); 171 | 172 | const sha512Hash = await RNSimpleCrypto.SHA.sha512("test"); 173 | console.log("SHA512 hash", sha512Hash); 174 | 175 | const arrayBufferToHash = RNSimpleCrypto.utils.convertUtf8ToArrayBuffer("test"); 176 | const sha1ArrayBuffer = await RNSimpleCrypto.SHA.sha1(arrayBufferToHash); 177 | console.log('SHA1 hash bytes', toHex(sha1ArrayBuffer)); 178 | if (toHex(sha1ArrayBuffer) !== sha1Hash) { 179 | console.error('SHA1 result mismatch!') 180 | } 181 | 182 | const sha256ArrayBuffer = await RNSimpleCrypto.SHA.sha256(arrayBufferToHash); 183 | console.log('SHA256 hash bytes', toHex(sha256ArrayBuffer)); 184 | if (toHex(sha256ArrayBuffer) !== sha256Hash) { 185 | console.error('SHA256 result mismatch!') 186 | } 187 | 188 | const sha512ArrayBuffer = await RNSimpleCrypto.SHA.sha512(arrayBufferToHash); 189 | console.log('SHA512 hash bytes', toHex(sha512ArrayBuffer)); 190 | if (toHex(sha512ArrayBuffer) !== sha512Hash) { 191 | console.error('SHA512 result mismatch!') 192 | } 193 | 194 | // -- PBKDF2 ---------------------------------------------------------- // 195 | 196 | const password = "secret password"; 197 | const salt = "my-salt" 198 | const iterations = 4096; 199 | const keyInBytes = 32; 200 | const hash = "SHA1"; 201 | const passwordKey = await RNSimpleCrypto.PBKDF2.hash( 202 | password, 203 | salt, 204 | iterations, 205 | keyInBytes, 206 | hash 207 | ); 208 | console.log("PBKDF2 passwordKey", toHex(passwordKey)); 209 | 210 | const passwordKeyArrayBuffer = await RNSimpleCrypto.PBKDF2.hash( 211 | RNSimpleCrypto.utils.convertUtf8ToArrayBuffer(password), 212 | RNSimpleCrypto.utils.convertUtf8ToArrayBuffer(salt), 213 | iterations, 214 | keyInBytes, 215 | hash 216 | ); 217 | console.log("PBKDF2 passwordKey bytes", toHex(passwordKeyArrayBuffer)); 218 | 219 | if (toHex(passwordKeyArrayBuffer) !== toHex(passwordKey)) { 220 | console.error('PBKDF2 result mismatch!') 221 | } 222 | 223 | const password2 = messageArrayBuffer; 224 | const salt2 = await RNSimpleCrypto.utils.randomBytes(8); 225 | const iterations2 = 10000; 226 | const keyInBytes2 = 32; 227 | const hash2 = "SHA256"; 228 | 229 | const passwordKey2 = await RNSimpleCrypto.PBKDF2.hash( 230 | password2, 231 | salt2, 232 | iterations2, 233 | keyInBytes2, 234 | hash2 235 | ); 236 | console.log("PBKDF2 passwordKey2", toHex(passwordKey2)); 237 | 238 | 239 | // -- RSA ------------------------------------------------------------ // 240 | 241 | const rsaKeys = await RNSimpleCrypto.RSA.generateKeys(1024); 242 | console.log("RSA1024 private key", rsaKeys.private); 243 | console.log("RSA1024 public key", rsaKeys.public); 244 | 245 | const rsaEncryptedMessage = await RNSimpleCrypto.RSA.encrypt( 246 | message, 247 | rsaKeys.public 248 | ); 249 | console.log("rsa Encrypt:", rsaEncryptedMessage); 250 | 251 | const rsaSignature = await RNSimpleCrypto.RSA.sign( 252 | rsaEncryptedMessage, 253 | rsaKeys.private, 254 | "SHA256" 255 | ); 256 | console.log("rsa Signature:", rsaSignature); 257 | 258 | const validSignature = await RNSimpleCrypto.RSA.verify( 259 | rsaSignature, 260 | rsaEncryptedMessage, 261 | rsaKeys.public, 262 | "SHA256" 263 | ); 264 | console.log("rsa signature verified:", validSignature); 265 | 266 | const rsaDecryptedMessage = await RNSimpleCrypto.RSA.decrypt( 267 | rsaEncryptedMessage, 268 | rsaKeys.private 269 | ); 270 | console.log("rsa Decrypt:", rsaDecryptedMessage); 271 | if (rsaDecryptedMessage !== message ) { 272 | console.error('RSA decrypt returned unexpected result') 273 | } 274 | ``` 275 | 276 | ## Forked Libraries 277 | 278 | - [@trackforce/react-native-crypto](https://github.com/trackforce/react-native-crypto) 279 | - [react-native-randombytes](https://github.com/mvayngrib/react-native-randombytes) 280 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | def safeExtGet(prop, fallback) { 2 | rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback 3 | } 4 | 5 | apply plugin: 'com.android.library' 6 | 7 | android { 8 | compileSdkVersion safeExtGet('compileSdkVersion', 26) 9 | buildToolsVersion safeExtGet('buildToolsVersion', '26.0.1') 10 | 11 | defaultConfig { 12 | minSdkVersion safeExtGet('minSdkVersion', 16) 13 | targetSdkVersion safeExtGet('targetSdkVersion', 22) 14 | versionCode 1 15 | versionName "1.0" 16 | } 17 | buildTypes { 18 | release { 19 | minifyEnabled false 20 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 21 | } 22 | } 23 | } 24 | 25 | dependencies { 26 | implementation 'com.android.support:appcompat-v7:23.0.1' 27 | implementation 'com.facebook.react:react-native:+' 28 | implementation 'com.madgag.spongycastle:core:1.58.0.0' 29 | implementation 'com.madgag.spongycastle:prov:1.54.0.0' 30 | implementation 'com.madgag.spongycastle:pkix:1.54.0.0' 31 | implementation 'com.madgag.spongycastle:pg:1.54.0.0' 32 | } 33 | -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ghbutton/react-native-simple-crypto/fe14572cba418c9fa2be03929a9a1075ffce8318/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Mon Apr 13 18:24:21 MDT 2020 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip 7 | -------------------------------------------------------------------------------- /android/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn () { 37 | echo "$*" 38 | } 39 | 40 | die () { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save () { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /android/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /android/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /android/src/main/java/com/pedrouid/crypto/RNSCAes.java: -------------------------------------------------------------------------------- 1 | package com.pedrouid.crypto; 2 | 3 | import android.widget.Toast; 4 | 5 | import java.io.IOException; 6 | import java.security.SecureRandom; 7 | import java.util.HashMap; 8 | import java.util.Map; 9 | 10 | import java.util.UUID; 11 | 12 | import java.security.MessageDigest; 13 | import java.security.NoSuchAlgorithmException; 14 | import java.security.spec.InvalidKeySpecException; 15 | import java.security.InvalidKeyException; 16 | 17 | import java.nio.charset.StandardCharsets; 18 | 19 | import javax.crypto.Cipher; 20 | import javax.crypto.SecretKey; 21 | import javax.crypto.spec.SecretKeySpec; 22 | import javax.crypto.spec.IvParameterSpec; 23 | import javax.crypto.spec.PBEKeySpec; 24 | import javax.crypto.SecretKeyFactory; 25 | import javax.crypto.Mac; 26 | 27 | import org.spongycastle.crypto.ExtendedDigest; 28 | import org.spongycastle.crypto.digests.SHA1Digest; 29 | import org.spongycastle.crypto.digests.SHA224Digest; 30 | import org.spongycastle.crypto.digests.SHA256Digest; 31 | import org.spongycastle.crypto.digests.SHA384Digest; 32 | import org.spongycastle.crypto.digests.SHA384Digest; 33 | import org.spongycastle.crypto.digests.SHA512Digest; 34 | import org.spongycastle.crypto.generators.PKCS5S2ParametersGenerator; 35 | import org.spongycastle.crypto.PBEParametersGenerator; 36 | import org.spongycastle.crypto.params.KeyParameter; 37 | import org.spongycastle.util.encoders.Hex; 38 | 39 | import android.util.Base64; 40 | 41 | import com.facebook.react.bridge.NativeModule; 42 | import com.facebook.react.bridge.ReactApplicationContext; 43 | import com.facebook.react.bridge.Promise; 44 | import com.facebook.react.bridge.ReactContext; 45 | import com.facebook.react.bridge.ReactContextBaseJavaModule; 46 | import com.facebook.react.bridge.ReactMethod; 47 | import com.facebook.react.bridge.Callback; 48 | 49 | public class RNSCAes extends ReactContextBaseJavaModule { 50 | 51 | private static final String CIPHER_ALGORITHM = "AES/CBC/PKCS7Padding"; 52 | private static final String KEY_ALGORITHM = "AES"; 53 | 54 | public RNSCAes(ReactApplicationContext reactContext) { 55 | super(reactContext); 56 | } 57 | 58 | @Override 59 | public String getName() { 60 | return "RNSCAes"; 61 | } 62 | 63 | @ReactMethod 64 | public void encrypt(String dataBase64, String keyBase64, String ivBase64, Promise promise) { 65 | try { 66 | String result = encrypt(dataBase64, keyBase64, ivBase64); 67 | promise.resolve(result); 68 | } catch (Exception e) { 69 | promise.reject("-1", e.getMessage()); 70 | } 71 | } 72 | 73 | @ReactMethod 74 | public void decrypt(String data, String pwd, String iv, Promise promise) { 75 | try { 76 | String strs = decrypt(data, pwd, iv); 77 | promise.resolve(strs); 78 | } catch (Exception e) { 79 | promise.reject("-1", e.getMessage()); 80 | } 81 | } 82 | 83 | @ReactMethod 84 | public void randomUuid(Promise promise) { 85 | try { 86 | String result = UUID.randomUUID().toString(); 87 | promise.resolve(result); 88 | } catch (Exception e) { 89 | promise.reject("-1", e.getMessage()); 90 | } 91 | } 92 | 93 | @ReactMethod 94 | public void randomKey(Integer length, Promise promise) { 95 | try { 96 | byte[] key = new byte[length]; 97 | SecureRandom rand = new SecureRandom(); 98 | rand.nextBytes(key); 99 | String keyHex = Util.bytesToHex(key); 100 | promise.resolve(keyHex); 101 | } catch (Exception e) { 102 | promise.reject("-1", e.getMessage()); 103 | } 104 | } 105 | 106 | final static IvParameterSpec emptyIvSpec = new IvParameterSpec(new byte[] {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}); 107 | 108 | private static String encrypt(String textBase64, String hexKey, String hexIv) throws Exception { 109 | if (textBase64 == null || textBase64.length() == 0) { 110 | return null; 111 | } 112 | 113 | byte[] key = Hex.decode(hexKey); 114 | SecretKey secretKey = new SecretKeySpec(key, KEY_ALGORITHM); 115 | 116 | Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM); 117 | cipher.init(Cipher.ENCRYPT_MODE, secretKey, hexIv == null ? emptyIvSpec : new IvParameterSpec(Hex.decode(hexIv))); 118 | byte[] encrypted = cipher.doFinal(Base64.decode(textBase64, Base64.NO_WRAP)); 119 | return Base64.encodeToString(encrypted, Base64.NO_WRAP); 120 | } 121 | 122 | private static String decrypt(String ciphertext, String hexKey, String hexIv) throws Exception { 123 | if(ciphertext == null || ciphertext.length() == 0) { 124 | return null; 125 | } 126 | 127 | byte[] key = Hex.decode(hexKey); 128 | SecretKey secretKey = new SecretKeySpec(key, KEY_ALGORITHM); 129 | 130 | Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM); 131 | cipher.init(Cipher.DECRYPT_MODE, secretKey, hexIv == null ? emptyIvSpec : new IvParameterSpec(Hex.decode(hexIv))); 132 | byte[] decrypted = cipher.doFinal(Base64.decode(ciphertext, Base64.NO_WRAP)); 133 | return Base64.encodeToString(decrypted, Base64.NO_WRAP); 134 | } 135 | 136 | } 137 | -------------------------------------------------------------------------------- /android/src/main/java/com/pedrouid/crypto/RNSCCryptoPackage.java: -------------------------------------------------------------------------------- 1 | package com.pedrouid.crypto; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Collections; 5 | import java.util.List; 6 | import java.util.Arrays; 7 | 8 | import com.facebook.react.ReactPackage; 9 | import com.facebook.react.bridge.JavaScriptModule; 10 | import com.facebook.react.bridge.NativeModule; 11 | import com.facebook.react.bridge.ReactApplicationContext; 12 | import com.facebook.react.uimanager.ViewManager; 13 | 14 | public class RNSCCryptoPackage implements ReactPackage { 15 | @Override 16 | public List createNativeModules(ReactApplicationContext reactContext) { 17 | return Arrays.asList( 18 | new RNSCAes(reactContext), 19 | new RNSCSha(reactContext), 20 | new RNSCHmac(reactContext), 21 | new RNSCPbkdf2(reactContext), 22 | new RNSCRsa(reactContext), 23 | new RNSCRandomBytes(reactContext) 24 | ); 25 | } 26 | 27 | @Override 28 | public List createViewManagers(ReactApplicationContext reactContext) { 29 | return Arrays.asList(); 30 | } 31 | 32 | // Deprecated from RN 0.47.0 33 | public List> createJSModules() { 34 | return Collections.emptyList(); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /android/src/main/java/com/pedrouid/crypto/RNSCHmac.java: -------------------------------------------------------------------------------- 1 | package com.pedrouid.crypto; 2 | 3 | import android.widget.Toast; 4 | 5 | import java.io.IOException; 6 | import java.security.SecureRandom; 7 | import java.util.HashMap; 8 | import java.util.Map; 9 | 10 | import java.util.UUID; 11 | 12 | import java.security.MessageDigest; 13 | import java.security.NoSuchAlgorithmException; 14 | import java.security.spec.InvalidKeySpecException; 15 | import java.security.InvalidKeyException; 16 | 17 | import java.nio.charset.StandardCharsets; 18 | 19 | import javax.crypto.Cipher; 20 | import javax.crypto.SecretKey; 21 | import javax.crypto.spec.SecretKeySpec; 22 | import javax.crypto.spec.IvParameterSpec; 23 | import javax.crypto.spec.PBEKeySpec; 24 | import javax.crypto.SecretKeyFactory; 25 | import javax.crypto.Mac; 26 | 27 | import org.spongycastle.crypto.ExtendedDigest; 28 | import org.spongycastle.crypto.digests.SHA1Digest; 29 | import org.spongycastle.crypto.digests.SHA224Digest; 30 | import org.spongycastle.crypto.digests.SHA256Digest; 31 | import org.spongycastle.crypto.digests.SHA384Digest; 32 | import org.spongycastle.crypto.digests.SHA384Digest; 33 | import org.spongycastle.crypto.digests.SHA512Digest; 34 | import org.spongycastle.crypto.generators.PKCS5S2ParametersGenerator; 35 | import org.spongycastle.crypto.PBEParametersGenerator; 36 | import org.spongycastle.crypto.params.KeyParameter; 37 | import org.spongycastle.util.encoders.Hex; 38 | 39 | import android.util.Base64; 40 | 41 | import com.facebook.react.bridge.NativeModule; 42 | import com.facebook.react.bridge.ReactApplicationContext; 43 | import com.facebook.react.bridge.Promise; 44 | import com.facebook.react.bridge.ReactContext; 45 | import com.facebook.react.bridge.ReactContextBaseJavaModule; 46 | import com.facebook.react.bridge.ReactMethod; 47 | import com.facebook.react.bridge.Callback; 48 | 49 | public class RNSCHmac extends ReactContextBaseJavaModule { 50 | 51 | public static final String HMAC_SHA_256 = "HmacSHA256"; 52 | 53 | public RNSCHmac(ReactApplicationContext reactContext) { 54 | super(reactContext); 55 | } 56 | 57 | @Override 58 | public String getName() { 59 | return "RNSCHmac"; 60 | } 61 | 62 | @ReactMethod 63 | public void hmac256(String data, String pwd, Promise promise) { 64 | try { 65 | String strs = hmac256(data, pwd); 66 | promise.resolve(strs); 67 | } catch (Exception e) { 68 | promise.reject("-1", e.getMessage()); 69 | } 70 | } 71 | 72 | private static String hmac256(String text, String key) throws NoSuchAlgorithmException, InvalidKeyException { 73 | byte[] contentData = Hex.decode(text); 74 | byte[] akHexData = Hex.decode(key); 75 | Mac sha256_HMAC = Mac.getInstance(HMAC_SHA_256); 76 | SecretKey secret_key = new SecretKeySpec(akHexData, HMAC_SHA_256); 77 | sha256_HMAC.init(secret_key); 78 | return Util.bytesToHex(sha256_HMAC.doFinal(contentData)); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /android/src/main/java/com/pedrouid/crypto/RNSCPbkdf2.java: -------------------------------------------------------------------------------- 1 | package com.pedrouid.crypto; 2 | 3 | import android.util.Base64; 4 | 5 | import com.facebook.react.bridge.Promise; 6 | import com.facebook.react.bridge.ReactApplicationContext; 7 | import com.facebook.react.bridge.ReactContextBaseJavaModule; 8 | import com.facebook.react.bridge.ReactMethod; 9 | 10 | import org.spongycastle.crypto.ExtendedDigest; 11 | import org.spongycastle.crypto.PBEParametersGenerator; 12 | import org.spongycastle.crypto.digests.SHA1Digest; 13 | import org.spongycastle.crypto.digests.SHA224Digest; 14 | import org.spongycastle.crypto.digests.SHA256Digest; 15 | import org.spongycastle.crypto.digests.SHA384Digest; 16 | import org.spongycastle.crypto.digests.SHA512Digest; 17 | import org.spongycastle.crypto.generators.PKCS5S2ParametersGenerator; 18 | import org.spongycastle.crypto.params.KeyParameter; 19 | 20 | import java.security.NoSuchAlgorithmException; 21 | import java.util.HashMap; 22 | import java.util.Map; 23 | 24 | public class RNSCPbkdf2 extends ReactContextBaseJavaModule { 25 | 26 | public RNSCPbkdf2(ReactApplicationContext reactContext) { 27 | super(reactContext); 28 | } 29 | 30 | @Override 31 | public String getName() { 32 | return "RNSCPbkdf2"; 33 | } 34 | 35 | @ReactMethod 36 | public void hash(String pwdBase64, String saltBase64, Integer iterations, Integer keyLen, String hash, Promise promise) { 37 | try { 38 | byte[] pwdBytes = Base64.decode(pwdBase64, Base64.NO_WRAP); 39 | byte[] saltBytes = Base64.decode(saltBase64, Base64.NO_WRAP); 40 | byte[] digest = pbkdf2(pwdBytes, saltBytes, iterations, keyLen, hash); 41 | promise.resolve(Base64.encodeToString(digest, Base64.NO_WRAP)); 42 | } catch (Exception e) { 43 | promise.reject("-1", e.getMessage()); 44 | } 45 | } 46 | 47 | private static byte[] pbkdf2(byte[] pwd, byte[] salt, Integer iterations, Integer keyLen, String hash) throws NullPointerException, NoSuchAlgorithmException { 48 | Map algMap = new HashMap(); 49 | algMap.put("SHA1", new SHA1Digest()); 50 | algMap.put("SHA224", new SHA224Digest()); 51 | algMap.put("SHA256", new SHA256Digest()); 52 | algMap.put("SHA384", new SHA384Digest()); 53 | algMap.put("SHA512", new SHA512Digest()); 54 | ExtendedDigest alg = algMap.get(hash); 55 | 56 | if (alg == null) { 57 | throw new NoSuchAlgorithmException("Specified hash algorithm is not supported"); 58 | } 59 | 60 | PBEParametersGenerator gen = new PKCS5S2ParametersGenerator(alg); 61 | gen.init(pwd, salt, iterations); 62 | return ((KeyParameter) gen.generateDerivedParameters(keyLen * 8)).getKey(); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /android/src/main/java/com/pedrouid/crypto/RNSCRandomBytes.java: -------------------------------------------------------------------------------- 1 | package com.pedrouid.crypto; 2 | 3 | import com.facebook.react.bridge.ReactMethod; 4 | import com.facebook.react.bridge.ReactApplicationContext; 5 | import com.facebook.react.bridge.Callback; 6 | 7 | import com.facebook.react.bridge.Promise; 8 | import com.facebook.react.bridge.ReactContextBaseJavaModule; 9 | 10 | import java.security.SecureRandom; 11 | import java.util.Map; 12 | import java.util.HashMap; 13 | 14 | import android.util.Base64; 15 | 16 | class RNSCRandomBytes extends ReactContextBaseJavaModule { 17 | private static final String SEED_KEY = "seed"; 18 | 19 | public RNSCRandomBytes(ReactApplicationContext reactContext) { 20 | super(reactContext); 21 | } 22 | 23 | @Override 24 | public String getName() { 25 | return "RNSCRandomBytes"; 26 | } 27 | 28 | @ReactMethod 29 | public void randomBytes(int size, Promise promise) { 30 | try { 31 | promise.resolve(getRandomBytes(size)); 32 | } catch (Exception e) { 33 | promise.reject("-1", e.getMessage()); 34 | } 35 | } 36 | 37 | @Override 38 | public Map getConstants() { 39 | final Map constants = new HashMap<>(); 40 | constants.put(SEED_KEY, getRandomBytes(4096)); 41 | return constants; 42 | } 43 | 44 | private String getRandomBytes(int size) { 45 | SecureRandom sr = new SecureRandom(); 46 | byte[] output = new byte[size]; 47 | sr.nextBytes(output); 48 | return Base64.encodeToString(output, Base64.NO_WRAP); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /android/src/main/java/com/pedrouid/crypto/RNSCRsa.java: -------------------------------------------------------------------------------- 1 | package com.pedrouid.crypto; 2 | 3 | import android.os.AsyncTask; 4 | 5 | import com.facebook.react.bridge.NoSuchKeyException; 6 | import com.facebook.react.bridge.ReactApplicationContext; 7 | import com.facebook.react.bridge.ReactContextBaseJavaModule; 8 | import com.facebook.react.bridge.ReactMethod; 9 | import com.facebook.react.bridge.Callback; 10 | import com.facebook.react.bridge.WritableNativeMap; 11 | import com.facebook.react.bridge.Promise; 12 | 13 | import java.io.IOException; 14 | import java.security.NoSuchAlgorithmException; 15 | 16 | public class RNSCRsa extends ReactContextBaseJavaModule { 17 | 18 | private final ReactApplicationContext reactContext; 19 | 20 | public RNSCRsa(ReactApplicationContext reactContext) { 21 | super(reactContext); 22 | this.reactContext = reactContext; 23 | } 24 | 25 | @Override 26 | public String getName() { 27 | return "RNSCRsa"; 28 | } 29 | 30 | private String getAlgorithmFromHash(final String hash) { 31 | if (hash.equals("Raw")) { 32 | return "NONEwithRSA"; 33 | } else if (hash.equals("SHA1")) { 34 | return "SHA1withRSA"; 35 | } else if (hash.equals("SHA224")) { 36 | return "SHA224withRSA"; 37 | } else if (hash.equals("SHA256")) { 38 | return "SHA256withRSA"; 39 | } else if (hash.equals("SHA384")) { 40 | return "SHA384withRSA"; 41 | } else if (hash.equals("SHA512")) { 42 | return "SHA512withRSA"; 43 | } else { 44 | return "SHA512withRSA"; 45 | } 46 | } 47 | 48 | @ReactMethod 49 | public void generate(final Promise promise) { 50 | this.generateKeys(2048, promise); 51 | } 52 | 53 | @ReactMethod 54 | public void generateKeys(final int keySize, final Promise promise) { 55 | AsyncTask.execute(new Runnable() { 56 | @Override 57 | public void run() { 58 | WritableNativeMap keys = new WritableNativeMap(); 59 | 60 | try { 61 | RSA rsa = new RSA(); 62 | rsa.generate(keySize); 63 | keys.putString("public", rsa.getPublicKey()); 64 | keys.putString("private", rsa.getPrivateKey()); 65 | promise.resolve(keys); 66 | } catch (NoSuchAlgorithmException e) { 67 | promise.reject("Error", e.getMessage()); 68 | } catch (Exception e) { 69 | promise.reject("Error", e.getMessage()); 70 | } 71 | } 72 | }); 73 | } 74 | 75 | @ReactMethod 76 | public void encrypt(final String message, final String publicKeyString, final Promise promise) { 77 | AsyncTask.execute(new Runnable() { 78 | @Override 79 | public void run() { 80 | try { 81 | RSA rsa = new RSA(); 82 | rsa.setPublicKey(publicKeyString); 83 | String encodedMessage = rsa.encrypt(message); 84 | promise.resolve(encodedMessage); 85 | } catch (Exception e) { 86 | promise.reject("Error", e.getMessage()); 87 | } 88 | } 89 | }); 90 | } 91 | 92 | @ReactMethod 93 | public void encrypt64(final String message, final String publicKeyString, final Promise promise) { 94 | AsyncTask.execute(new Runnable() { 95 | @Override 96 | public void run() { 97 | try { 98 | RSA rsa = new RSA(); 99 | rsa.setPublicKey(publicKeyString); 100 | String encodedMessage = rsa.encrypt64(message); 101 | promise.resolve(encodedMessage); 102 | } catch (Exception e) { 103 | promise.reject("Error", e.getMessage()); 104 | } 105 | } 106 | }); 107 | } 108 | 109 | @ReactMethod 110 | public void decrypt(final String encodedMessage, final String privateKeyString, final Promise promise) { 111 | AsyncTask.execute(new Runnable() { 112 | @Override 113 | public void run() { 114 | try { 115 | RSA rsa = new RSA(); 116 | rsa.setPrivateKey(privateKeyString); 117 | String message = rsa.decrypt(encodedMessage); 118 | promise.resolve(message); 119 | 120 | } catch (Exception e) { 121 | promise.reject("Error", e.getMessage()); 122 | } 123 | } 124 | }); 125 | } 126 | 127 | @ReactMethod 128 | public void decrypt64(final String encodedMessage, final String privateKeyString, final Promise promise) { 129 | AsyncTask.execute(new Runnable() { 130 | @Override 131 | public void run() { 132 | try { 133 | RSA rsa = new RSA(); 134 | rsa.setPrivateKey(privateKeyString); 135 | String message = rsa.decrypt64(encodedMessage); 136 | promise.resolve(message); 137 | 138 | } catch (Exception e) { 139 | promise.reject("Error", e.getMessage()); 140 | } 141 | } 142 | }); 143 | } 144 | 145 | @ReactMethod 146 | public void sign(final String message, final String privateKeyString, final String hash, final Promise promise) { 147 | AsyncTask.execute(new Runnable() { 148 | @Override 149 | public void run() { 150 | try { 151 | RSA rsa = new RSA(); 152 | rsa.setPrivateKey(privateKeyString); 153 | String signature = rsa.sign(message, getAlgorithmFromHash(hash)); 154 | promise.resolve(signature); 155 | 156 | } catch (Exception e) { 157 | promise.reject("Error", e.getMessage()); 158 | } 159 | } 160 | }); 161 | } 162 | 163 | @ReactMethod 164 | public void sign64(final String message, final String privateKeyString, final String hash, final Promise promise) { 165 | AsyncTask.execute(new Runnable() { 166 | @Override 167 | public void run() { 168 | try { 169 | RSA rsa = new RSA(); 170 | rsa.setPrivateKey(privateKeyString); 171 | String signature = rsa.sign64(message, getAlgorithmFromHash(hash)); 172 | promise.resolve(signature); 173 | 174 | } catch (Exception e) { 175 | promise.reject("Error", e.getMessage()); 176 | } 177 | } 178 | }); 179 | } 180 | 181 | @ReactMethod 182 | public void verify(final String signature, final String message, final String publicKeyString, final String hash, 183 | final Promise promise) { 184 | AsyncTask.execute(new Runnable() { 185 | @Override 186 | public void run() { 187 | try { 188 | RSA rsa = new RSA(); 189 | rsa.setPublicKey(publicKeyString); 190 | boolean verified = rsa.verify(signature, message, getAlgorithmFromHash(hash)); 191 | promise.resolve(verified); 192 | 193 | } catch (Exception e) { 194 | promise.reject("Error", e.getMessage()); 195 | } 196 | } 197 | }); 198 | } 199 | 200 | @ReactMethod 201 | public void verify64(final String signature, final String message, final String publicKeyString, final String hash, 202 | final Promise promise) { 203 | AsyncTask.execute(new Runnable() { 204 | @Override 205 | public void run() { 206 | try { 207 | RSA rsa = new RSA(); 208 | rsa.setPublicKey(publicKeyString); 209 | boolean verified = rsa.verify64(signature, message, getAlgorithmFromHash(hash)); 210 | promise.resolve(verified); 211 | 212 | } catch (Exception e) { 213 | promise.reject("Error", e.getMessage()); 214 | } 215 | } 216 | }); 217 | } 218 | } 219 | -------------------------------------------------------------------------------- /android/src/main/java/com/pedrouid/crypto/RNSCSha.java: -------------------------------------------------------------------------------- 1 | package com.pedrouid.crypto; 2 | 3 | import android.widget.Toast; 4 | 5 | import java.io.IOException; 6 | import java.security.SecureRandom; 7 | import java.util.Arrays; 8 | import java.util.ArrayList; 9 | import java.util.HashMap; 10 | import java.util.Map; 11 | 12 | import java.util.UUID; 13 | 14 | import java.security.MessageDigest; 15 | import java.security.NoSuchAlgorithmException; 16 | import java.security.spec.InvalidKeySpecException; 17 | import java.security.InvalidKeyException; 18 | 19 | import java.nio.charset.StandardCharsets; 20 | 21 | import javax.crypto.Cipher; 22 | import javax.crypto.SecretKey; 23 | import javax.crypto.spec.SecretKeySpec; 24 | import javax.crypto.spec.IvParameterSpec; 25 | import javax.crypto.spec.PBEKeySpec; 26 | import javax.crypto.SecretKeyFactory; 27 | import javax.crypto.Mac; 28 | 29 | import org.spongycastle.crypto.ExtendedDigest; 30 | import org.spongycastle.crypto.digests.SHA1Digest; 31 | import org.spongycastle.crypto.digests.SHA224Digest; 32 | import org.spongycastle.crypto.digests.SHA256Digest; 33 | import org.spongycastle.crypto.digests.SHA384Digest; 34 | import org.spongycastle.crypto.digests.SHA512Digest; 35 | import org.spongycastle.crypto.generators.PKCS5S2ParametersGenerator; 36 | import org.spongycastle.crypto.PBEParametersGenerator; 37 | import org.spongycastle.crypto.params.KeyParameter; 38 | import org.spongycastle.util.encoders.Hex; 39 | 40 | import android.util.Base64; 41 | 42 | import com.facebook.react.bridge.NativeModule; 43 | import com.facebook.react.bridge.ReactApplicationContext; 44 | import com.facebook.react.bridge.Promise; 45 | import com.facebook.react.bridge.ReactContext; 46 | import com.facebook.react.bridge.ReactContextBaseJavaModule; 47 | import com.facebook.react.bridge.ReactMethod; 48 | import com.facebook.react.bridge.Callback; 49 | 50 | public class RNSCSha extends ReactContextBaseJavaModule { 51 | 52 | public RNSCSha(ReactApplicationContext reactContext) { 53 | super(reactContext); 54 | } 55 | 56 | private static ArrayList algorithms = new ArrayList( 57 | Arrays.asList("SHA-1", 58 | "SHA-256", 59 | "SHA-512")); 60 | 61 | @Override 62 | public String getName() { 63 | return "RNSCSha"; 64 | } 65 | 66 | private byte[] sha(byte[] data, String algorithm) throws Exception { 67 | if (!algorithms.contains(algorithm)) { 68 | throw new Exception("Invalid algorithm"); 69 | } 70 | 71 | MessageDigest md = MessageDigest.getInstance(algorithm); 72 | md.update(data); 73 | return md.digest(); 74 | } 75 | 76 | @ReactMethod 77 | public void shaBase64(String data, String algorithm, Promise promise) throws Exception { 78 | try { 79 | byte[] digest = this.sha(Base64.decode(data, Base64.NO_WRAP), algorithm); 80 | promise.resolve(Base64.encodeToString(digest, Base64.NO_WRAP)); 81 | } catch (Exception e) { 82 | promise.reject("-1", e.getMessage()); 83 | } 84 | } 85 | 86 | @ReactMethod 87 | public void shaUtf8(String data, String algorithm, Promise promise) throws Exception { 88 | try { 89 | byte[] digest = this.sha(data.getBytes(), algorithm); 90 | promise.resolve(Util.bytesToHex(digest)); 91 | } catch (Exception e) { 92 | promise.reject("-1", e.getMessage()); 93 | } 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /android/src/main/java/com/pedrouid/crypto/RSA.java: -------------------------------------------------------------------------------- 1 | package com.pedrouid.crypto; 2 | 3 | 4 | import android.annotation.TargetApi; 5 | import android.os.Build; 6 | import android.security.keystore.KeyGenParameterSpec; 7 | import android.security.keystore.KeyProperties; 8 | import android.security.KeyPairGeneratorSpec; 9 | 10 | import android.util.Base64; 11 | import android.util.Log; 12 | import android.content.Context; 13 | 14 | import java.util.Calendar; 15 | import java.math.BigInteger; 16 | import java.io.Reader; 17 | import java.io.StringReader; 18 | import java.io.StringWriter; 19 | import java.security.InvalidAlgorithmParameterException; 20 | import java.security.KeyPair; 21 | import java.security.KeyStore; 22 | import java.security.KeyStoreException; 23 | import java.security.NoSuchProviderException; 24 | import java.security.PublicKey; 25 | import java.security.PrivateKey; 26 | import java.security.KeyFactory; 27 | import java.security.KeyPairGenerator; 28 | import java.security.NoSuchAlgorithmException; 29 | import java.security.InvalidKeyException; 30 | import java.security.Signature; 31 | import java.security.SignatureException; 32 | import java.security.UnrecoverableEntryException; 33 | import java.security.UnrecoverableKeyException; 34 | import java.security.cert.CertificateException; 35 | import java.security.spec.X509EncodedKeySpec; 36 | import java.security.spec.RSAPublicKeySpec; 37 | import java.security.spec.RSAPrivateKeySpec; 38 | import java.security.spec.InvalidKeySpecException; 39 | 40 | import javax.crypto.Cipher; 41 | import javax.crypto.IllegalBlockSizeException; 42 | import javax.crypto.NoSuchPaddingException; 43 | import javax.crypto.BadPaddingException; 44 | import javax.security.cert.X509Certificate; 45 | import javax.security.auth.x500.X500Principal; 46 | 47 | import java.io.IOException; 48 | 49 | import org.spongycastle.asn1.ASN1InputStream; 50 | import org.spongycastle.asn1.ASN1Encodable; 51 | import org.spongycastle.asn1.ASN1Primitive; 52 | import org.spongycastle.asn1.pkcs.PrivateKeyInfo; 53 | import org.spongycastle.asn1.pkcs.RSAPublicKey; 54 | import org.spongycastle.asn1.pkcs.RSAPrivateKey; 55 | import org.spongycastle.asn1.x509.SubjectPublicKeyInfo; 56 | import org.spongycastle.asn1.x509.RSAPublicKeyStructure; 57 | import org.spongycastle.util.io.pem.PemObject; 58 | import org.spongycastle.util.io.pem.PemWriter; 59 | import org.spongycastle.util.io.pem.PemReader; 60 | import org.spongycastle.asn1.pkcs.RSAPublicKey; 61 | import org.spongycastle.openssl.PEMParser; 62 | import org.spongycastle.util.io.pem.PemObject; 63 | 64 | import static android.security.keystore.KeyProperties.*; 65 | 66 | import static java.nio.charset.StandardCharsets.UTF_8; 67 | import java.nio.charset.Charset; 68 | 69 | public class RSA { 70 | public static Charset CharsetUTF_8; 71 | 72 | public static final String ALGORITHM = "RSA"; 73 | 74 | private static final String PUBLIC_HEADER = "RSA PUBLIC KEY"; 75 | private static final String PRIVATE_HEADER = "RSA PRIVATE KEY"; 76 | 77 | private String keyTag; 78 | 79 | private PublicKey publicKey; 80 | private PrivateKey privateKey; 81 | 82 | public RSA() { 83 | this.setupCharset(); 84 | } 85 | 86 | public RSA(String keyTag) throws KeyStoreException, UnrecoverableEntryException, NoSuchAlgorithmException, IOException, CertificateException { 87 | this.setupCharset(); 88 | this.keyTag = keyTag; 89 | this.loadFromKeystore(); 90 | } 91 | 92 | private void setupCharset() { 93 | if (android.os.Build.VERSION.SDK_INT >= 19) { 94 | CharsetUTF_8 = UTF_8; 95 | } else { 96 | CharsetUTF_8 = Charset.forName("UTF-8"); 97 | } 98 | } 99 | 100 | public String getPublicKey() throws IOException { 101 | byte[] pkcs1PublicKey = publicKeyToPkcs1(this.publicKey); 102 | 103 | return dataToPem(PUBLIC_HEADER, pkcs1PublicKey); 104 | } 105 | 106 | public String getPrivateKey() throws IOException { 107 | byte[] pkcs1PrivateKey = privateKeyToPkcs1(this.privateKey); 108 | 109 | return dataToPem(PRIVATE_HEADER, pkcs1PrivateKey); 110 | } 111 | 112 | public void setPublicKey(String publicKey) throws IOException, NoSuchAlgorithmException, InvalidKeySpecException { 113 | this.publicKey = pkcs1ToPublicKey(publicKey); 114 | } 115 | 116 | public void setPrivateKey(String privateKey) throws IOException, NoSuchAlgorithmException, InvalidKeySpecException { 117 | byte[] pkcs1PrivateKey = pemToData(privateKey); 118 | this.privateKey = pkcs1ToPrivateKey(pkcs1PrivateKey); 119 | } 120 | 121 | 122 | // This function will be called by encrypt and encrypt64 123 | private byte[] encrypt(byte[] data) throws NoSuchAlgorithmException, InvalidKeySpecException, IllegalBlockSizeException, BadPaddingException, NoSuchPaddingException, InvalidKeyException { 124 | String encodedMessage = null; 125 | final Cipher cipher = Cipher.getInstance("RSA/NONE/PKCS1Padding"); 126 | cipher.init(Cipher.ENCRYPT_MODE, this.publicKey); 127 | byte[] cipherBytes = cipher.doFinal(data); 128 | return cipherBytes; 129 | } 130 | 131 | // Base64 input 132 | public String encrypt64(String b64Message) throws NoSuchAlgorithmException, InvalidKeySpecException, IllegalBlockSizeException, BadPaddingException, NoSuchPaddingException, InvalidKeyException { 133 | byte[] data = Base64.decode(b64Message, Base64.NO_WRAP); 134 | byte[] cipherBytes = encrypt(data); 135 | return Base64.encodeToString(cipherBytes, Base64.NO_WRAP); 136 | } 137 | 138 | // UTF-8 input 139 | public String encrypt(String message) throws NoSuchAlgorithmException, InvalidKeySpecException, IllegalBlockSizeException, BadPaddingException, NoSuchPaddingException, InvalidKeyException { 140 | byte[] data = message.getBytes(CharsetUTF_8); 141 | byte[] cipherBytes = encrypt(data); 142 | return Base64.encodeToString(cipherBytes, Base64.NO_WRAP); 143 | } 144 | 145 | private byte[] decrypt(byte[] cipherBytes) throws NoSuchAlgorithmException, InvalidKeySpecException, IllegalBlockSizeException, BadPaddingException, NoSuchPaddingException, InvalidKeyException { 146 | String message = null; 147 | final Cipher cipher = Cipher.getInstance("RSA/NONE/PKCS1Padding"); 148 | cipher.init(Cipher.DECRYPT_MODE, this.privateKey); 149 | byte[] data = cipher.doFinal(cipherBytes); 150 | return data; 151 | } 152 | 153 | // UTF-8 input 154 | public String decrypt(String message) throws NoSuchAlgorithmException, InvalidKeySpecException, IllegalBlockSizeException, BadPaddingException, NoSuchPaddingException, InvalidKeyException { 155 | byte[] cipherBytes = Base64.decode(message, Base64.NO_WRAP); 156 | byte[] data = decrypt(cipherBytes); 157 | return new String(data, CharsetUTF_8); 158 | } 159 | 160 | // Base64 input 161 | public String decrypt64(String b64message) throws NoSuchAlgorithmException, InvalidKeySpecException, IllegalBlockSizeException, BadPaddingException, NoSuchPaddingException, InvalidKeyException { 162 | byte[] cipherBytes = Base64.decode(b64message, Base64.NO_WRAP); 163 | byte[] data = decrypt(cipherBytes); 164 | return Base64.encodeToString(data, Base64.NO_WRAP); 165 | } 166 | 167 | private String sign(byte[] messageBytes, String algorithm) throws NoSuchAlgorithmException, InvalidKeySpecException, IllegalBlockSizeException, BadPaddingException, NoSuchPaddingException, InvalidKeyException, SignatureException { 168 | Signature privateSignature = Signature.getInstance(algorithm); 169 | privateSignature.initSign(this.privateKey); 170 | privateSignature.update(messageBytes); 171 | byte[] signature = privateSignature.sign(); 172 | return Base64.encodeToString(signature, Base64.NO_WRAP); 173 | } 174 | 175 | // b64 message 176 | public String sign64(String b64message, String algorithm) throws NoSuchAlgorithmException, InvalidKeySpecException, IllegalBlockSizeException, BadPaddingException, NoSuchPaddingException, InvalidKeyException, SignatureException { 177 | byte[] messageBytes = Base64.decode(b64message, Base64.NO_WRAP); 178 | return sign(messageBytes, algorithm); 179 | } 180 | 181 | //utf-8 message 182 | public String sign(String message, String algorithm) throws NoSuchAlgorithmException, InvalidKeySpecException, IllegalBlockSizeException, BadPaddingException, NoSuchPaddingException, InvalidKeyException, SignatureException { 183 | byte[] messageBytes = message.getBytes(CharsetUTF_8); 184 | return sign(messageBytes, algorithm); 185 | } 186 | 187 | private boolean verify(byte[] signatureBytes, byte[] messageBytes, String algorithm) throws NoSuchAlgorithmException, InvalidKeySpecException, IllegalBlockSizeException, BadPaddingException, NoSuchPaddingException, InvalidKeyException, SignatureException { 188 | Signature publicSignature = Signature.getInstance(algorithm); 189 | publicSignature.initVerify(this.publicKey); 190 | publicSignature.update(messageBytes); 191 | return publicSignature.verify(signatureBytes); 192 | } 193 | 194 | // b64 message 195 | public boolean verify64(String signature, String message, String algorithm) throws NoSuchAlgorithmException, InvalidKeySpecException, IllegalBlockSizeException, BadPaddingException, NoSuchPaddingException, InvalidKeyException, SignatureException { 196 | Signature publicSignature = Signature.getInstance(algorithm); 197 | publicSignature.initVerify(this.publicKey); 198 | byte[] messageBytes = Base64.decode(message, Base64.NO_WRAP); 199 | byte[] signatureBytes = Base64.decode(signature, Base64.NO_WRAP); 200 | return verify(signatureBytes, messageBytes, algorithm); 201 | } 202 | 203 | // utf-8 message 204 | public boolean verify(String signature, String message, String algorithm) throws NoSuchAlgorithmException, InvalidKeySpecException, IllegalBlockSizeException, BadPaddingException, NoSuchPaddingException, InvalidKeyException, SignatureException { 205 | Signature publicSignature = Signature.getInstance(algorithm); 206 | publicSignature.initVerify(this.publicKey); 207 | byte[] messageBytes = message.getBytes(CharsetUTF_8); 208 | byte[] signatureBytes = Base64.decode(signature, Base64.NO_WRAP); 209 | return verify(signatureBytes, messageBytes, algorithm); 210 | } 211 | 212 | private String dataToPem(String header, byte[] keyData) throws IOException { 213 | PemObject pemObject = new PemObject(header, keyData); 214 | StringWriter stringWriter = new StringWriter(); 215 | PemWriter pemWriter = new PemWriter(stringWriter); 216 | pemWriter.writeObject(pemObject); 217 | pemWriter.close(); 218 | return stringWriter.toString(); 219 | } 220 | 221 | private byte[] pemToData(String pemKey) throws IOException { 222 | Reader keyReader = new StringReader(pemKey); 223 | PemReader pemReader = new PemReader(keyReader); 224 | PemObject pemObject = pemReader.readPemObject(); 225 | return pemObject.getContent(); 226 | } 227 | 228 | private PublicKey pkcs1ToPublicKey(String publicKey) throws IOException, NoSuchAlgorithmException, InvalidKeySpecException { 229 | Reader keyReader = null; 230 | try { 231 | keyReader = new StringReader(publicKey); 232 | PEMParser pemParser = new PEMParser(keyReader); 233 | SubjectPublicKeyInfo subjectPublicKeyInfo = (SubjectPublicKeyInfo) pemParser.readObject(); 234 | X509EncodedKeySpec spec = new X509EncodedKeySpec(subjectPublicKeyInfo.getEncoded()); 235 | return KeyFactory.getInstance("RSA").generatePublic(spec); 236 | } finally { 237 | if (keyReader != null) { 238 | keyReader.close(); 239 | } 240 | } 241 | } 242 | 243 | private PrivateKey pkcs1ToPrivateKey(byte[] pkcs1PrivateKey) throws IOException, NoSuchAlgorithmException, InvalidKeySpecException { 244 | ASN1InputStream in = new ASN1InputStream(pkcs1PrivateKey); 245 | ASN1Primitive obj = in.readObject(); 246 | RSAPrivateKey keyStruct = RSAPrivateKey.getInstance(obj); 247 | RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(keyStruct.getModulus(), keyStruct.getPrivateExponent()); 248 | KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM); 249 | return keyFactory.generatePrivate(keySpec); 250 | } 251 | 252 | private byte[] publicKeyToPkcs1(PublicKey publicKey) throws IOException { 253 | SubjectPublicKeyInfo spkInfo = SubjectPublicKeyInfo.getInstance(publicKey.getEncoded()); 254 | ASN1Primitive primitive = spkInfo.parsePublicKey(); 255 | return primitive.getEncoded(); 256 | } 257 | 258 | private byte[] privateKeyToPkcs1(PrivateKey privateKey) throws IOException { 259 | PrivateKeyInfo pkInfo = PrivateKeyInfo.getInstance(privateKey.getEncoded()); 260 | ASN1Encodable encodeable = pkInfo.parsePrivateKey(); 261 | ASN1Primitive primitive = encodeable.toASN1Primitive(); 262 | return primitive.getEncoded(); 263 | } 264 | 265 | public void loadFromKeystore() throws KeyStoreException, UnrecoverableEntryException, NoSuchAlgorithmException, IOException, CertificateException { 266 | KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); 267 | keyStore.load(null); 268 | KeyStore.PrivateKeyEntry privateKeyEntry = (KeyStore.PrivateKeyEntry) keyStore.getEntry(this.keyTag, null); 269 | 270 | if (privateKeyEntry != null) { 271 | this.privateKey = privateKeyEntry.getPrivateKey(); 272 | this.publicKey = privateKeyEntry.getCertificate().getPublicKey(); 273 | } 274 | } 275 | 276 | public void deletePrivateKey() throws KeyStoreException, UnrecoverableEntryException, NoSuchAlgorithmException, IOException, CertificateException { 277 | KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); 278 | keyStore.load(null); 279 | keyStore.deleteEntry(this.keyTag); 280 | this.privateKey = null; 281 | this.publicKey = null; 282 | } 283 | 284 | public void generate() throws IOException, NoSuchAlgorithmException, InvalidAlgorithmParameterException { 285 | this.generate(2048); 286 | } 287 | 288 | public void generate(int keySize) throws IOException, NoSuchAlgorithmException, InvalidAlgorithmParameterException { 289 | KeyPairGenerator kpg = KeyPairGenerator.getInstance(ALGORITHM); 290 | kpg.initialize(keySize); 291 | 292 | KeyPair keyPair = kpg.genKeyPair(); 293 | this.publicKey = keyPair.getPublic(); 294 | this.privateKey = keyPair.getPrivate(); 295 | } 296 | 297 | public void generate(String keyTag, Context context) throws IOException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, NoSuchProviderException { 298 | this.generate(keyTag, 2048, context); 299 | } 300 | 301 | public void generate(String keyTag, int keySize, Context context) throws IOException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, NoSuchProviderException { 302 | KeyPairGenerator kpg = KeyPairGenerator.getInstance(ALGORITHM, "AndroidKeyStore"); 303 | if (android.os.Build.VERSION.SDK_INT >= 23) { 304 | kpg.initialize( 305 | new KeyGenParameterSpec.Builder( 306 | keyTag, 307 | PURPOSE_ENCRYPT | PURPOSE_DECRYPT | PURPOSE_SIGN | PURPOSE_VERIFY 308 | ) 309 | .setKeySize(keySize) 310 | .setDigests(KeyProperties.DIGEST_SHA512) 311 | .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1) 312 | .setSignaturePaddings(KeyProperties.SIGNATURE_PADDING_RSA_PKCS1) 313 | .build() 314 | ); 315 | } else { 316 | Calendar endDate = Calendar.getInstance(); 317 | endDate.add(Calendar.YEAR, 1); 318 | KeyPairGeneratorSpec.Builder keyPairGeneratorSpec = new KeyPairGeneratorSpec.Builder(context) 319 | .setAlias(keyTag) 320 | .setSubject(new X500Principal( 321 | String.format("CN=%s, OU=%s", keyTag, context.getPackageName()) 322 | )) 323 | .setSerialNumber(BigInteger.ONE) 324 | .setStartDate(Calendar.getInstance().getTime()) 325 | .setEndDate(endDate.getTime()); 326 | if (android.os.Build.VERSION.SDK_INT >= 19) { 327 | keyPairGeneratorSpec.setKeySize(keySize).setKeyType(ALGORITHM); 328 | } 329 | kpg.initialize(keyPairGeneratorSpec.build()); 330 | } 331 | 332 | KeyPair keyPair = kpg.genKeyPair(); 333 | this.publicKey = keyPair.getPublic(); 334 | } 335 | 336 | } 337 | -------------------------------------------------------------------------------- /android/src/main/java/com/pedrouid/crypto/Util.java: -------------------------------------------------------------------------------- 1 | package com.pedrouid.crypto; 2 | 3 | class Util { 4 | static String bytesToHex(byte[] bytes) { 5 | final char[] hexArray = "0123456789abcdef".toCharArray(); 6 | char[] hexChars = new char[bytes.length * 2]; 7 | for ( int j = 0; j < bytes.length; j++ ) { 8 | int v = bytes[j] & 0xFF; 9 | hexChars[j * 2] = hexArray[v >>> 4]; 10 | hexChars[j * 2 + 1] = hexArray[v & 0x0F]; 11 | } 12 | return new String(hexChars); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /index.d.ts: -------------------------------------------------------------------------------- 1 | declare module "react-native-simple-crypto" { 2 | interface PublicKey { 3 | public: string; 4 | } 5 | 6 | interface KeyPair extends PublicKey { 7 | private: string; 8 | } 9 | 10 | export namespace AES { 11 | export function encrypt( 12 | text: ArrayBuffer, 13 | key: ArrayBuffer, 14 | iv: ArrayBuffer 15 | ): Promise; 16 | export function decrypt( 17 | ciphertext: ArrayBuffer, 18 | key: ArrayBuffer, 19 | iv: ArrayBuffer 20 | ): Promise; 21 | } 22 | 23 | export namespace SHA { 24 | export function sha1(text: string): Promise; 25 | export function sha1(text: ArrayBuffer): Promise; 26 | export function sha256(text: string): Promise; 27 | export function sha256(text: ArrayBuffer): Promise; 28 | export function sha512(text: string): Promise; 29 | export function sha512(text: ArrayBuffer): Promise; 30 | } 31 | 32 | export namespace HMAC { 33 | export function hmac256( 34 | ciphertext: ArrayBuffer, 35 | key: ArrayBuffer 36 | ): Promise; 37 | } 38 | 39 | export namespace PBKDF2 { 40 | export function hash( 41 | password: string | ArrayBuffer, 42 | salt: string | ArrayBuffer, 43 | iterations: number, 44 | keyLen: number, 45 | algorithm: "SHA1" | "SHA224" | "SHA256" | "SHA384" | "SHA512" 46 | ): Promise; 47 | } 48 | 49 | export namespace RSA { 50 | export function generateKeys(keySize: number): Promise; 51 | export function encrypt(data: string, key: string): Promise; 52 | export function decrypt(data: string, key: string): Promise; 53 | export function sign( 54 | data: string, 55 | key: string, 56 | hash: "Raw" | "SHA1" | "SHA224" | "SHA256" | "SHA384" | "SHA512" 57 | ): Promise; 58 | export function verify( 59 | data: string, 60 | secretToVerify: string, 61 | key: string, 62 | hash: "Raw" | "SHA1" | "SHA224" | "SHA256" | "SHA384" | "SHA512" 63 | ): Promise; 64 | } 65 | 66 | export namespace utils { 67 | export function randomBytes(bytes: number): Promise; 68 | export function convertArrayBufferToUtf8(input: ArrayBuffer): string; 69 | export function convertUtf8ToArrayBuffer(input: string): ArrayBuffer; 70 | export function convertArrayBufferToBase64(input: ArrayBuffer): string; 71 | export function convertBase64ToArrayBuffer(input: string): ArrayBuffer; 72 | export function convertArrayBufferToHex(input: ArrayBuffer): string; 73 | export function convertHexToArrayBuffer(input: string): ArrayBuffer; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | import base64js from 'base64-js'; 4 | import hexLite from 'hex-lite'; 5 | import { NativeModules } from 'react-native'; 6 | 7 | function convertArrayBufferToUtf8(arrayBuffer) { 8 | const array = new Uint8Array(arrayBuffer); 9 | const chars = []; 10 | let i = 0; 11 | 12 | while (i < array.length) { 13 | const byte = array[i]; 14 | if (byte < 128) { 15 | chars.push(String.fromCharCode(byte)); 16 | i++; 17 | } else if (byte > 191 && byte < 224) { 18 | chars.push( 19 | String.fromCharCode(((byte & 0x1f) << 6) | (array[i + 1] & 0x3f)) 20 | ); 21 | i += 2; 22 | } else { 23 | chars.push( 24 | String.fromCharCode( 25 | ((byte & 0x0f) << 12) | 26 | ((array[i + 1] & 0x3f) << 6) | 27 | (array[i + 2] & 0x3f) 28 | ) 29 | ); 30 | i += 3; 31 | } 32 | } 33 | 34 | return chars.join(''); 35 | } 36 | 37 | function convertUtf8ToArrayBuffer(utf8) { 38 | const bytes = []; 39 | 40 | let i = 0; 41 | utf8 = encodeURI(utf8); 42 | while (i < utf8.length) { 43 | const byte = utf8.charCodeAt(i++); 44 | if (byte === 37) { 45 | bytes.push(parseInt(utf8.substr(i, 2), 16)); 46 | i += 2; 47 | } else { 48 | bytes.push(byte); 49 | } 50 | } 51 | 52 | const array = new Uint8Array(bytes); 53 | return array.buffer; 54 | } 55 | 56 | function convertArrayBufferToBase64(arrayBuffer) { 57 | return base64js.fromByteArray(new Uint8Array(arrayBuffer)); 58 | } 59 | 60 | function convertBase64ToArrayBuffer(base64) { 61 | return base64js.toByteArray(base64).buffer; 62 | } 63 | 64 | const convertArrayBufferToHex = hexLite.fromBuffer; 65 | 66 | const convertHexToArrayBuffer = hexLite.toBuffer; 67 | 68 | async function randomBytes(length) { 69 | return convertBase64ToArrayBuffer(await NativeModules.RNSCRandomBytes.randomBytes(length)); 70 | } 71 | 72 | async function SHAWrapper(data, algorithm) { 73 | if (typeof data === 'string') { 74 | return NativeModules.RNSCSha.shaUtf8(data, algorithm); 75 | } else { 76 | const dataBase64 = convertArrayBufferToBase64(data); 77 | const result = await NativeModules.RNSCSha.shaBase64(dataBase64, algorithm); 78 | 79 | return convertBase64ToArrayBuffer(result); 80 | } 81 | } 82 | 83 | const AES = { 84 | encrypt: async function (textArrayBuffer, keyArrayBuffer, ivArrayBuffer) { 85 | const textBase64 = convertArrayBufferToBase64(textArrayBuffer); 86 | const keyHex = convertArrayBufferToHex(keyArrayBuffer); 87 | const ivHex = convertArrayBufferToHex(ivArrayBuffer); 88 | return convertBase64ToArrayBuffer(await NativeModules.RNSCAes.encrypt(textBase64, keyHex, ivHex)); 89 | }, 90 | decrypt: async function (cipherTextArrayBuffer, keyArrayBuffer, ivArrayBuffer) { 91 | const cipherTextBase64 = convertArrayBufferToBase64(cipherTextArrayBuffer); 92 | const keyHex = convertArrayBufferToHex(keyArrayBuffer); 93 | const ivHex = convertArrayBufferToHex(ivArrayBuffer); 94 | return convertBase64ToArrayBuffer(await NativeModules.RNSCAes.decrypt(cipherTextBase64, keyHex, ivHex)); 95 | } 96 | }; 97 | 98 | const SHA = { 99 | sha1: data => SHAWrapper(data, 'SHA-1'), 100 | sha256: data => SHAWrapper(data, 'SHA-256'), 101 | sha512: data => SHAWrapper(data, 'SHA-512') 102 | }; 103 | 104 | const HMAC = { 105 | hmac256: async function (textArrayBuffer, keyArrayBuffer) { 106 | const textHex = convertArrayBufferToHex(textArrayBuffer); 107 | const keyHex = convertArrayBufferToHex(keyArrayBuffer); 108 | const signatureHex = await NativeModules.RNSCHmac.hmac256(textHex, keyHex); 109 | return convertHexToArrayBuffer(signatureHex); 110 | } 111 | }; 112 | 113 | const PBKDF2 = { 114 | hash: async function (password, salt, iterations, keyLength, algorithm) { 115 | let passwordToHash = password; 116 | let saltToHash = salt; 117 | 118 | if (typeof password === 'string') { 119 | passwordToHash = convertUtf8ToArrayBuffer(password); 120 | } 121 | 122 | if (typeof salt === 'string') { 123 | saltToHash = convertUtf8ToArrayBuffer(salt); 124 | } 125 | 126 | const digest = await NativeModules.RNSCPbkdf2.hash( 127 | convertArrayBufferToBase64(passwordToHash), 128 | convertArrayBufferToBase64(saltToHash), 129 | iterations, 130 | keyLength, 131 | algorithm 132 | ); 133 | 134 | return convertBase64ToArrayBuffer(digest); 135 | } 136 | }; 137 | 138 | const RSA = NativeModules.RNSCRsa; 139 | 140 | const utils = { 141 | randomBytes, 142 | convertArrayBufferToUtf8, 143 | convertUtf8ToArrayBuffer, 144 | convertArrayBufferToBase64, 145 | convertBase64ToArrayBuffer, 146 | convertArrayBufferToHex, 147 | convertHexToArrayBuffer 148 | }; 149 | 150 | export default { 151 | AES, 152 | SHA, 153 | HMAC, 154 | PBKDF2, 155 | RSA, 156 | utils 157 | }; 158 | -------------------------------------------------------------------------------- /ios/RNSCCrypto.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 48; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 42F12D9A21E7D98C00519322 /* RNSCRandomBytes.m in Sources */ = {isa = PBXBuildFile; fileRef = 42F12D9921E7D98C00519322 /* RNSCRandomBytes.m */; }; 11 | 9643DA86218A0E3800535D00 /* Sha.m in Sources */ = {isa = PBXBuildFile; fileRef = 9643DA84218A0E3800535D00 /* Sha.m */; }; 12 | 9643DA87218A0E3800535D00 /* Shared.m in Sources */ = {isa = PBXBuildFile; fileRef = 9643DA85218A0E3800535D00 /* Shared.m */; }; 13 | 9643DA8A218A0E4400535D00 /* RNSCSha.m in Sources */ = {isa = PBXBuildFile; fileRef = 9643DA89218A0E4400535D00 /* RNSCSha.m */; }; 14 | 9643DA8D218A5C4800535D00 /* RNSCHmac.m in Sources */ = {isa = PBXBuildFile; fileRef = 9643DA8C218A5C4800535D00 /* RNSCHmac.m */; }; 15 | 9643DA90218A5C5200535D00 /* Hmac.m in Sources */ = {isa = PBXBuildFile; fileRef = 9643DA8F218A5C5200535D00 /* Hmac.m */; }; 16 | 9643DA93218A65A900535D00 /* Pbkdf2.m in Sources */ = {isa = PBXBuildFile; fileRef = 9643DA92218A65A900535D00 /* Pbkdf2.m */; }; 17 | 9643DA96218A65B500535D00 /* RNSCPbkdf2.m in Sources */ = {isa = PBXBuildFile; fileRef = 9643DA94218A65B500535D00 /* RNSCPbkdf2.m */; }; 18 | 9643DA99218B779400535D00 /* RNSCRsa.m in Sources */ = {isa = PBXBuildFile; fileRef = 9643DA97218B779400535D00 /* RNSCRsa.m */; }; 19 | 9643DA9E218B77A200535D00 /* RsaFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = 9643DA9C218B77A200535D00 /* RsaFormatter.m */; }; 20 | 9643DA9F218B77A200535D00 /* Rsa.m in Sources */ = {isa = PBXBuildFile; fileRef = 9643DA9D218B77A200535D00 /* Rsa.m */; }; 21 | 9668CE0421471DE0001D58C3 /* Aes.m in Sources */ = {isa = PBXBuildFile; fileRef = 9668CE0221471DDF001D58C3 /* Aes.m */; }; 22 | 9668CE0721471DEA001D58C3 /* RNSCAes.m in Sources */ = {isa = PBXBuildFile; fileRef = 9668CE0621471DEA001D58C3 /* RNSCAes.m */; }; 23 | /* End PBXBuildFile section */ 24 | 25 | /* Begin PBXCopyFilesBuildPhase section */ 26 | 32D980DB1BE9F11C00FA27E5 /* CopyFiles */ = { 27 | isa = PBXCopyFilesBuildPhase; 28 | buildActionMask = 2147483647; 29 | dstPath = "include/$(PRODUCT_NAME)"; 30 | dstSubfolderSpec = 16; 31 | files = ( 32 | ); 33 | runOnlyForDeploymentPostprocessing = 0; 34 | }; 35 | /* End PBXCopyFilesBuildPhase section */ 36 | 37 | /* Begin PBXFileReference section */ 38 | 32D980DD1BE9F11C00FA27E5 /* libRNSCCrypto.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRNSCCrypto.a; sourceTree = BUILT_PRODUCTS_DIR; }; 39 | 42F12D9821E7D98C00519322 /* RNSCRandomBytes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNSCRandomBytes.h; sourceTree = ""; }; 40 | 42F12D9921E7D98C00519322 /* RNSCRandomBytes.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNSCRandomBytes.m; sourceTree = ""; }; 41 | 9643DA82218A0E3800535D00 /* Sha.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Sha.h; sourceTree = ""; }; 42 | 9643DA83218A0E3800535D00 /* Shared.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Shared.h; sourceTree = ""; }; 43 | 9643DA84218A0E3800535D00 /* Sha.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Sha.m; sourceTree = ""; }; 44 | 9643DA85218A0E3800535D00 /* Shared.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Shared.m; sourceTree = ""; }; 45 | 9643DA88218A0E4400535D00 /* RNSCSha.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNSCSha.h; sourceTree = ""; }; 46 | 9643DA89218A0E4400535D00 /* RNSCSha.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNSCSha.m; sourceTree = ""; }; 47 | 9643DA8B218A5C4800535D00 /* RNSCHmac.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNSCHmac.h; sourceTree = ""; }; 48 | 9643DA8C218A5C4800535D00 /* RNSCHmac.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNSCHmac.m; sourceTree = ""; }; 49 | 9643DA8E218A5C5200535D00 /* Hmac.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Hmac.h; sourceTree = ""; }; 50 | 9643DA8F218A5C5200535D00 /* Hmac.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Hmac.m; sourceTree = ""; }; 51 | 9643DA91218A65A900535D00 /* Pbkdf2.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Pbkdf2.h; sourceTree = ""; }; 52 | 9643DA92218A65A900535D00 /* Pbkdf2.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Pbkdf2.m; sourceTree = ""; }; 53 | 9643DA94218A65B500535D00 /* RNSCPbkdf2.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNSCPbkdf2.m; sourceTree = ""; }; 54 | 9643DA95218A65B500535D00 /* RNSCPbkdf2.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNSCPbkdf2.h; sourceTree = ""; }; 55 | 9643DA97218B779400535D00 /* RNSCRsa.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNSCRsa.m; sourceTree = ""; }; 56 | 9643DA98218B779400535D00 /* RNSCRsa.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNSCRsa.h; sourceTree = ""; }; 57 | 9643DA9A218B77A200535D00 /* RsaFormatter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RsaFormatter.h; sourceTree = ""; }; 58 | 9643DA9B218B77A200535D00 /* Rsa.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Rsa.h; sourceTree = ""; }; 59 | 9643DA9C218B77A200535D00 /* RsaFormatter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RsaFormatter.m; sourceTree = ""; }; 60 | 9643DA9D218B77A200535D00 /* Rsa.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Rsa.m; sourceTree = ""; }; 61 | 9668CE0221471DDF001D58C3 /* Aes.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Aes.m; sourceTree = ""; }; 62 | 9668CE0321471DDF001D58C3 /* Aes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Aes.h; sourceTree = ""; }; 63 | 9668CE0521471DEA001D58C3 /* RNSCAes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNSCAes.h; sourceTree = ""; }; 64 | 9668CE0621471DEA001D58C3 /* RNSCAes.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNSCAes.m; sourceTree = ""; }; 65 | /* End PBXFileReference section */ 66 | 67 | /* Begin PBXFrameworksBuildPhase section */ 68 | 32D980DA1BE9F11C00FA27E5 /* Frameworks */ = { 69 | isa = PBXFrameworksBuildPhase; 70 | buildActionMask = 2147483647; 71 | files = ( 72 | ); 73 | runOnlyForDeploymentPostprocessing = 0; 74 | }; 75 | /* End PBXFrameworksBuildPhase section */ 76 | 77 | /* Begin PBXGroup section */ 78 | 32D980D41BE9F11C00FA27E5 = { 79 | isa = PBXGroup; 80 | children = ( 81 | 32D980DF1BE9F11C00FA27E5 /* RNSCCrypto */, 82 | 32D980DE1BE9F11C00FA27E5 /* Products */, 83 | ); 84 | sourceTree = ""; 85 | }; 86 | 32D980DE1BE9F11C00FA27E5 /* Products */ = { 87 | isa = PBXGroup; 88 | children = ( 89 | 32D980DD1BE9F11C00FA27E5 /* libRNSCCrypto.a */, 90 | ); 91 | name = Products; 92 | sourceTree = ""; 93 | }; 94 | 32D980DF1BE9F11C00FA27E5 /* RNSCCrypto */ = { 95 | isa = PBXGroup; 96 | children = ( 97 | 9643DA98218B779400535D00 /* RNSCRsa.h */, 98 | 9643DA97218B779400535D00 /* RNSCRsa.m */, 99 | 9643DA95218A65B500535D00 /* RNSCPbkdf2.h */, 100 | 9643DA94218A65B500535D00 /* RNSCPbkdf2.m */, 101 | 9643DA8B218A5C4800535D00 /* RNSCHmac.h */, 102 | 9643DA8C218A5C4800535D00 /* RNSCHmac.m */, 103 | 9643DA88218A0E4400535D00 /* RNSCSha.h */, 104 | 9643DA89218A0E4400535D00 /* RNSCSha.m */, 105 | 9668CE0521471DEA001D58C3 /* RNSCAes.h */, 106 | 9668CE0621471DEA001D58C3 /* RNSCAes.m */, 107 | 42F12D9821E7D98C00519322 /* RNSCRandomBytes.h */, 108 | 42F12D9921E7D98C00519322 /* RNSCRandomBytes.m */, 109 | 32D981161BE9F1B600FA27E5 /* lib */, 110 | ); 111 | path = RNSCCrypto; 112 | sourceTree = ""; 113 | }; 114 | 32D981161BE9F1B600FA27E5 /* lib */ = { 115 | isa = PBXGroup; 116 | children = ( 117 | 9643DA9B218B77A200535D00 /* Rsa.h */, 118 | 9643DA9D218B77A200535D00 /* Rsa.m */, 119 | 9643DA9A218B77A200535D00 /* RsaFormatter.h */, 120 | 9643DA9C218B77A200535D00 /* RsaFormatter.m */, 121 | 9643DA91218A65A900535D00 /* Pbkdf2.h */, 122 | 9643DA92218A65A900535D00 /* Pbkdf2.m */, 123 | 9643DA8E218A5C5200535D00 /* Hmac.h */, 124 | 9643DA8F218A5C5200535D00 /* Hmac.m */, 125 | 9643DA82218A0E3800535D00 /* Sha.h */, 126 | 9643DA84218A0E3800535D00 /* Sha.m */, 127 | 9643DA83218A0E3800535D00 /* Shared.h */, 128 | 9643DA85218A0E3800535D00 /* Shared.m */, 129 | 9668CE0321471DDF001D58C3 /* Aes.h */, 130 | 9668CE0221471DDF001D58C3 /* Aes.m */, 131 | ); 132 | path = lib; 133 | sourceTree = ""; 134 | }; 135 | /* End PBXGroup section */ 136 | 137 | /* Begin PBXNativeTarget section */ 138 | 32D980DC1BE9F11C00FA27E5 /* RNSCCrypto */ = { 139 | isa = PBXNativeTarget; 140 | buildConfigurationList = 32D980F11BE9F11C00FA27E5 /* Build configuration list for PBXNativeTarget "RNSCCrypto" */; 141 | buildPhases = ( 142 | 32D980D91BE9F11C00FA27E5 /* Sources */, 143 | 32D980DA1BE9F11C00FA27E5 /* Frameworks */, 144 | 32D980DB1BE9F11C00FA27E5 /* CopyFiles */, 145 | ); 146 | buildRules = ( 147 | ); 148 | dependencies = ( 149 | ); 150 | name = RNSCCrypto; 151 | productName = RCTCrypto; 152 | productReference = 32D980DD1BE9F11C00FA27E5 /* libRNSCCrypto.a */; 153 | productType = "com.apple.product-type.library.static"; 154 | }; 155 | /* End PBXNativeTarget section */ 156 | 157 | /* Begin PBXProject section */ 158 | 32D980D51BE9F11C00FA27E5 /* Project object */ = { 159 | isa = PBXProject; 160 | attributes = { 161 | LastUpgradeCheck = 1140; 162 | ORGANIZATIONNAME = pedrouid; 163 | TargetAttributes = { 164 | 32D980DC1BE9F11C00FA27E5 = { 165 | CreatedOnToolsVersion = 6.4; 166 | }; 167 | }; 168 | }; 169 | buildConfigurationList = 32D980D81BE9F11C00FA27E5 /* Build configuration list for PBXProject "RNSCCrypto" */; 170 | compatibilityVersion = "Xcode 8.0"; 171 | developmentRegion = English; 172 | hasScannedForEncodings = 0; 173 | knownRegions = ( 174 | English, 175 | en, 176 | ); 177 | mainGroup = 32D980D41BE9F11C00FA27E5; 178 | productRefGroup = 32D980DE1BE9F11C00FA27E5 /* Products */; 179 | projectDirPath = ""; 180 | projectRoot = ""; 181 | targets = ( 182 | 32D980DC1BE9F11C00FA27E5 /* RNSCCrypto */, 183 | ); 184 | }; 185 | /* End PBXProject section */ 186 | 187 | /* Begin PBXSourcesBuildPhase section */ 188 | 32D980D91BE9F11C00FA27E5 /* Sources */ = { 189 | isa = PBXSourcesBuildPhase; 190 | buildActionMask = 2147483647; 191 | files = ( 192 | 9643DA8D218A5C4800535D00 /* RNSCHmac.m in Sources */, 193 | 9643DA86218A0E3800535D00 /* Sha.m in Sources */, 194 | 9643DA99218B779400535D00 /* RNSCRsa.m in Sources */, 195 | 9643DA8A218A0E4400535D00 /* RNSCSha.m in Sources */, 196 | 9668CE0721471DEA001D58C3 /* RNSCAes.m in Sources */, 197 | 9643DA93218A65A900535D00 /* Pbkdf2.m in Sources */, 198 | 9643DA9F218B77A200535D00 /* Rsa.m in Sources */, 199 | 9643DA96218A65B500535D00 /* RNSCPbkdf2.m in Sources */, 200 | 42F12D9A21E7D98C00519322 /* RNSCRandomBytes.m in Sources */, 201 | 9643DA90218A5C5200535D00 /* Hmac.m in Sources */, 202 | 9643DA9E218B77A200535D00 /* RsaFormatter.m in Sources */, 203 | 9643DA87218A0E3800535D00 /* Shared.m in Sources */, 204 | 9668CE0421471DE0001D58C3 /* Aes.m in Sources */, 205 | ); 206 | runOnlyForDeploymentPostprocessing = 0; 207 | }; 208 | /* End PBXSourcesBuildPhase section */ 209 | 210 | /* Begin XCBuildConfiguration section */ 211 | 32D980EF1BE9F11C00FA27E5 /* Debug */ = { 212 | isa = XCBuildConfiguration; 213 | buildSettings = { 214 | ALWAYS_SEARCH_USER_PATHS = NO; 215 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 216 | CLANG_CXX_LIBRARY = "libc++"; 217 | CLANG_ENABLE_MODULES = YES; 218 | CLANG_ENABLE_OBJC_ARC = YES; 219 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 220 | CLANG_WARN_BOOL_CONVERSION = YES; 221 | CLANG_WARN_COMMA = YES; 222 | CLANG_WARN_CONSTANT_CONVERSION = YES; 223 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 224 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 225 | CLANG_WARN_EMPTY_BODY = YES; 226 | CLANG_WARN_ENUM_CONVERSION = YES; 227 | CLANG_WARN_INFINITE_RECURSION = YES; 228 | CLANG_WARN_INT_CONVERSION = YES; 229 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 230 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 231 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 232 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 233 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 234 | CLANG_WARN_STRICT_PROTOTYPES = YES; 235 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 236 | CLANG_WARN_UNREACHABLE_CODE = YES; 237 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 238 | COPY_PHASE_STRIP = NO; 239 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 240 | ENABLE_STRICT_OBJC_MSGSEND = YES; 241 | ENABLE_TESTABILITY = YES; 242 | GCC_C_LANGUAGE_STANDARD = gnu99; 243 | GCC_DYNAMIC_NO_PIC = NO; 244 | GCC_NO_COMMON_BLOCKS = YES; 245 | GCC_OPTIMIZATION_LEVEL = 0; 246 | GCC_PREPROCESSOR_DEFINITIONS = ( 247 | "DEBUG=1", 248 | "$(inherited)", 249 | ); 250 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 251 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 252 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 253 | GCC_WARN_UNDECLARED_SELECTOR = YES; 254 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 255 | GCC_WARN_UNUSED_FUNCTION = YES; 256 | GCC_WARN_UNUSED_VARIABLE = YES; 257 | IPHONEOS_DEPLOYMENT_TARGET = 10.0; 258 | MTL_ENABLE_DEBUG_INFO = YES; 259 | ONLY_ACTIVE_ARCH = YES; 260 | SDKROOT = iphoneos; 261 | }; 262 | name = Debug; 263 | }; 264 | 32D980F01BE9F11C00FA27E5 /* Release */ = { 265 | isa = XCBuildConfiguration; 266 | buildSettings = { 267 | ALWAYS_SEARCH_USER_PATHS = NO; 268 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 269 | CLANG_CXX_LIBRARY = "libc++"; 270 | CLANG_ENABLE_MODULES = YES; 271 | CLANG_ENABLE_OBJC_ARC = YES; 272 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 273 | CLANG_WARN_BOOL_CONVERSION = YES; 274 | CLANG_WARN_COMMA = YES; 275 | CLANG_WARN_CONSTANT_CONVERSION = YES; 276 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 277 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 278 | CLANG_WARN_EMPTY_BODY = YES; 279 | CLANG_WARN_ENUM_CONVERSION = YES; 280 | CLANG_WARN_INFINITE_RECURSION = YES; 281 | CLANG_WARN_INT_CONVERSION = YES; 282 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 283 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 284 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 285 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 286 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 287 | CLANG_WARN_STRICT_PROTOTYPES = YES; 288 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 289 | CLANG_WARN_UNREACHABLE_CODE = YES; 290 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 291 | COPY_PHASE_STRIP = NO; 292 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 293 | ENABLE_NS_ASSERTIONS = NO; 294 | ENABLE_STRICT_OBJC_MSGSEND = YES; 295 | GCC_C_LANGUAGE_STANDARD = gnu99; 296 | GCC_NO_COMMON_BLOCKS = YES; 297 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 298 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 299 | GCC_WARN_UNDECLARED_SELECTOR = YES; 300 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 301 | GCC_WARN_UNUSED_FUNCTION = YES; 302 | GCC_WARN_UNUSED_VARIABLE = YES; 303 | IPHONEOS_DEPLOYMENT_TARGET = 10.0; 304 | MTL_ENABLE_DEBUG_INFO = NO; 305 | SDKROOT = iphoneos; 306 | VALIDATE_PRODUCT = YES; 307 | }; 308 | name = Release; 309 | }; 310 | 32D980F21BE9F11C00FA27E5 /* Debug */ = { 311 | isa = XCBuildConfiguration; 312 | buildSettings = { 313 | HEADER_SEARCH_PATHS = ( 314 | "$(inherited)", 315 | /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, 316 | "$(SRCROOT)/../../../react-native/React/**", 317 | "$(SRCROOT)/../../../../../node_modules/react-native/React/**", 318 | ); 319 | OTHER_LDFLAGS = "-ObjC"; 320 | PRODUCT_NAME = "$(TARGET_NAME)"; 321 | SKIP_INSTALL = YES; 322 | }; 323 | name = Debug; 324 | }; 325 | 32D980F31BE9F11C00FA27E5 /* Release */ = { 326 | isa = XCBuildConfiguration; 327 | buildSettings = { 328 | HEADER_SEARCH_PATHS = ( 329 | "$(inherited)", 330 | /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, 331 | "$(SRCROOT)/../../../react-native/React/**", 332 | "$(SRCROOT)/../../../../../node_modules/react-native/React/**", 333 | ); 334 | OTHER_LDFLAGS = "-ObjC"; 335 | PRODUCT_NAME = "$(TARGET_NAME)"; 336 | SKIP_INSTALL = YES; 337 | }; 338 | name = Release; 339 | }; 340 | /* End XCBuildConfiguration section */ 341 | 342 | /* Begin XCConfigurationList section */ 343 | 32D980D81BE9F11C00FA27E5 /* Build configuration list for PBXProject "RNSCCrypto" */ = { 344 | isa = XCConfigurationList; 345 | buildConfigurations = ( 346 | 32D980EF1BE9F11C00FA27E5 /* Debug */, 347 | 32D980F01BE9F11C00FA27E5 /* Release */, 348 | ); 349 | defaultConfigurationIsVisible = 0; 350 | defaultConfigurationName = Release; 351 | }; 352 | 32D980F11BE9F11C00FA27E5 /* Build configuration list for PBXNativeTarget "RNSCCrypto" */ = { 353 | isa = XCConfigurationList; 354 | buildConfigurations = ( 355 | 32D980F21BE9F11C00FA27E5 /* Debug */, 356 | 32D980F31BE9F11C00FA27E5 /* Release */, 357 | ); 358 | defaultConfigurationIsVisible = 0; 359 | defaultConfigurationName = Release; 360 | }; 361 | /* End XCConfigurationList section */ 362 | }; 363 | rootObject = 32D980D51BE9F11C00FA27E5 /* Project object */; 364 | } 365 | -------------------------------------------------------------------------------- /ios/RNSCCrypto.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ios/RNSCCrypto.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/RNSCCrypto/RNSCAes.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface RNSCAes : NSObject 4 | 5 | @end 6 | -------------------------------------------------------------------------------- /ios/RNSCCrypto/RNSCAes.m: -------------------------------------------------------------------------------- 1 | #import "RNSCAes.h" 2 | #import "Aes.h" 3 | 4 | @implementation RNSCAes 5 | 6 | RCT_EXPORT_MODULE() 7 | 8 | RCT_EXPORT_METHOD(encrypt:(NSString *)dataBase64 key:(NSString *)key iv:(NSString *)iv 9 | resolver:(RCTPromiseResolveBlock)resolve 10 | rejecter:(RCTPromiseRejectBlock)reject) { 11 | NSError *error = nil; 12 | NSString *base64 = [Aes encrypt:dataBase64 key:key iv:iv]; 13 | if (base64 == nil) { 14 | reject(@"encrypt_fail", @"Encrypt error", error); 15 | } else { 16 | resolve(base64); 17 | } 18 | } 19 | 20 | RCT_EXPORT_METHOD(decrypt:(NSString *)base64 key:(NSString *)key iv:(NSString *)iv 21 | resolver:(RCTPromiseResolveBlock)resolve 22 | rejecter:(RCTPromiseRejectBlock)reject) { 23 | NSError *error = nil; 24 | NSString *data = [Aes decrypt:base64 key:key iv:iv]; 25 | if (data == nil) { 26 | reject(@"decrypt_fail", @"Decrypt failed", error); 27 | } else { 28 | resolve(data); 29 | } 30 | } 31 | 32 | @end 33 | -------------------------------------------------------------------------------- /ios/RNSCCrypto/RNSCHmac.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface RNSCHmac : NSObject 4 | 5 | @end 6 | -------------------------------------------------------------------------------- /ios/RNSCCrypto/RNSCHmac.m: -------------------------------------------------------------------------------- 1 | #import "RNSCHmac.h" 2 | #import "Hmac.h" 3 | 4 | @implementation RNSCHmac 5 | 6 | RCT_EXPORT_MODULE() 7 | 8 | RCT_EXPORT_METHOD(hmac256:(NSString *)base64 key:(NSString *)key 9 | resolver:(RCTPromiseResolveBlock)resolve 10 | rejecter:(RCTPromiseRejectBlock)reject) { 11 | NSError *error = nil; 12 | NSString *data = [Hmac hmac256:base64 key:key]; 13 | if (data == nil) { 14 | reject(@"hmac_fail", @"HMAC error", error); 15 | } else { 16 | resolve(data); 17 | } 18 | } 19 | @end 20 | -------------------------------------------------------------------------------- /ios/RNSCCrypto/RNSCPbkdf2.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface RNSCPbkdf2 : NSObject 4 | 5 | @end 6 | -------------------------------------------------------------------------------- /ios/RNSCCrypto/RNSCPbkdf2.m: -------------------------------------------------------------------------------- 1 | #import "RNSCPbkdf2.h" 2 | #import "lib/Pbkdf2.h" 3 | 4 | @implementation RNSCPbkdf2 5 | 6 | RCT_EXPORT_MODULE() 7 | 8 | RCT_EXPORT_METHOD(hash:(NSString *)password 9 | salt:(NSString *)salt 10 | iterations:(int)iterations 11 | keyLen:(int)keyLen 12 | algorithm:(NSString *)algorithm 13 | resolver:(RCTPromiseResolveBlock)resolve 14 | rejecter:(RCTPromiseRejectBlock)reject) { 15 | NSError *error = nil; 16 | NSString *data = [Pbkdf2 hash:password salt:salt iterations:iterations keyLen:keyLen algorithm:algorithm]; 17 | if (data == nil) { 18 | reject(@"keygen_fail", @"Key generation failed", error); 19 | } else { 20 | resolve(data); 21 | } 22 | } 23 | @end 24 | -------------------------------------------------------------------------------- /ios/RNSCCrypto/RNSCRandomBytes.h: -------------------------------------------------------------------------------- 1 | // 2 | // RNSCRandomBytes.h 3 | // randombytes 4 | // 5 | // Created by Mark Vayngrib on 10/13/15. 6 | // Copyright (c) 2015 Facebook. All rights reserved. 7 | // 8 | 9 | #import 10 | #if __has_include() 11 | #import 12 | #elif __has_include("RCTBridgeModule.h") 13 | #import "RCTBridgeModule.h" 14 | #else 15 | #import "React/RCTBridgeModule.h" // Required when used as a Pod in a Swift project 16 | #endif 17 | 18 | 19 | @interface RNSCRandomBytes : NSObject 20 | 21 | @end 22 | -------------------------------------------------------------------------------- /ios/RNSCCrypto/RNSCRandomBytes.m: -------------------------------------------------------------------------------- 1 | // 2 | // RNRandom.m 3 | // randombytes 4 | // 5 | // Created by Mark Vayngrib on 10/13/15. 6 | // Copyright (c) 2015 Facebook. All rights reserved. 7 | // 8 | 9 | #import "RNSCRandomBytes.h" 10 | #if __has_include() 11 | #import 12 | #elif __has_include("RCTBridgeModule.h") 13 | #import "RCTBridgeModule.h" 14 | #else 15 | #import "React/RCTBridgeModule.h" // Required when used as a Pod in a Swift project 16 | #endif 17 | 18 | @implementation RNSCRandomBytes 19 | 20 | RCT_EXPORT_MODULE() 21 | 22 | @synthesize bridge = _bridge; 23 | 24 | RCT_EXPORT_METHOD(randomBytes:(NSUInteger)length 25 | resolver:(RCTPromiseResolveBlock)resolve 26 | rejecter:(RCTPromiseRejectBlock)reject) 27 | { 28 | NSError *error = nil; 29 | NSString *base64 = [RNSCRandomBytes randomBytes:length]; 30 | if (base64 == nil) { 31 | reject(@"random_bytes failed", @"Random bytes error", error); 32 | } else { 33 | resolve(base64); 34 | } 35 | } 36 | 37 | + (NSString *) randomBytes:(NSUInteger)length 38 | { 39 | NSMutableData* bytes = [NSMutableData dataWithLength:length]; 40 | SecRandomCopyBytes(kSecRandomDefault, length, [bytes mutableBytes]); 41 | return [bytes base64EncodedStringWithOptions:0]; 42 | } 43 | 44 | + (NSDictionary *)constantsToExport 45 | { 46 | return @{ 47 | @"seed": [RNSCRandomBytes randomBytes:4096] 48 | }; 49 | }; 50 | 51 | + (BOOL)requiresMainQueueSetup { 52 | return YES; 53 | } 54 | 55 | @end 56 | -------------------------------------------------------------------------------- /ios/RNSCCrypto/RNSCRsa.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface RNSCRsa : NSObject 4 | 5 | @end 6 | -------------------------------------------------------------------------------- /ios/RNSCCrypto/RNSCRsa.m: -------------------------------------------------------------------------------- 1 | #import "RNSCRsa.h" 2 | #import "Rsa.h" 3 | 4 | @interface RNSCRsa() 5 | + (SecKeyAlgorithm)getAlgorithmFromHash:(NSString *)hash; 6 | @end 7 | 8 | @implementation RNSCRsa 9 | 10 | - (dispatch_queue_t)methodQueue { 11 | return dispatch_get_main_queue(); 12 | } 13 | 14 | 15 | + (SecKeyAlgorithm)getAlgorithmFromHash:(NSString *)hash { 16 | if ([hash isEqualToString:@"Raw"]) { 17 | return kSecKeyAlgorithmRSASignatureDigestPKCS1v15Raw; 18 | } else if ([hash isEqualToString:@"SHA1"]) { 19 | return kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA1; 20 | } else if ([hash isEqualToString:@"SHA224"]) { 21 | return kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA224; 22 | } else if ([hash isEqualToString:@"SHA256"]) { 23 | return kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA256; 24 | } else if ([hash isEqualToString:@"SHA384"]) { 25 | return kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA384; 26 | } else if ([hash isEqualToString:@"SHA512"]) { 27 | return kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA512; 28 | } else { 29 | return kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA512; 30 | } 31 | } 32 | 33 | RCT_EXPORT_MODULE() 34 | 35 | // Key based API, provide the public or private key with each call - pending discussions with @amitaymolko 36 | 37 | RCT_EXPORT_METHOD(generate:(RCTPromiseResolveBlock)resolve 38 | rejecter:(RCTPromiseRejectBlock)reject) { 39 | [self generateKeys:2048 resolve:resolve rejecter:reject]; 40 | } 41 | 42 | RCT_EXPORT_METHOD(generateKeys:(int)keySize resolve:(RCTPromiseResolveBlock)resolve 43 | rejecter:(RCTPromiseRejectBlock)reject) { 44 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 45 | Rsa *rsa = [[Rsa alloc] init]; 46 | [rsa generate:keySize]; 47 | NSDictionary *keys = @{ 48 | @"private" : [rsa encodedPrivateKey], 49 | @"public" : [rsa encodedPublicKey] 50 | }; 51 | resolve(keys); 52 | }); 53 | } 54 | 55 | RCT_EXPORT_METHOD(encrypt:(NSString *)message withKey:(NSString *)key resolve:(RCTPromiseResolveBlock)resolve 56 | rejecter:(RCTPromiseRejectBlock)reject) { 57 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 58 | Rsa *rsa = [[Rsa alloc] init]; 59 | rsa.publicKey = key; 60 | NSString *encodedMessage = [rsa encrypt:message]; 61 | resolve(encodedMessage); 62 | }); 63 | } 64 | 65 | RCT_EXPORT_METHOD(decrypt:(NSString *)encodedMessage withKey:(NSString *)key resolve:(RCTPromiseResolveBlock)resolve 66 | rejecter:(RCTPromiseRejectBlock)reject) { 67 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 68 | Rsa *rsa = [[Rsa alloc] init]; 69 | rsa.privateKey = key; 70 | NSString *message = [rsa decrypt:encodedMessage]; 71 | resolve(message); 72 | }); 73 | } 74 | 75 | RCT_EXPORT_METHOD(encrypt64:(NSString *)message withKey:(NSString *)key resolve:(RCTPromiseResolveBlock)resolve 76 | rejecter:(RCTPromiseRejectBlock)reject) { 77 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 78 | Rsa *rsa = [[Rsa alloc] init]; 79 | rsa.publicKey = key; 80 | NSString *encodedMessage = [rsa encrypt64:message]; 81 | resolve(encodedMessage); 82 | }); 83 | } 84 | 85 | RCT_EXPORT_METHOD(decrypt64:(NSString *)encodedMessage withKey:(NSString *)key resolve:(RCTPromiseResolveBlock)resolve 86 | rejecter:(RCTPromiseRejectBlock)reject) { 87 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 88 | Rsa *rsa = [[Rsa alloc] init]; 89 | rsa.privateKey = key; 90 | NSString *message = [rsa decrypt64:encodedMessage]; 91 | resolve(message); 92 | }); 93 | } 94 | 95 | 96 | RCT_EXPORT_METHOD(sign:(NSString *)message withKey:(NSString *)key andHash:(NSString *)hash resolve:(RCTPromiseResolveBlock)resolve 97 | rejecter:(RCTPromiseRejectBlock)reject) { 98 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 99 | NSError *error = nil; 100 | Rsa *rsa = [[Rsa alloc] init]; 101 | rsa.privateKey = key; 102 | NSString *signature = [rsa sign:message withAlgorithm:[RNSCRsa getAlgorithmFromHash:hash] andError:&error]; 103 | if (error != nil) { 104 | reject(@"error", error.localizedDescription, error); 105 | } else { 106 | resolve(signature); 107 | } 108 | }); 109 | } 110 | 111 | RCT_EXPORT_METHOD(sign64:(NSString *)message withKey:(NSString *)key andHash:(NSString *)hash resolve:(RCTPromiseResolveBlock)resolve 112 | rejecter:(RCTPromiseRejectBlock)reject) { 113 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 114 | NSError *error = nil; 115 | Rsa *rsa = [[Rsa alloc] init]; 116 | rsa.privateKey = key; 117 | NSString *signature = [rsa sign64:message withAlgorithm:[RNSCRsa getAlgorithmFromHash:hash] andError:&error]; 118 | if (error != nil) { 119 | reject(@"error", error.localizedDescription, error); 120 | } else { 121 | resolve(signature); 122 | } 123 | }); 124 | } 125 | 126 | RCT_EXPORT_METHOD(verify:(NSString *)signature withMessage:(NSString *)message andKey:(NSString *)key andHash:(NSString *)hash resolve:(RCTPromiseResolveBlock)resolve 127 | rejecter:(RCTPromiseRejectBlock)reject) { 128 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 129 | Rsa *rsa = [[Rsa alloc] init]; 130 | rsa.publicKey = key; 131 | BOOL valid = [rsa verify:signature withMessage:message andAlgorithm:[RNSCRsa getAlgorithmFromHash:hash]]; 132 | resolve(@(valid)); 133 | }); 134 | } 135 | 136 | RCT_EXPORT_METHOD(verify64:(NSString *)signature withMessage:(NSString *)message andKey:(NSString *)key andHash:(NSString *)hash resolve:(RCTPromiseResolveBlock)resolve 137 | rejecter:(RCTPromiseRejectBlock)reject) { 138 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 139 | Rsa *rsa = [[Rsa alloc] init]; 140 | rsa.publicKey = key; 141 | BOOL valid = [rsa verify64:signature withMessage:message andAlgorithm:[RNSCRsa getAlgorithmFromHash:hash]]; 142 | resolve(@(valid)); 143 | }); 144 | } 145 | 146 | @end 147 | -------------------------------------------------------------------------------- /ios/RNSCCrypto/RNSCSha.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface RNSCSha : NSObject 4 | 5 | @end 6 | -------------------------------------------------------------------------------- /ios/RNSCCrypto/RNSCSha.m: -------------------------------------------------------------------------------- 1 | #import "RNSCSha.h" 2 | #import "Sha.h" 3 | 4 | @implementation RNSCSha 5 | 6 | RCT_EXPORT_MODULE() 7 | 8 | RCT_EXPORT_METHOD(shaBase64:(NSString *)text :(NSString *)algorithm 9 | resolver:(RCTPromiseResolveBlock)resolve 10 | rejecter:(RCTPromiseRejectBlock)reject) { 11 | NSError *error = nil; 12 | NSString *data = [Sha shaBase64:text :algorithm]; 13 | if (data == nil) { 14 | reject(@"shaBase64_fail", @"Hash error", error); 15 | } else { 16 | resolve(data); 17 | } 18 | } 19 | 20 | RCT_EXPORT_METHOD(shaUtf8:(NSString *)text :(NSString *)algorithm 21 | resolver:(RCTPromiseResolveBlock)resolve 22 | rejecter:(RCTPromiseRejectBlock)reject) { 23 | NSError *error = nil; 24 | NSString *data = [Sha shaUtf8:text :algorithm]; 25 | if (data == nil) { 26 | reject(@"shaUtf8_fail", @"Hash error", error); 27 | } else { 28 | resolve(data); 29 | } 30 | } 31 | 32 | @end 33 | -------------------------------------------------------------------------------- /ios/RNSCCrypto/lib/Aes.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface Aes : NSObject 4 | + (NSString *) encrypt: (NSString *)clearText64 key: (NSString *)key iv: (NSString *)iv; 5 | + (NSString *) decrypt: (NSString *)cipherText key: (NSString *)key iv: (NSString *)iv; 6 | @end 7 | -------------------------------------------------------------------------------- /ios/RNSCCrypto/lib/Aes.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | #import 4 | 5 | #import "Shared.h" 6 | #import "Aes.h" 7 | 8 | @implementation Aes 9 | 10 | + (NSData *) AES128CBC: (NSString *)operation data: (NSData *)data key: (NSString *)key iv: (NSString *)iv { 11 | // Convert hex string to hex data. 12 | NSData *keyData = [Shared fromHex:key]; 13 | NSData *ivData = [Shared fromHex:iv]; 14 | size_t numBytes = 0; 15 | NSMutableData *buffer = [[NSMutableData alloc] initWithLength:[data length] + kCCBlockSizeAES128]; 16 | 17 | CCCryptorStatus cryptStatus = CCCrypt( 18 | [operation isEqualToString:@"encrypt"] ? kCCEncrypt : kCCDecrypt, 19 | kCCAlgorithmAES128, 20 | kCCOptionPKCS7Padding, 21 | keyData.bytes, 22 | keyData.length, 23 | ivData.bytes, 24 | data.bytes, data.length, 25 | buffer.mutableBytes, 26 | buffer.length, 27 | &numBytes); 28 | 29 | if (cryptStatus == kCCSuccess) { 30 | [buffer setLength:numBytes]; 31 | return buffer; 32 | } 33 | NSLog(@"AES error, %d", cryptStatus); 34 | return nil; 35 | } 36 | 37 | + (NSString *) encrypt: (NSString *)clearText64 key: (NSString *)key iv: (NSString *)iv { 38 | NSData* clearData = [[NSData alloc] initWithBase64EncodedString:clearText64 options:0]; 39 | NSData *result = [self AES128CBC:@"encrypt" data:clearData key:key iv:iv]; 40 | return [result base64EncodedStringWithOptions:0]; 41 | } 42 | 43 | + (NSString *) decrypt: (NSString *)cipherText key: (NSString *)key iv: (NSString *)iv { 44 | NSData *result = [self AES128CBC:@"decrypt" data:[[NSData alloc] initWithBase64EncodedString:cipherText options:0] key:key iv:iv]; 45 | return [result base64EncodedStringWithOptions:0]; 46 | } 47 | 48 | @end 49 | -------------------------------------------------------------------------------- /ios/RNSCCrypto/lib/Hmac.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface Hmac : NSObject 4 | + (NSString *) hmac256: (NSString *)input key: (NSString *)key; 5 | @end 6 | -------------------------------------------------------------------------------- /ios/RNSCCrypto/lib/Hmac.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | #import "Shared.h" 5 | #import "Hmac.h" 6 | 7 | @implementation Hmac 8 | 9 | + (NSString *) hmac256: (NSString *)input key: (NSString *)key { 10 | NSData *keyData = [Shared fromHex:key]; 11 | NSData* inputData = [Shared fromHex:input]; 12 | void* buffer = malloc(CC_SHA256_DIGEST_LENGTH); 13 | CCHmac(kCCHmacAlgSHA256, [keyData bytes], [keyData length], [inputData bytes], [inputData length], buffer); 14 | NSData *nsdata = [NSData dataWithBytesNoCopy:buffer length:CC_SHA256_DIGEST_LENGTH freeWhenDone:YES]; 15 | return [Shared toHex:nsdata]; 16 | } 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /ios/RNSCCrypto/lib/Pbkdf2.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface Pbkdf2 : NSObject 4 | + (NSString *) hash:(NSString *)password salt: (NSString *)salt iterations: (int)iterations keyLen: (int)keyLen algorithm: (NSString *)algorithm; 5 | @end 6 | -------------------------------------------------------------------------------- /ios/RNSCCrypto/lib/Pbkdf2.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | #import 4 | 5 | #import "Shared.h" 6 | #import "Pbkdf2.h" 7 | 8 | @implementation Pbkdf2 9 | 10 | + (NSString *) hash:(NSString *)password salt: (NSString *)salt iterations: (int)iterations keyLen: (int)keyLen algorithm: (NSString *)algorithm { 11 | // Data of String to generate Hash key(hexa decimal string). 12 | NSData *passwordData = [[NSData alloc]initWithBase64EncodedString:password options:0]; 13 | NSData *saltData = [[NSData alloc]initWithBase64EncodedString:salt options:0]; 14 | 15 | // Hash key (hexa decimal) string data length. 16 | NSMutableData *hashKeyData = [NSMutableData dataWithLength:keyLen]; 17 | 18 | NSDictionary *algMap = @{ 19 | @"SHA1" : [NSNumber numberWithInt:kCCPRFHmacAlgSHA1], 20 | @"SHA224" : [NSNumber numberWithInt:kCCPRFHmacAlgSHA224], 21 | @"SHA256" : [NSNumber numberWithInt:kCCPRFHmacAlgSHA256], 22 | @"SHA384" : [NSNumber numberWithInt:kCCPRFHmacAlgSHA384], 23 | @"SHA512" : [NSNumber numberWithInt:kCCPRFHmacAlgSHA512], 24 | }; 25 | 26 | int alg = [[algMap valueForKey:algorithm] intValue]; 27 | 28 | // Key Derivation using PBKDF2 algorithm. 29 | int status = CCKeyDerivationPBKDF( 30 | kCCPBKDF2, 31 | passwordData.bytes, 32 | passwordData.length, 33 | saltData.bytes, 34 | saltData.length, 35 | alg, 36 | iterations, 37 | hashKeyData.mutableBytes, 38 | hashKeyData.length); 39 | 40 | if (status == kCCParamError) { 41 | NSLog(@"Key derivation error"); 42 | return @""; 43 | } 44 | 45 | return [hashKeyData base64EncodedStringWithOptions:0]; 46 | } 47 | 48 | @end 49 | -------------------------------------------------------------------------------- /ios/RNSCCrypto/lib/Rsa.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface Rsa : NSObject 4 | 5 | @property (nonatomic) NSString *publicKey; 6 | @property (nonatomic) NSString *privateKey; 7 | 8 | - (void)generate:(int)keySize; 9 | - (void)deletePrivateKey; 10 | 11 | - (NSString *)encodedPublicKey; 12 | - (NSString *)encodedPrivateKey; 13 | 14 | - (NSString *)encrypt:(NSString *)message; 15 | - (NSString *)decrypt:(NSString *)encodedMessage; 16 | 17 | - (NSString *)encrypt64:(NSString *)message; 18 | - (NSString *)decrypt64:(NSString *)encodedMessage; 19 | 20 | - (NSData *)_encrypt:(NSData *)message; 21 | - (NSData *)_decrypt:(NSData *)encodedMessage; 22 | 23 | - (NSString *)sign:(NSString *)message withAlgorithm:(SecKeyAlgorithm)algorithm andError:(NSError **)anError; 24 | - (BOOL)verify:(NSString *)signature withMessage:(NSString *)message andAlgorithm:(SecKeyAlgorithm)algorithm; 25 | 26 | - (NSString *)sign64:(NSString *)b64message withAlgorithm:(SecKeyAlgorithm)algorithm andError:(NSError **)anError; 27 | - (BOOL)verify64:(NSString *)signature withMessage:(NSString *)b64message andAlgorithm:(SecKeyAlgorithm)algorithm; 28 | 29 | - (NSString *)_sign:(NSData *)messageBytes withAlgorithm:(SecKeyAlgorithm)algorithm andError:(NSError**)anError; 30 | - (BOOL)_verify:(NSData *)signatureBytes withMessage:(NSData *)messageBytes andAlgorithm:(SecKeyAlgorithm)algorithm; 31 | 32 | - (NSUInteger)getKeyLength; 33 | @end -------------------------------------------------------------------------------- /ios/RNSCCrypto/lib/Rsa.m: -------------------------------------------------------------------------------- 1 | #import "Rsa.h" 2 | #import "RsaFormatter.h" 3 | 4 | typedef void (^SecKeyPerformBlock)(SecKeyRef key); 5 | 6 | @interface Rsa () 7 | @property (nonatomic) SecKeyRef publicKeyRef; 8 | @property (nonatomic) SecKeyRef privateKeyRef; 9 | @end 10 | 11 | @implementation Rsa 12 | 13 | - (void)generate:(int)keySize { 14 | NSMutableDictionary *privateKeyAttributes = [NSMutableDictionary dictionary]; 15 | 16 | NSMutableDictionary *attributes = [[NSMutableDictionary alloc] init]; 17 | [attributes setObject:(__bridge id)kSecAttrKeyTypeRSA forKey:(__bridge id)kSecAttrKeyType]; 18 | [attributes setObject:[NSNumber numberWithInt:keySize] forKey:(__bridge id)kSecAttrKeySizeInBits]; 19 | [attributes setObject:privateKeyAttributes forKey:(__bridge id)kSecPrivateKeyAttrs]; 20 | 21 | CFErrorRef error = NULL; 22 | SecKeyRef privateKey = SecKeyCreateRandomKey((__bridge CFDictionaryRef)attributes, &error); 23 | 24 | if (!privateKey) { 25 | NSError *err = CFBridgingRelease(error); 26 | NSLog(@"%@", err); 27 | } 28 | 29 | _privateKeyRef = privateKey; 30 | _publicKeyRef = SecKeyCopyPublicKey(privateKey); 31 | } 32 | 33 | - (void)deletePrivateKey { 34 | self.privateKey = nil; 35 | } 36 | 37 | - (NSString *)encodedPublicKey { 38 | return [self externalRepresentationForPublicKey:self.publicKeyRef]; 39 | } 40 | 41 | - (NSString *)encodedPrivateKey { 42 | return [self externalRepresentationForPrivateKey:self.privateKeyRef]; 43 | } 44 | 45 | - (void)setPublicKey:(NSString *)publicKey { 46 | publicKey = [RsaFormatter stripHeaders: publicKey]; 47 | NSDictionary* options = @{(id)kSecAttrKeyType: (id)kSecAttrKeyTypeRSA, 48 | (id)kSecAttrKeyClass: (id)kSecAttrKeyClassPublic, 49 | // (id)kSecAttrKeySizeInBits: @2048, 50 | }; 51 | CFErrorRef error = NULL; 52 | NSData *data = [[NSData alloc] initWithBase64EncodedString:publicKey options:NSDataBase64DecodingIgnoreUnknownCharacters]; 53 | SecKeyRef key = SecKeyCreateWithData((__bridge CFDataRef)data, 54 | (__bridge CFDictionaryRef)options, 55 | &error); 56 | if (!key) { 57 | NSError *err = CFBridgingRelease(error); 58 | NSLog(@"%@", err); 59 | } else { 60 | _publicKeyRef = key; 61 | } 62 | } 63 | 64 | - (void)setPrivateKey:(NSString *)privateKey { 65 | privateKey = [RsaFormatter stripHeaders: privateKey]; 66 | 67 | NSDictionary* options = @{(id)kSecAttrKeyType: (id)kSecAttrKeyTypeRSA, 68 | (id)kSecAttrKeyClass: (id)kSecAttrKeyClassPrivate, 69 | // (id)kSecAttrKeySizeInBits: @2048, 70 | }; 71 | CFErrorRef error = NULL; 72 | NSData *data = [[NSData alloc] initWithBase64EncodedString:privateKey options:NSDataBase64DecodingIgnoreUnknownCharacters]; 73 | SecKeyRef key = SecKeyCreateWithData((__bridge CFDataRef)data, 74 | (__bridge CFDictionaryRef)options, 75 | &error); 76 | if (!key) { 77 | NSError *err = CFBridgingRelease(error); 78 | NSLog(@"%@", err); 79 | } else { 80 | _privateKeyRef = key; 81 | } 82 | } 83 | 84 | - (NSString *)encrypt64:(NSString*)message { 85 | NSData *data = [[NSData alloc] initWithBase64EncodedString:message options:NSDataBase64DecodingIgnoreUnknownCharacters]; 86 | NSData *encrypted = [self _encrypt: data]; 87 | return [encrypted base64EncodedStringWithOptions:0]; 88 | } 89 | 90 | - (NSString *)encrypt:(NSString *)message { 91 | NSData *data = [message dataUsingEncoding:NSUTF8StringEncoding]; 92 | NSData *encrypted = [self _encrypt: data]; 93 | return [encrypted base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength]; 94 | } 95 | 96 | - (NSData *)_encrypt:(NSData *)data { 97 | __block NSData *cipherText = nil; 98 | 99 | void(^encryptor)(SecKeyRef) = ^(SecKeyRef publicKey) { 100 | BOOL canEncrypt = SecKeyIsAlgorithmSupported(publicKey, 101 | kSecKeyOperationTypeEncrypt, 102 | kSecKeyAlgorithmRSAEncryptionPKCS1); 103 | if (canEncrypt) { 104 | CFErrorRef error = NULL; 105 | cipherText = (NSData *)CFBridgingRelease(SecKeyCreateEncryptedData(publicKey, 106 | kSecKeyAlgorithmRSAEncryptionPKCS1, 107 | (__bridge CFDataRef)data, 108 | &error)); 109 | if (!cipherText) { 110 | NSError *err = CFBridgingRelease(error); 111 | NSLog(@"%@", err); 112 | } 113 | } 114 | }; 115 | 116 | encryptor(self.publicKeyRef); 117 | return cipherText; 118 | } 119 | 120 | - (NSString *)decrypt64:(NSString*)message { 121 | NSData *data = [[NSData alloc] initWithBase64EncodedString:message options:NSDataBase64DecodingIgnoreUnknownCharacters]; 122 | NSData *decrypted = [self _decrypt: data]; 123 | return [decrypted base64EncodedStringWithOptions:0]; 124 | } 125 | 126 | - (NSString *)decrypt:(NSString *)message { 127 | NSData *data = [[NSData alloc] initWithBase64EncodedString:message options:NSDataBase64DecodingIgnoreUnknownCharacters]; 128 | NSData *decrypted = [self _decrypt: data]; 129 | return [[NSString alloc] initWithData:decrypted encoding:NSUTF8StringEncoding]; 130 | } 131 | 132 | - (NSData *)_decrypt:(NSData *)data { 133 | __block NSData *clearText = nil; 134 | 135 | void(^decryptor)(SecKeyRef) = ^(SecKeyRef privateKey) { 136 | 137 | BOOL canDecrypt = SecKeyIsAlgorithmSupported(privateKey, 138 | kSecKeyOperationTypeDecrypt, 139 | kSecKeyAlgorithmRSAEncryptionPKCS1); 140 | if (canDecrypt) { 141 | CFErrorRef error = NULL; 142 | clearText = (NSData *)CFBridgingRelease(SecKeyCreateDecryptedData(privateKey, 143 | kSecKeyAlgorithmRSAEncryptionPKCS1, 144 | (__bridge CFDataRef)data, 145 | &error)); 146 | if (!clearText) { 147 | NSError *err = CFBridgingRelease(error); 148 | NSLog(@"%@", err); 149 | } 150 | } 151 | }; 152 | 153 | decryptor(self.privateKeyRef); 154 | return clearText; 155 | } 156 | 157 | - (NSString *)sign64:(NSString *)b64message withAlgorithm:(SecKeyAlgorithm)algorithm andError:(NSError **)anError { 158 | NSData *data = [[NSData alloc] initWithBase64EncodedString:b64message options:NSDataBase64DecodingIgnoreUnknownCharacters]; 159 | NSString *encodedSignature = [self _sign:data withAlgorithm:algorithm andError:anError]; 160 | return encodedSignature; 161 | } 162 | 163 | - (NSString *)sign:(NSString *)message withAlgorithm:(SecKeyAlgorithm)algorithm andError:(NSError **)anError { 164 | NSData* data = [message dataUsingEncoding:NSUTF8StringEncoding]; 165 | NSString *encodedSignature = [self _sign:data withAlgorithm:algorithm andError:anError]; 166 | return encodedSignature; 167 | } 168 | 169 | - (NSString *)_sign:(NSData *)messageBytes withAlgorithm:(SecKeyAlgorithm)algorithm andError:(NSError **)anError { 170 | __block NSString *encodedSignature = nil; 171 | 172 | if (algorithm == kSecKeyAlgorithmRSASignatureDigestPKCS1v15Raw && [self getKeyLength] < [messageBytes length]) { 173 | NSDictionary *errorDetail = @{ 174 | NSLocalizedDescriptionKey: [NSString stringWithFormat:@"sign: Message length %lu is bigger than key length %lu",(unsigned long)[messageBytes length], (unsigned long)[self getKeyLength]] 175 | }; 176 | *anError = [NSError errorWithDomain:@"react-native-simple-crypto" code:0 userInfo:errorDetail]; 177 | return nil; 178 | } 179 | 180 | 181 | void(^signer)(SecKeyRef) = ^(SecKeyRef privateKey) { 182 | BOOL canSign = SecKeyIsAlgorithmSupported(privateKey, 183 | kSecKeyOperationTypeSign, 184 | algorithm); 185 | 186 | NSData* signature = nil; 187 | 188 | if (canSign) { 189 | CFErrorRef error = NULL; 190 | signature = (NSData*)CFBridgingRelease(SecKeyCreateSignature(privateKey, 191 | algorithm, 192 | (__bridge CFDataRef)messageBytes, 193 | &error)); 194 | if (!signature) { 195 | *anError = CFBridgingRelease(error); 196 | NSLog(@"error: %@", *anError); 197 | } 198 | } 199 | 200 | encodedSignature = [signature base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength]; 201 | }; 202 | 203 | signer(self.privateKeyRef); 204 | if (*anError != nil) { 205 | return nil; 206 | } 207 | return encodedSignature; 208 | } 209 | 210 | - (BOOL)verify64:(NSString *)encodedSignature withMessage:(NSString *)b64message andAlgorithm:(SecKeyAlgorithm)algorithm { 211 | NSData *messageBytes = [[NSData alloc] initWithBase64EncodedString:b64message options:NSDataBase64DecodingIgnoreUnknownCharacters]; 212 | NSData *signatureBytes = [[NSData alloc] initWithBase64EncodedString:encodedSignature options:NSDataBase64DecodingIgnoreUnknownCharacters]; 213 | return [self _verify: signatureBytes withMessage: messageBytes andAlgorithm:algorithm]; 214 | } 215 | 216 | - (BOOL)verify:(NSString *)encodedSignature withMessage:(NSString *)message andAlgorithm:(SecKeyAlgorithm)algorithm { 217 | NSData *messageBytes = [message dataUsingEncoding:NSUTF8StringEncoding]; 218 | NSData *signatureBytes = [[NSData alloc] initWithBase64EncodedString:encodedSignature options:NSDataBase64DecodingIgnoreUnknownCharacters]; 219 | return [self _verify: signatureBytes withMessage: messageBytes andAlgorithm:algorithm]; 220 | } 221 | 222 | - (BOOL)_verify:(NSData *)signatureBytes withMessage:(NSData *)messageBytes andAlgorithm:(SecKeyAlgorithm)algorithm { 223 | __block BOOL result = NO; 224 | 225 | void(^verifier)(SecKeyRef) = ^(SecKeyRef publicKey) { 226 | BOOL canVerify = SecKeyIsAlgorithmSupported(publicKey, 227 | kSecKeyOperationTypeVerify, 228 | algorithm); 229 | 230 | if (canVerify) { 231 | CFErrorRef error = NULL; 232 | result = SecKeyVerifySignature(publicKey, 233 | algorithm, 234 | (__bridge CFDataRef)messageBytes, 235 | (__bridge CFDataRef)signatureBytes, 236 | &error); 237 | if (!result) { 238 | NSError *err = CFBridgingRelease(error); 239 | NSLog(@"error: %@", err); 240 | } 241 | } 242 | }; 243 | 244 | verifier(self.publicKeyRef); 245 | return result; 246 | } 247 | 248 | - (NSString *) externalRepresentationForPublicKey:(SecKeyRef)key { 249 | NSData *keyData = [self dataForKey:key]; 250 | return [RsaFormatter PEMFormattedPublicKey:keyData]; 251 | } 252 | 253 | - (NSString *) externalRepresentationForPrivateKey:(SecKeyRef)key { 254 | NSData *keyData = [self dataForKey:key]; 255 | return [RsaFormatter PEMFormattedPrivateKey:keyData]; 256 | } 257 | 258 | - (NSUInteger) getKeyLength { 259 | return SecKeyGetBlockSize(self.privateKeyRef); 260 | } 261 | 262 | - (NSData *)dataForKey:(SecKeyRef)key { 263 | CFErrorRef error = NULL; 264 | NSData * keyData = (NSData *)CFBridgingRelease(SecKeyCopyExternalRepresentation(key, &error)); 265 | 266 | if (!keyData) { 267 | NSError *err = CFBridgingRelease(error); 268 | NSLog(@"%@", err); 269 | } 270 | 271 | return keyData; 272 | } 273 | 274 | @end 275 | -------------------------------------------------------------------------------- /ios/RNSCCrypto/lib/RsaFormatter.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface RsaFormatter : NSObject 4 | + (NSString *)PEMFormattedPublicKey:(NSData *)publicKeyData; 5 | + (NSString *)PEMFormattedPrivateKey:(NSData *)privateKeyData; 6 | + (NSString *)stripHeaders:(NSString *)pemString; 7 | @end 8 | -------------------------------------------------------------------------------- /ios/RNSCCrypto/lib/RsaFormatter.m: -------------------------------------------------------------------------------- 1 | #import "RsaFormatter.h" 2 | 3 | @implementation RsaFormatter 4 | 5 | static NSString *publicTag = @"PUBLIC"; 6 | static NSString *privateTag = @"PRIVATE"; 7 | static NSString *publicRsaTag = @"RSA PUBLIC"; 8 | static NSString *privateRsaTag = @"RSA PRIVATE"; 9 | 10 | + (NSString *)PEMFormattedPublicKey:(NSData *)publicKeyData { 11 | NSMutableData * encodedKey = [[NSMutableData alloc] init]; 12 | [encodedKey appendData:publicKeyData]; 13 | return [self pemFormat:encodedKey tag:publicRsaTag]; 14 | } 15 | 16 | + (NSString *)PEMFormattedPrivateKey:(NSData *)privateKeyData { 17 | NSMutableData * encodedKey = [[NSMutableData alloc] init]; 18 | [encodedKey appendData:privateKeyData]; 19 | return [self pemFormat:encodedKey tag:privateRsaTag]; 20 | } 21 | 22 | + (NSString *)pemFormat:(NSData *)encodedKey tag:(NSString *)tag { 23 | return [NSString stringWithFormat:@"%@\n%@\n%@", 24 | [self headerForTag:tag], 25 | [encodedKey base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength], 26 | [self footerForTag:tag] 27 | ]; 28 | } 29 | 30 | + (NSString *)headerForTag:(NSString *)tag { 31 | return [NSString stringWithFormat:@"-----BEGIN %@ KEY-----", tag ]; 32 | } 33 | 34 | + (NSString *)footerForTag:(NSString *)tag { 35 | return [NSString stringWithFormat:@"-----END %@ KEY-----", tag]; 36 | } 37 | 38 | + (NSString *)stripHeaders:(NSString *)pemString { 39 | NSRange spos; 40 | NSRange epos; 41 | if ([pemString rangeOfString:[self headerForTag:privateRsaTag]].length > 0) { 42 | spos = [pemString rangeOfString:[self headerForTag:privateRsaTag]]; 43 | epos = [pemString rangeOfString:[self footerForTag:privateRsaTag]]; 44 | } else if ([pemString rangeOfString:[self headerForTag:publicRsaTag]].length > 0) { 45 | spos = [pemString rangeOfString:[self headerForTag:publicRsaTag]]; 46 | epos = [pemString rangeOfString:[self footerForTag:publicRsaTag]]; 47 | } else if ([pemString rangeOfString:[self headerForTag:privateTag]].length > 0) { 48 | spos = [pemString rangeOfString:[self headerForTag:privateTag]]; 49 | epos = [pemString rangeOfString:[self footerForTag:privateTag]]; 50 | } else if ([pemString rangeOfString:[self headerForTag:publicTag]].length > 0) { 51 | spos = [pemString rangeOfString:[self headerForTag:publicTag]]; 52 | epos = [pemString rangeOfString:[self footerForTag:publicTag]]; 53 | } 54 | 55 | if(spos.location != NSNotFound && epos.location != NSNotFound){ 56 | NSUInteger s = spos.location + spos.length; 57 | NSUInteger e = epos.location; 58 | NSRange range = NSMakeRange(s, e-s); 59 | pemString = [pemString substringWithRange:range]; 60 | } 61 | return pemString; 62 | } 63 | 64 | @end -------------------------------------------------------------------------------- /ios/RNSCCrypto/lib/Sha.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface Sha : NSObject 4 | + (NSData *) sha: (NSData *)input :(NSString *)type; 5 | + (NSString *) shaUtf8: (NSString *)input :(NSString *)type;; 6 | + (NSString *) shaBase64: (NSString *)input :(NSString *)type;; 7 | @end 8 | -------------------------------------------------------------------------------- /ios/RNSCCrypto/lib/Sha.m: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | #import "Shared.h" 4 | #import "Sha.h" 5 | 6 | @implementation Sha 7 | 8 | + (NSData *) sha: (NSData *)input :(NSString *)type { 9 | NSDictionary *algMap = @{ 10 | @"SHA-1" : [NSNumber numberWithInt:CC_SHA1_DIGEST_LENGTH], 11 | @"SHA-256" : [NSNumber numberWithInt:CC_SHA256_DIGEST_LENGTH], 12 | @"SHA-512" : [NSNumber numberWithInt:CC_SHA512_DIGEST_LENGTH], 13 | }; 14 | 15 | int digestLength = [[algMap valueForKey:type] intValue]; 16 | if (digestLength == 0) { 17 | [NSException raise:@"Invalid hash algorithm" format:@"%@ is not a valid hash algorithm", type]; 18 | } 19 | 20 | if (digestLength == CC_SHA1_DIGEST_LENGTH) { 21 | NSMutableData *result = [[NSMutableData alloc] initWithLength:CC_SHA1_DIGEST_LENGTH]; 22 | CC_SHA1([input bytes], (CC_LONG)[input length], result.mutableBytes); 23 | return result; 24 | } else { 25 | unsigned char* buffer = malloc(digestLength); 26 | if (digestLength == CC_SHA256_DIGEST_LENGTH) { 27 | CC_SHA256([input bytes], (CC_LONG)[input length], buffer); 28 | } else { 29 | CC_SHA512([input bytes], (CC_LONG)[input length], buffer); 30 | } 31 | return [NSData dataWithBytesNoCopy:buffer length:digestLength freeWhenDone:YES]; 32 | } 33 | } 34 | 35 | + (NSString *) shaUtf8: (NSString *)input :(NSString *)type { 36 | NSData* inputData = [input dataUsingEncoding:NSUTF8StringEncoding]; 37 | NSData* result = [self sha:inputData :type]; 38 | return [Shared toHex:result]; 39 | } 40 | 41 | + (NSString *) shaBase64: (NSString *)input :(NSString *)type { 42 | NSData* inputData = [[NSData alloc] initWithBase64EncodedString:input options:0]; 43 | NSData* result = [self sha:inputData :type]; 44 | return [result base64EncodedStringWithOptions:0]; 45 | } 46 | 47 | @end 48 | -------------------------------------------------------------------------------- /ios/RNSCCrypto/lib/Shared.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface Shared : NSObject 4 | + (NSString *) toHex: (NSData *)nsdata; 5 | + (NSData *) fromHex: (NSString *)string; 6 | @end 7 | -------------------------------------------------------------------------------- /ios/RNSCCrypto/lib/Shared.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | #import 4 | 5 | #import "Shared.h" 6 | 7 | @implementation Shared 8 | 9 | + (NSString *) toHex:(NSData *)nsdata { 10 | // Copied from: https://riptutorial.com/ios/example/18979/converting-nsdata-to-hex-string 11 | const unsigned char *bytes = (const unsigned char *)nsdata.bytes; 12 | NSMutableString *hex = [NSMutableString new]; 13 | for (NSInteger i = 0; i < nsdata.length; i++) { 14 | [hex appendFormat:@"%02x", bytes[i]]; 15 | } 16 | return [hex copy]; 17 | } 18 | 19 | + (NSData *) fromHex: (NSString *)string { 20 | NSMutableData *data = [[NSMutableData alloc] init]; 21 | unsigned char whole_byte; 22 | char byte_chars[3] = {'\0','\0','\0'}; 23 | for (int i = 0; i < ([string length] / 2); i++) { 24 | byte_chars[0] = [string characterAtIndex:i*2]; 25 | byte_chars[1] = [string characterAtIndex:i*2+1]; 26 | whole_byte = strtol(byte_chars, NULL, 16); 27 | [data appendBytes:&whole_byte length:1]; 28 | } 29 | return data; 30 | } 31 | 32 | @end 33 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-native-simple-crypto", 3 | "version": "0.2.15", 4 | "description": "A simpler React-Native crypto library", 5 | "main": "index.js", 6 | "author": "Gary Button ", 7 | "homepage": "https://github.com/ghbutton/react-native-simple-crypto", 8 | "license": "MIT", 9 | "keywords": [ 10 | "react-native", 11 | "react-component", 12 | "ios", 13 | "android", 14 | "aes", 15 | "crypto", 16 | "mobile", 17 | "async", 18 | "sha1", 19 | "sha256", 20 | "sha512", 21 | "pbkdf2", 22 | "hmac256", 23 | "rsa", 24 | "random", 25 | "randomBytes" 26 | ], 27 | "repository": { 28 | "type": "git", 29 | "url": "git+https://github.com/ghbutton/react-native-simple-crypto.git" 30 | }, 31 | "bugs": { 32 | "url": "https://github.com/ghbutton/react-native-simple-crypto/issues" 33 | }, 34 | "scripts": { 35 | "test": "echo \"Error: no test specified\" && exit 1" 36 | }, 37 | "dependencies": { 38 | "base64-js": "^1.3.0", 39 | "hex-lite": "^1.5.0" 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /react-native-simple-crypto.podspec: -------------------------------------------------------------------------------- 1 | require 'json' 2 | package_json = JSON.parse(File.read('package.json')) 3 | 4 | Pod::Spec.new do |s| 5 | s.name = package_json["name"] 6 | s.version = package_json["version"] 7 | s.summary = package_json["description"] 8 | s.author = package_json["author"] 9 | s.license = package_json["license"] 10 | s.requires_arc = true 11 | s.homepage = package_json["homepage"] 12 | s.source = { :git => "#{package_json["repository"]["url"]}" } 13 | s.platform = :ios, '8.0' 14 | s.source_files = "ios/**/*.{h,m}" 15 | 16 | s.dependency "React" 17 | end 18 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | base64-js@^1.3.0: 6 | version "1.3.0" 7 | resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.0.tgz#cab1e6118f051095e58b5281aea8c1cd22bfc0e3" 8 | integrity sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw== 9 | 10 | hex-lite@^1.5.0: 11 | version "1.5.0" 12 | resolved "https://registry.yarnpkg.com/hex-lite/-/hex-lite-1.5.0.tgz#482db64f673dcacdb8be93c629a799ce5a76b24d" 13 | integrity sha512-bXFMCFoKcksmJ1kDRq6B0+Go5Wgq84Dq/3rX99+0OzBQZKUBEMLguPd1lZSpvmzJACb516n07eyswF4KHAF9cg== 14 | --------------------------------------------------------------------------------