@icedevml/react-native-host-card-emulation 0.2.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -21
- package/README.md +17 -17
- package/RTNHCEModuleIOS.podspec +19 -19
- package/android/build.gradle +33 -33
- package/android/src/main/AndroidMainfest.xml +3 -3
- package/android/src/main/java/com/itsecrnd/rtnhceandroid/AESGCMUtil.java +89 -89
- package/android/src/main/java/com/itsecrnd/rtnhceandroid/BinaryUtils.java +65 -65
- package/android/src/main/java/com/itsecrnd/rtnhceandroid/HCEService.java +92 -92
- package/android/src/main/java/com/itsecrnd/rtnhceandroid/IntentKeys.java +6 -6
- package/android/src/main/java/com/itsecrnd/rtnhceandroid/RTNHCEAndroidModule.java +148 -148
- package/android/src/main/java/com/itsecrnd/rtnhceandroid/RTNHCEAndroidPackage.java +47 -47
- package/ios/RTNHCEModuleIOS-Bridging-Header.h +1 -1
- package/ios/RTNHCEModuleIOS.h +12 -12
- package/ios/RTNHCEModuleIOS.mm +125 -125
- package/ios/RTNHCEModuleIOSImpl.swift +190 -190
- package/js/NativeHCEModule.ts +33 -33
- package/package.json +1 -1
package/LICENSE
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2025 Michal Leszczynski
|
|
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.
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Michal Leszczynski
|
|
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.
|
package/README.md
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
# Package: React Native HCE Module
|
|
2
|
-
|
|
3
|
-
Host Card Emulation Module for React Native on iOS and Android platforms.
|
|
4
|
-
|
|
5
|
-
> [!IMPORTANT]
|
|
6
|
-
> As per Apple's policy, **Host Card Emulation feature is only available for users based in the European
|
|
7
|
-
> Economic Area (EEA)** with an iPhone running iOS 17.4 or later. Applications require a special HCE entitlement
|
|
8
|
-
> in order to use this feature, which is managed by Apple. Read more in the official support article:
|
|
9
|
-
> "[HCE-based contactless NFC transactions for apps in the European Economic Area (EEA)](https://developer.apple.com/support/hce-transactions-in-apps/)".
|
|
10
|
-
|
|
11
|
-
> [!NOTE]
|
|
12
|
-
> Kindly please reference this project in your README if you are willing to create a derivative library.
|
|
13
|
-
|
|
14
|
-
## API Specification & Demo App
|
|
15
|
-
|
|
16
|
-
* [module API (declarations)](https://github.com/icedevml/react-native-host-card-emulation/blob/master/packages/react-native-hce-module/js/NativeHCEModule.ts)
|
|
17
|
-
* [demo app's code (example usage)](https://github.com/icedevml/react-native-host-card-emulation/blob/master/packages/demo-hce-module-ios-app/App.tsx)
|
|
1
|
+
# Package: React Native HCE Module
|
|
2
|
+
|
|
3
|
+
Host Card Emulation Module for React Native on iOS and Android platforms.
|
|
4
|
+
|
|
5
|
+
> [!IMPORTANT]
|
|
6
|
+
> As per Apple's policy, **Host Card Emulation feature is only available for users based in the European
|
|
7
|
+
> Economic Area (EEA)** with an iPhone running iOS 17.4 or later. Applications require a special HCE entitlement
|
|
8
|
+
> in order to use this feature, which is managed by Apple. Read more in the official support article:
|
|
9
|
+
> "[HCE-based contactless NFC transactions for apps in the European Economic Area (EEA)](https://developer.apple.com/support/hce-transactions-in-apps/)".
|
|
10
|
+
|
|
11
|
+
> [!NOTE]
|
|
12
|
+
> Kindly please reference this project in your README if you are willing to create a derivative library.
|
|
13
|
+
|
|
14
|
+
## API Specification & Demo App
|
|
15
|
+
|
|
16
|
+
* [module API (declarations)](https://github.com/icedevml/react-native-host-card-emulation/blob/master/packages/react-native-hce-module/js/NativeHCEModule.ts)
|
|
17
|
+
* [demo app's code (example usage)](https://github.com/icedevml/react-native-host-card-emulation/blob/master/packages/demo-hce-module-ios-app/App.tsx)
|
package/RTNHCEModuleIOS.podspec
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
require "json"
|
|
2
|
-
|
|
3
|
-
package = JSON.parse(File.read(File.join(__dir__, "package.json")))
|
|
4
|
-
|
|
5
|
-
Pod::Spec.new do |s|
|
|
6
|
-
s.name = "RTNHCEModuleIOS"
|
|
7
|
-
s.version = package["version"]
|
|
8
|
-
s.summary = package["description"]
|
|
9
|
-
s.description = package["description"]
|
|
10
|
-
s.homepage = package["homepage"]
|
|
11
|
-
s.license = package["license"]
|
|
12
|
-
s.platforms = { :ios => "11.0" }
|
|
13
|
-
s.author = package["author"]
|
|
14
|
-
s.source = { :git => package["repository"], :tag => "#{s.version}" }
|
|
15
|
-
|
|
16
|
-
s.source_files = "ios/**/*.{h,m,mm,swift}"
|
|
17
|
-
|
|
18
|
-
install_modules_dependencies(s)
|
|
19
|
-
end
|
|
1
|
+
require "json"
|
|
2
|
+
|
|
3
|
+
package = JSON.parse(File.read(File.join(__dir__, "package.json")))
|
|
4
|
+
|
|
5
|
+
Pod::Spec.new do |s|
|
|
6
|
+
s.name = "RTNHCEModuleIOS"
|
|
7
|
+
s.version = package["version"]
|
|
8
|
+
s.summary = package["description"]
|
|
9
|
+
s.description = package["description"]
|
|
10
|
+
s.homepage = package["homepage"]
|
|
11
|
+
s.license = package["license"]
|
|
12
|
+
s.platforms = { :ios => "11.0" }
|
|
13
|
+
s.author = package["author"]
|
|
14
|
+
s.source = { :git => package["repository"], :tag => "#{s.version}" }
|
|
15
|
+
|
|
16
|
+
s.source_files = "ios/**/*.{h,m,mm,swift}"
|
|
17
|
+
|
|
18
|
+
install_modules_dependencies(s)
|
|
19
|
+
end
|
package/android/build.gradle
CHANGED
|
@@ -1,33 +1,33 @@
|
|
|
1
|
-
buildscript {
|
|
2
|
-
ext.safeExtGet = {prop, fallback ->
|
|
3
|
-
rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
|
|
4
|
-
}
|
|
5
|
-
repositories {
|
|
6
|
-
google()
|
|
7
|
-
gradlePluginPortal()
|
|
8
|
-
}
|
|
9
|
-
dependencies {
|
|
10
|
-
classpath("com.android.tools.build:gradle:7.3.1")
|
|
11
|
-
}
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
apply plugin: 'com.android.library'
|
|
15
|
-
apply plugin: 'com.facebook.react'
|
|
16
|
-
|
|
17
|
-
android {
|
|
18
|
-
compileSdkVersion safeExtGet('compileSdkVersion', 33)
|
|
19
|
-
namespace "com.itsecrnd.rtnhceandroid"
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
repositories {
|
|
23
|
-
maven {
|
|
24
|
-
// All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
|
|
25
|
-
url "$projectDir/../node_modules/react-native/android"
|
|
26
|
-
}
|
|
27
|
-
mavenCentral()
|
|
28
|
-
google()
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
dependencies {
|
|
32
|
-
implementation 'com.facebook.react:react-native:+'
|
|
33
|
-
}
|
|
1
|
+
buildscript {
|
|
2
|
+
ext.safeExtGet = {prop, fallback ->
|
|
3
|
+
rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
|
|
4
|
+
}
|
|
5
|
+
repositories {
|
|
6
|
+
google()
|
|
7
|
+
gradlePluginPortal()
|
|
8
|
+
}
|
|
9
|
+
dependencies {
|
|
10
|
+
classpath("com.android.tools.build:gradle:7.3.1")
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
apply plugin: 'com.android.library'
|
|
15
|
+
apply plugin: 'com.facebook.react'
|
|
16
|
+
|
|
17
|
+
android {
|
|
18
|
+
compileSdkVersion safeExtGet('compileSdkVersion', 33)
|
|
19
|
+
namespace "com.itsecrnd.rtnhceandroid"
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
repositories {
|
|
23
|
+
maven {
|
|
24
|
+
// All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
|
|
25
|
+
url "$projectDir/../node_modules/react-native/android"
|
|
26
|
+
}
|
|
27
|
+
mavenCentral()
|
|
28
|
+
google()
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
dependencies {
|
|
32
|
+
implementation 'com.facebook.react:react-native:+'
|
|
33
|
+
}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
|
2
|
-
package="com.itsecrnd.rtnhceandroid">
|
|
3
|
-
</manifest>
|
|
1
|
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
|
2
|
+
package="com.itsecrnd.rtnhceandroid">
|
|
3
|
+
</manifest>
|
|
@@ -1,89 +1,89 @@
|
|
|
1
|
-
package com.itsecrnd.rtnhceandroid;
|
|
2
|
-
|
|
3
|
-
import android.annotation.SuppressLint;
|
|
4
|
-
|
|
5
|
-
import javax.crypto.BadPaddingException;
|
|
6
|
-
import javax.crypto.Cipher;
|
|
7
|
-
import javax.crypto.IllegalBlockSizeException;
|
|
8
|
-
import javax.crypto.KeyGenerator;
|
|
9
|
-
import javax.crypto.NoSuchPaddingException;
|
|
10
|
-
import javax.crypto.SecretKey;
|
|
11
|
-
import javax.crypto.spec.GCMParameterSpec;
|
|
12
|
-
|
|
13
|
-
import java.nio.charset.StandardCharsets;
|
|
14
|
-
import java.security.InvalidAlgorithmParameterException;
|
|
15
|
-
import java.security.InvalidKeyException;
|
|
16
|
-
import java.security.NoSuchAlgorithmException;
|
|
17
|
-
import java.security.SecureRandom;
|
|
18
|
-
import java.util.Base64;
|
|
19
|
-
|
|
20
|
-
@SuppressLint("NewApi")
|
|
21
|
-
public class AESGCMUtil {
|
|
22
|
-
public static SecretKey generateKey() {
|
|
23
|
-
KeyGenerator keyGen;
|
|
24
|
-
try {
|
|
25
|
-
keyGen = KeyGenerator.getInstance("AES");
|
|
26
|
-
} catch (NoSuchAlgorithmException e) {
|
|
27
|
-
throw new RuntimeException("Failed to get AES algorithm.", e);
|
|
28
|
-
}
|
|
29
|
-
keyGen.init(256);
|
|
30
|
-
return keyGen.generateKey();
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
public static byte[] generateNonce(int size) {
|
|
34
|
-
byte[] nonce = new byte[size];
|
|
35
|
-
new SecureRandom().nextBytes(nonce); // Fill nonce with random bytes
|
|
36
|
-
return nonce;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
public static String encryptData(SecretKey key, String plaintext) {
|
|
40
|
-
try {
|
|
41
|
-
byte[] iv = new byte[32];
|
|
42
|
-
new SecureRandom().nextBytes(iv);
|
|
43
|
-
|
|
44
|
-
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
|
|
45
|
-
GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(128, iv);
|
|
46
|
-
cipher.init(Cipher.ENCRYPT_MODE, key, gcmParameterSpec);
|
|
47
|
-
|
|
48
|
-
byte[] plaintextBytes = plaintext.getBytes(StandardCharsets.UTF_8);
|
|
49
|
-
byte[] ciphertextBytes = cipher.doFinal(plaintextBytes);
|
|
50
|
-
|
|
51
|
-
return Base64.getEncoder().encodeToString(iv) + ';' +
|
|
52
|
-
Base64.getEncoder().encodeToString(ciphertextBytes);
|
|
53
|
-
} catch (NoSuchPaddingException
|
|
54
|
-
| NoSuchAlgorithmException
|
|
55
|
-
| IllegalBlockSizeException
|
|
56
|
-
| InvalidAlgorithmParameterException
|
|
57
|
-
| BadPaddingException
|
|
58
|
-
| InvalidKeyException e) {
|
|
59
|
-
throw new RuntimeException(e);
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
public static String decryptData(SecretKey key, String ciphertext) {
|
|
64
|
-
try {
|
|
65
|
-
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
|
|
66
|
-
String[] parts = ciphertext.split(";");
|
|
67
|
-
|
|
68
|
-
if (parts.length != 2) {
|
|
69
|
-
throw new IllegalArgumentException("Invalid ciphertext parameter.");
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
byte[] iv = Base64.getDecoder().decode(parts[0]);
|
|
73
|
-
byte[] ciphertextBytes = Base64.getDecoder().decode(parts[1]);
|
|
74
|
-
|
|
75
|
-
GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(128, iv);
|
|
76
|
-
cipher.init(Cipher.DECRYPT_MODE, key, gcmParameterSpec);
|
|
77
|
-
|
|
78
|
-
byte[] plaintextBytes = cipher.doFinal(ciphertextBytes);
|
|
79
|
-
return new String(plaintextBytes, StandardCharsets.UTF_8);
|
|
80
|
-
} catch (NoSuchPaddingException
|
|
81
|
-
| IllegalBlockSizeException
|
|
82
|
-
| InvalidAlgorithmParameterException
|
|
83
|
-
| BadPaddingException
|
|
84
|
-
| InvalidKeyException
|
|
85
|
-
| NoSuchAlgorithmException e) {
|
|
86
|
-
throw new RuntimeException(e);
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
}
|
|
1
|
+
package com.itsecrnd.rtnhceandroid;
|
|
2
|
+
|
|
3
|
+
import android.annotation.SuppressLint;
|
|
4
|
+
|
|
5
|
+
import javax.crypto.BadPaddingException;
|
|
6
|
+
import javax.crypto.Cipher;
|
|
7
|
+
import javax.crypto.IllegalBlockSizeException;
|
|
8
|
+
import javax.crypto.KeyGenerator;
|
|
9
|
+
import javax.crypto.NoSuchPaddingException;
|
|
10
|
+
import javax.crypto.SecretKey;
|
|
11
|
+
import javax.crypto.spec.GCMParameterSpec;
|
|
12
|
+
|
|
13
|
+
import java.nio.charset.StandardCharsets;
|
|
14
|
+
import java.security.InvalidAlgorithmParameterException;
|
|
15
|
+
import java.security.InvalidKeyException;
|
|
16
|
+
import java.security.NoSuchAlgorithmException;
|
|
17
|
+
import java.security.SecureRandom;
|
|
18
|
+
import java.util.Base64;
|
|
19
|
+
|
|
20
|
+
@SuppressLint("NewApi")
|
|
21
|
+
public class AESGCMUtil {
|
|
22
|
+
public static SecretKey generateKey() {
|
|
23
|
+
KeyGenerator keyGen;
|
|
24
|
+
try {
|
|
25
|
+
keyGen = KeyGenerator.getInstance("AES");
|
|
26
|
+
} catch (NoSuchAlgorithmException e) {
|
|
27
|
+
throw new RuntimeException("Failed to get AES algorithm.", e);
|
|
28
|
+
}
|
|
29
|
+
keyGen.init(256);
|
|
30
|
+
return keyGen.generateKey();
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
public static byte[] generateNonce(int size) {
|
|
34
|
+
byte[] nonce = new byte[size];
|
|
35
|
+
new SecureRandom().nextBytes(nonce); // Fill nonce with random bytes
|
|
36
|
+
return nonce;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
public static String encryptData(SecretKey key, String plaintext) {
|
|
40
|
+
try {
|
|
41
|
+
byte[] iv = new byte[32];
|
|
42
|
+
new SecureRandom().nextBytes(iv);
|
|
43
|
+
|
|
44
|
+
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
|
|
45
|
+
GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(128, iv);
|
|
46
|
+
cipher.init(Cipher.ENCRYPT_MODE, key, gcmParameterSpec);
|
|
47
|
+
|
|
48
|
+
byte[] plaintextBytes = plaintext.getBytes(StandardCharsets.UTF_8);
|
|
49
|
+
byte[] ciphertextBytes = cipher.doFinal(plaintextBytes);
|
|
50
|
+
|
|
51
|
+
return Base64.getEncoder().encodeToString(iv) + ';' +
|
|
52
|
+
Base64.getEncoder().encodeToString(ciphertextBytes);
|
|
53
|
+
} catch (NoSuchPaddingException
|
|
54
|
+
| NoSuchAlgorithmException
|
|
55
|
+
| IllegalBlockSizeException
|
|
56
|
+
| InvalidAlgorithmParameterException
|
|
57
|
+
| BadPaddingException
|
|
58
|
+
| InvalidKeyException e) {
|
|
59
|
+
throw new RuntimeException(e);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
public static String decryptData(SecretKey key, String ciphertext) {
|
|
64
|
+
try {
|
|
65
|
+
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
|
|
66
|
+
String[] parts = ciphertext.split(";");
|
|
67
|
+
|
|
68
|
+
if (parts.length != 2) {
|
|
69
|
+
throw new IllegalArgumentException("Invalid ciphertext parameter.");
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
byte[] iv = Base64.getDecoder().decode(parts[0]);
|
|
73
|
+
byte[] ciphertextBytes = Base64.getDecoder().decode(parts[1]);
|
|
74
|
+
|
|
75
|
+
GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(128, iv);
|
|
76
|
+
cipher.init(Cipher.DECRYPT_MODE, key, gcmParameterSpec);
|
|
77
|
+
|
|
78
|
+
byte[] plaintextBytes = cipher.doFinal(ciphertextBytes);
|
|
79
|
+
return new String(plaintextBytes, StandardCharsets.UTF_8);
|
|
80
|
+
} catch (NoSuchPaddingException
|
|
81
|
+
| IllegalBlockSizeException
|
|
82
|
+
| InvalidAlgorithmParameterException
|
|
83
|
+
| BadPaddingException
|
|
84
|
+
| InvalidKeyException
|
|
85
|
+
| NoSuchAlgorithmException e) {
|
|
86
|
+
throw new RuntimeException(e);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
@@ -1,66 +1,66 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Content of "BinaryUtils" class:
|
|
3
|
-
* Original source: https://github.com/googlearchive/android-CardEmulation
|
|
4
|
-
*
|
|
5
|
-
* ---
|
|
6
|
-
*
|
|
7
|
-
* Copyright (C) 2013 The Android Open Source Project
|
|
8
|
-
*
|
|
9
|
-
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
10
|
-
* you may not use this file except in compliance with the License.
|
|
11
|
-
* You may obtain a copy of the License at
|
|
12
|
-
*
|
|
13
|
-
* http://www.apache.org/licenses/LICENSE-2.0
|
|
14
|
-
*
|
|
15
|
-
* Unless required by applicable law or agreed to in writing, software
|
|
16
|
-
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
17
|
-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
18
|
-
* See the License for the specific language governing permissions and
|
|
19
|
-
* limitations under the License.
|
|
20
|
-
*
|
|
21
|
-
*/
|
|
22
|
-
|
|
23
|
-
package com.itsecrnd.rtnhceandroid;
|
|
24
|
-
|
|
25
|
-
public class BinaryUtils {
|
|
26
|
-
/**
|
|
27
|
-
* Utility method to convert a byte array to a hexadecimal string.
|
|
28
|
-
*
|
|
29
|
-
* @param bytes Bytes to convert
|
|
30
|
-
* @return String, containing hexadecimal representation.
|
|
31
|
-
*/
|
|
32
|
-
public static String ByteArrayToHexString(byte[] bytes) {
|
|
33
|
-
final char[] hexArray = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
|
|
34
|
-
char[] hexChars = new char[bytes.length * 2]; // Each byte has two hex characters (nibbles)
|
|
35
|
-
int v;
|
|
36
|
-
for (int j = 0; j < bytes.length; j++) {
|
|
37
|
-
v = bytes[j] & 0xFF; // Cast bytes[j] to int, treating as unsigned value
|
|
38
|
-
hexChars[j * 2] = hexArray[v >>> 4]; // Select hex character from upper nibble
|
|
39
|
-
hexChars[j * 2 + 1] = hexArray[v & 0x0F]; // Select hex character from lower nibble
|
|
40
|
-
}
|
|
41
|
-
return new String(hexChars);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* Utility method to convert a hexadecimal string to a byte string.
|
|
46
|
-
*
|
|
47
|
-
* <p>Behavior with input strings containing non-hexadecimal characters is undefined.
|
|
48
|
-
*
|
|
49
|
-
* @param s String containing hexadecimal characters to convert
|
|
50
|
-
* @return Byte array generated from input
|
|
51
|
-
* @throws java.lang.IllegalArgumentException if input length is incorrect
|
|
52
|
-
*/
|
|
53
|
-
public static byte[] HexStringToByteArray(String s) throws IllegalArgumentException {
|
|
54
|
-
int len = s.length();
|
|
55
|
-
if (len % 2 == 1) {
|
|
56
|
-
throw new IllegalArgumentException("Hex string must have even number of characters");
|
|
57
|
-
}
|
|
58
|
-
byte[] data = new byte[len / 2]; // Allocate 1 byte per 2 hex characters
|
|
59
|
-
for (int i = 0; i < len; i += 2) {
|
|
60
|
-
// Convert each character into a integer (base-16), then bit-shift into place
|
|
61
|
-
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
|
|
62
|
-
+ Character.digit(s.charAt(i+1), 16));
|
|
63
|
-
}
|
|
64
|
-
return data;
|
|
65
|
-
}
|
|
1
|
+
/*
|
|
2
|
+
* Content of "BinaryUtils" class:
|
|
3
|
+
* Original source: https://github.com/googlearchive/android-CardEmulation
|
|
4
|
+
*
|
|
5
|
+
* ---
|
|
6
|
+
*
|
|
7
|
+
* Copyright (C) 2013 The Android Open Source Project
|
|
8
|
+
*
|
|
9
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
10
|
+
* you may not use this file except in compliance with the License.
|
|
11
|
+
* You may obtain a copy of the License at
|
|
12
|
+
*
|
|
13
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
14
|
+
*
|
|
15
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
16
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
17
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
18
|
+
* See the License for the specific language governing permissions and
|
|
19
|
+
* limitations under the License.
|
|
20
|
+
*
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
package com.itsecrnd.rtnhceandroid;
|
|
24
|
+
|
|
25
|
+
public class BinaryUtils {
|
|
26
|
+
/**
|
|
27
|
+
* Utility method to convert a byte array to a hexadecimal string.
|
|
28
|
+
*
|
|
29
|
+
* @param bytes Bytes to convert
|
|
30
|
+
* @return String, containing hexadecimal representation.
|
|
31
|
+
*/
|
|
32
|
+
public static String ByteArrayToHexString(byte[] bytes) {
|
|
33
|
+
final char[] hexArray = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
|
|
34
|
+
char[] hexChars = new char[bytes.length * 2]; // Each byte has two hex characters (nibbles)
|
|
35
|
+
int v;
|
|
36
|
+
for (int j = 0; j < bytes.length; j++) {
|
|
37
|
+
v = bytes[j] & 0xFF; // Cast bytes[j] to int, treating as unsigned value
|
|
38
|
+
hexChars[j * 2] = hexArray[v >>> 4]; // Select hex character from upper nibble
|
|
39
|
+
hexChars[j * 2 + 1] = hexArray[v & 0x0F]; // Select hex character from lower nibble
|
|
40
|
+
}
|
|
41
|
+
return new String(hexChars);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Utility method to convert a hexadecimal string to a byte string.
|
|
46
|
+
*
|
|
47
|
+
* <p>Behavior with input strings containing non-hexadecimal characters is undefined.
|
|
48
|
+
*
|
|
49
|
+
* @param s String containing hexadecimal characters to convert
|
|
50
|
+
* @return Byte array generated from input
|
|
51
|
+
* @throws java.lang.IllegalArgumentException if input length is incorrect
|
|
52
|
+
*/
|
|
53
|
+
public static byte[] HexStringToByteArray(String s) throws IllegalArgumentException {
|
|
54
|
+
int len = s.length();
|
|
55
|
+
if (len % 2 == 1) {
|
|
56
|
+
throw new IllegalArgumentException("Hex string must have even number of characters");
|
|
57
|
+
}
|
|
58
|
+
byte[] data = new byte[len / 2]; // Allocate 1 byte per 2 hex characters
|
|
59
|
+
for (int i = 0; i < len; i += 2) {
|
|
60
|
+
// Convert each character into a integer (base-16), then bit-shift into place
|
|
61
|
+
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
|
|
62
|
+
+ Character.digit(s.charAt(i+1), 16));
|
|
63
|
+
}
|
|
64
|
+
return data;
|
|
65
|
+
}
|
|
66
66
|
}
|