Внутренний широковещательный приёмник
Внутренний широковещательный приёмник — это широковещательный приёмник, который никогда не будет получать широковещательные сообщения от приложений, внешних по отношению к внутренним. Он состоит из нескольких внутренних приложений и используется для защиты информации или функций, обрабатываемых внутренними приложениями.
Ключевые моменты (приём широковещательных сообщений):
Пример кода внутреннего широковещательного приёмника может использоваться для статических и динамических широковещательных приёмников.
InhouseReceiver.java
package org.jssec.android.broadcast.inhousereceiver;
import org.jssec.android.shared.SigPerm;
import org.jssec.android.shared.Utils;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.widget.Toast;
public class InhouseReceiver extends BroadcastReceiver {
// Внутреннее разрешение на подпись
private static final String MY_PERMISSION = "org.jssec.android.broadcast.inhousereceiver.MY_PERMISSION";
// Хеш-значение сертификата
private static String sMyCertHash = null;
private static String myCertHash(Context context) {
if (sMyCertHash == null) {
if (Utils.isDebuggable(context)) {
// Значение хеш-функции сертификата "androiddebugkey" в debug.keystore.
sMyCertHash = "0EFB7236 328348A9 89718BAD DF57F544 D5CCB4AE B9DB34BC 1E29DD26 F77C8255";
} else {
// Значение хеш-функции сертификата «ключ моей компании» в keystore.
sMyCertHash = "D397D343 A5CBC10F 4EDDEB7C A10062DE 5690984F 1FB9E88B D7B3A7C2 42E142CA";
}
}
return sMyCertHash;
}
private static final String MY_BROADCAST_INHOUSE =
"org.jssec.android.broadcast.MY_BROADCAST_INHOUSE";
public boolean isDynamic = false;
private String getName() {
return isDynamic ? "Внутренний динамический широковещательный приёмник" : "Внутренний статический широковещательный приёмник";
}
@Override
public void onReceive(Context context, Intent intent) {
// *** Пункт 6 *** Убедитесь, что внутреннее разрешение на подпись определяется внутренним приложением.
if (!SigPerm.test(context, MY_PERMISSION, myCertHash(context))) {
Toast.makeText(context, "Внутреннее разрешение на подпись не объявлено внутренним приложением.",
Toast.LENGTH_LONG).show();
return;
}
// *** Пункт 7 *** Осторожно и надёжно обработайте полученное намерение,
// даже если широковещательная передача была отправлена внутренним приложением..
// Опущено, поскольку это пример. Пожалуйста, обратитесь к разделу «3.2 Обработка входных данных осторожно и надёжно».
if (MY_BROADCAST_INHOUSE.equals(intent.getAction())) {
String param = intent.getStringExtra("PARAM");
Toast.makeText(context,
String.format("%s:¥nReceived param: ¥"%s¥"", getName(), param),
Toast.LENGTH_SHORT).show();
}
// *** Пункт 8 *** Можно вернуть конфиденциальную информацию, так как запрашивающее приложение является внутренним.
setResultCode(Activity.RESULT_OK);
setResultData(String.format("Конфиденциальная информация от %s", getName()));
abortBroadcast();
}
}
Статический широковещательный приёмник определяется в AndroidManifest.xml.
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.jssec.android.broadcast.inhousereceiver" >
<!-- *** Пункт 1 *** Определите внутреннее разрешение на подпись для приёма Широковещательных Сообщений -->
<permission
android:name="org.jssec.android.broadcast.inhousereceiver.MY_PERMISSION"
android:protectionLevel="signature" />
<!-- *** Пункт 2 *** Объявите об использовании внутреннего разрешения на подпись для получения результатов. -->
<uses-permission
android:name="org.jssec.android.broadcast.inhousesender.MY_PERMISSION" />
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:allowBackup="false" >
<!-- *** Пункт 3 *** Явно установите атрибут exported в значение true. -->
<!-- *** Пункт 4 *** Требуйте внутреннего разрешения на подпись статического Широковещательного Приёмника -->
А здесь приведённый текст обрывается. Возможно, в запросе есть продолжение, которое нужно перевести? В динамическом широковещательном приёмнике регистрация/отмена регистрации выполняется через вызов программы `registerReceiver()` или `unregisterReceiver()`, чтобы выполнить регистрацию/отмену регистрации, необходимо определить кнопку в `PublicReceiverActivity`. Поскольку область действия экземпляра динамического широковещательного приёмника больше, чем у `PublicReceiverActivity`, его нельзя сохранить как переменную-член `PublicReceiverActivity`. В этом случае экземпляр динамического широковещательного приёмника следует сохранить как переменную-член `DynamicReceiverService`, а затем запустить/остановить `DynamicReceiverService` из `PublicReceiverActivity` для косвенной регистрации/отмены регистрации динамического широковещательного приёмника.
**InhouseReceiverActivity.java**
```java
package org.jssec.android.broadcast.inhousereceiver;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
public class InhouseReceiverActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
public void onRegisterReceiverClick(View view) {
Intent intent = new Intent(this, DynamicReceiverService.class);
startService(intent);
}
public void onUnregisterReceiverClick(View view) {
Intent intent = new Intent(this, DynamicReceiverService.class);
stopService(intent);
}
}
DynamicReceiverService.java
package org.jssec.android.broadcast.inhousereceiver;
import android.app.Service;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.IBinder;
import android.widget.Toast;
public class DynamicReceiverService extends Service {
private static final String MY_BROADCAST_INHOUSE = "org.jssec.android.broadcast.MY_BROADCAST_INHOUSE";
private InhouseReceiver mReceiver;
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
mReceiver = new InhouseReceiver();
mReceiver.isDynamic = true;
IntentFilter filter = new IntentFilter();
filter.addAction(MY_BROADCAST_INHOUSE);
filter.setPriority(1); // Prioritize Dynamic Broadcast Receiver, rather than Static Broadcast Receiver.
// *** POINT 5 *** When registering a dynamic broadcast receiver, require the in-house signature permission.
registerReceiver(mReceiver, filter, "org.jssec.android.broadcast.inhousereceiver.MY_PERMISSION", null);
Toast.makeText(this,
"Registered Dynamic Broadcast Receiver.",
Toast.LENGTH_SHORT).show();
}
@Override
public void onDestroy() {
super.onDestroy();
unregisterReceiver(mReceiver);
mReceiver = null;
Toast.makeText(this,
"Unregistered Dynamic Broadcast Receiver.",
Toast.LENGTH_SHORT).show();
}
}
Примечание: в тексте запроса есть фрагменты кода на языке Java, но они не содержат ошибок и не требуют доработки. Код PkgCert.java
public class PkgCert {
public static boolean test(Context ctx, String pkgname, String correctHash) {
if (correctHash == null) return false;
correctHash = correctHash.replaceAll(" ", "");
return correctHash.equals(hash(ctx, pkgname));
}
public static String hash(Context ctx, String sigPermName) {
if (sigPermName == null) return null;
try {
// Get the package name of the application which declares a permission named sigPermName.
PackageManager pm = ctx.getPackageManager();
PermissionInfo pi;
pi = pm.getPermissionInfo(sigPermName, PackageManager.GET_META_DATA);
String pkgname = pi.packageName;
// Fail if the permission named sigPermName is not a Signature Permission
if (pi.protectionLevel != PermissionInfo.PROTECTION_SIGNATURE) return null;
// Return the certificate hash value of the application which declares a permission named sigPermName.
return PkgCert.hash(ctx, pkgname);
} catch (NameNotFoundException e) {
return null;
}
}
}
Текст запроса
При экспорте APK необходимо использовать тот же ключ разработчика, который использовался для подписи приложения.
Далее представлен пример кода для отправки широковещательного сообщения.
Основные шаги: 10. Определить внутреннее разрешение на подпись для получения результатов. 11. Объявить использование внутреннего разрешения на подпись для приёма широковещательных сообщений. 12. Убедиться, что внутреннее разрешение на подпись определено внутренним приложением. 13. Поскольку запрашивающее приложение является внутренним, можно вернуть конфиденциальную информацию. 14. Необходим приёмник с внутренним разрешением на подпись. 15. Осторожно и безопасно обрабатывать полученные данные. 16. При экспорте APK использовать тот же ключ разработчика для подписания APK.
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.jssec.android.broadcast.inhousesender" >
<uses-permission android:name="android.permission.BROADCAST_STICKY"/>
<!-- *** POINT 10 *** Define an in-house signature permission to receive results. -->
<permission
android:name="org.jssec.android.broadcast.inhousesender.MY_PERMISSION"
android:protectionLevel="signature" />
<!-- *** POINT 11 *** Declare to use the in-house signature permission to receive Broadcasts. -->
<uses-permission
android:name="org.jssec.android.broadcast.inhousereceiver.MY_PERMISSION" />
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:allowBackup="false" >
<activity
android:name="org.jssec.android.broadcast.inhousesender.InhouseSenderActivity"
android:label="@string/app_name"
android:exported="true" >
<intent-filter>
<action
``` ```
android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
InhouseSenderActivity.java
package org.jssec.android.broadcast.inhousesender;
import org.jssec.android.shared.SigPerm;
import org.jssec.android.shared.Utils;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
public class InhouseSenderActivity extends Activity {
// In-house Signature Permission
private static final String MY_PERMISSION = "org.jssec.android.broadcast.inhousesender.MY_PERMISSION";
// In-house certificate hash value
private static String sMyCertHash = null;
private static String myCertHash(Context context) {
if (sMyCertHash == null) {
if (Utils.isDebuggable(context)) {
// Certificate hash value of "androiddebugkey" in the debug.keystore.
sMyCertHash = "0EFB7236 328348A9 89718BAD DF57F544 D5CCB4AE B9DB34BC 1E29DD26 F77C8255";
} else {
// Certificate hash value of "my company key" in the keystore.
sMyCertHash = "D397D343 A5CBC10F 4EDDEB7C A10062DE 5690984F 1FB9E88B D7B3A7C2 42E142CA";
}
}
return sMyCertHash;
}
private static final String MY_BROADCAST_INHOUSE =
"org.jssec.android.broadcast.MY_BROADCAST_INHOUSE";
public void onSendNormalClick(View view) {
// *** POINT 12 *** Verify that the in-house signature permission is defined by an in-house application.
if (!SigPerm.test(this, MY_PERMISSION, myCertHash(this))) {
Toast.makeText(this, "The in-house signature permission is not declared by in-house application.",
Toast.LENGTH_LONG).show();
return;
}
// *** POINT 13 *** Sensitive information can be returned since the requesting application is in-house.
Intent intent = new Intent(MY_BROADCAST_INHOUSE);
intent.putExtra("PARAM", "Sensitive Info from Sender");
// *** POINT 14 *** Require the in-house signature permission to limit receivers.
sendBroadcast(intent, "org.jssec.android.broadcast.inhousesender.MY_PERMISSION");
}
public void onSendOrderedClick(View view) {
// *** POINT 12 *** Verify that the in-house signature permission is defined by an in-house application.
if (!SigPerm.test(this, MY_PERMISSION, myCertHash(this))) {
Toast.makeText(this, "The in-house signature permission is not declared by in-house application.",
Toast.LENGTH_LONG).set
return;
}
// *** POINT 13 *** Sensitive information can be returned since the requesting application is in-house.
Intent intent = new Intent(MY_BROADCAST_INHOUSE);
intent.putExtra("PARAM", "Sensitive Info from Sender");
// *** POINT 14 *** Require the in-house signature permission to limit receivers.
sendOrderedBroadcast(intent, "org.jssec.android.broadcast.inhousesender.MY_PERMISSION",
mResultReceiver, null, 0, null, null);
}
private BroadcastReceiver mResultReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
// *** POINT 15 *** Handle the received result data carefully and securely,
// even though the data came from an in-house application.
// Omitted, since this is a sample. Please refer to "3.2 Handling Input Data Carefully and Securely."
String data = getResultData();
InhouseSenderActivity.this.logLine(String.format("Received result: ¥"%s¥"", data));
}
};
private TextView mLogView;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
``` **SigPerm.java**
package org.jssec.android.shared;
import android.content.Context; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.PermissionInfo;
public class SigPerm { public static boolean test(Context ctx, String sigPermName, String correctHash) { if (correctHash == null) return false; correctHash = correctHash.replaceAll(" ", ""); return correctHash.equals(hash(ctx, sigPermName)); }
public static String hash(Context ctx, String sigPermName) {
if (sigPermName == null) return null;
try {
// Получить имя пакета приложения, которое объявляет разрешение с именем sigPermName.
PackageManager pm = ctx.getPackageManager();
PermissionInfo pi;
pi = pm.getPermissionInfo(sigPermName, PackageManager.GET_META_DATA);
String pkgname = pi.packageName;
// Завершить работу, если разрешение с именем sigPermName не является разрешением подписи
if (pi.protectionLevel != PermissionInfo.PROTECTION_SIGNATURE) return null;
// Возвратить значение хэша сертификата приложения, которое заявляет разрешение с именем sigPermName.
return PkgCert.hash(ctx, pkgname);
} catch (NameNotFoundException e) {
return null;
}
}
}
**PkgCert.java**
package org.jssec.android.shared;
import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import android.content.Context; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.Signature;
public class PkgCert { public static boolean test(Context ctx, String pkgname, String correctHash) { if (correctHash == null) return false; correctHash = correctHash.replaceAll(" ", ""); return correctHash.equals(hash(ctx, pkgname)); }
public static String hash(Context ctx, String pkgname) {
if (pkgname == null) return null;
try {
PackageManager pm = ctx.getPackageManager();
PackageInfo pkginfo = pm.getPackageInfo(pkgname, PackageManager.GET_SIGNATURES);
if (pkginfo.signatures.length != 1) return null; // Не будет обрабатывать несколько подписей.
Signature sig = pkginfo.signatures[0];
byte[] cert = sig.toByteArray();
byte[] sha256 = computeSha256(cert);
return byte2hex(sha256);
} catch (NameNotFoundException e) {
return null;
}
}
private static byte[] computeSha256(byte[] data) {
try {
return MessageDigest.getInstance("SHA-256").digest(data);
} catch (NoSuchAlgorithmException e) {
return null;
}
}
private static String byte2hex(byte[] data) {
if (data == null) return null;
final StringBuilder hexadecimal = new StringBuilder();
for (final byte b : data) {
hexadecimal.append(String.format("%02X", b));
}
return hexadecimal.toString();
}
}
При экспорте APK используйте тот же ключ разработчика, что и для отправки приложения.
Вы можете оставить комментарий после Вход в систему
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Опубликовать ( 0 )