Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in / Register
Toggle navigation
M
Magisk
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Administrator
Magisk
Commits
05f41928
Commit
05f41928
authored
Oct 29, 2017
by
topjohnwu
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add boot signing
parent
2ee08298
Show whitespace changes
Inline
Side-by-side
Showing
17 changed files
with
460 additions
and
68 deletions
+460
-68
build.gradle
app/build.gradle
+5
-5
CheckSafetyNet.java
...main/java/com/topjohnwu/magisk/asyncs/CheckSafetyNet.java
+1
-1
HideManager.java
...rc/main/java/com/topjohnwu/magisk/asyncs/HideManager.java
+1
-1
Activity.java
...c/main/java/com/topjohnwu/magisk/components/Activity.java
+3
-7
OnBootIntentService.java
...va/com/topjohnwu/magisk/services/OnBootIntentService.java
+4
-2
BootSigner.java
app/src/main/java/com/topjohnwu/magisk/utils/BootSigner.java
+46
-0
Utils.java
app/src/main/java/com/topjohnwu/magisk/utils/Utils.java
+12
-0
ZipUtils.java
app/src/main/java/com/topjohnwu/magisk/utils/ZipUtils.java
+4
-4
.gitignore
crypto/.gitignore
+0
-0
build.gradle
crypto/build.gradle
+4
-3
ByteArrayStream.java
...o/src/main/java/com/topjohnwu/crypto/ByteArrayStream.java
+1
-1
CryptoUtils.java
crypto/src/main/java/com/topjohnwu/crypto/CryptoUtils.java
+136
-0
JarMap.java
crypto/src/main/java/com/topjohnwu/crypto/JarMap.java
+1
-1
SignAPK.java
crypto/src/main/java/com/topjohnwu/crypto/SignAPK.java
+5
-40
SignBoot.java
crypto/src/main/java/com/topjohnwu/crypto/SignBoot.java
+234
-0
ZipSigner.java
crypto/src/main/java/com/topjohnwu/crypto/ZipSigner.java
+2
-2
settings.gradle
settings.gradle
+1
-1
No files found.
app/build.gradle
View file @
05f41928
...
@@ -54,11 +54,11 @@ repositories {
...
@@ -54,11 +54,11 @@ repositories {
dependencies
{
dependencies
{
implementation
fileTree
(
include:
[
'*.jar'
],
dir:
'libs'
)
implementation
fileTree
(
include:
[
'*.jar'
],
dir:
'libs'
)
implementation
project
(
':
jarsigner
'
)
implementation
project
(
':
crypto
'
)
implementation
'com.android.support:recyclerview-v7:2
6.1
.0'
implementation
'com.android.support:recyclerview-v7:2
7.0
.0'
implementation
'com.android.support:cardview-v7:2
6.1
.0'
implementation
'com.android.support:cardview-v7:2
7.0
.0'
implementation
'com.android.support:design:2
6.1
.0'
implementation
'com.android.support:design:2
7.0
.0'
implementation
'com.android.support:support-v4:2
6.1
.0'
implementation
'com.android.support:support-v4:2
7.0
.0'
implementation
'com.jakewharton:butterknife:8.8.1'
implementation
'com.jakewharton:butterknife:8.8.1'
implementation
'com.atlassian.commonmark:commonmark:0.10.0'
implementation
'com.atlassian.commonmark:commonmark:0.10.0'
implementation
'org.kamranzafar:jtar:2.3'
implementation
'org.kamranzafar:jtar:2.3'
...
...
app/src/main/java/com/topjohnwu/magisk/asyncs/CheckSafetyNet.java
View file @
05f41928
...
@@ -2,7 +2,7 @@ package com.topjohnwu.magisk.asyncs;
...
@@ -2,7 +2,7 @@ package com.topjohnwu.magisk.asyncs;
import
android.app.Activity
;
import
android.app.Activity
;
import
com.topjohnwu.
jarsigner
.ByteArrayStream
;
import
com.topjohnwu.
crypto
.ByteArrayStream
;
import
com.topjohnwu.magisk.MagiskManager
;
import
com.topjohnwu.magisk.MagiskManager
;
import
com.topjohnwu.magisk.utils.Shell
;
import
com.topjohnwu.magisk.utils.Shell
;
import
com.topjohnwu.magisk.utils.WebService
;
import
com.topjohnwu.magisk.utils.WebService
;
...
...
app/src/main/java/com/topjohnwu/magisk/asyncs/HideManager.java
View file @
05f41928
...
@@ -3,7 +3,7 @@ package com.topjohnwu.magisk.asyncs;
...
@@ -3,7 +3,7 @@ package com.topjohnwu.magisk.asyncs;
import
android.os.Environment
;
import
android.os.Environment
;
import
android.widget.Toast
;
import
android.widget.Toast
;
import
com.topjohnwu.
jarsigner
.JarMap
;
import
com.topjohnwu.
crypto
.JarMap
;
import
com.topjohnwu.magisk.MagiskManager
;
import
com.topjohnwu.magisk.MagiskManager
;
import
com.topjohnwu.magisk.R
;
import
com.topjohnwu.magisk.R
;
import
com.topjohnwu.magisk.database.SuDatabaseHelper
;
import
com.topjohnwu.magisk.database.SuDatabaseHelper
;
...
...
app/src/main/java/com/topjohnwu/magisk/components/Activity.java
View file @
05f41928
...
@@ -14,6 +14,7 @@ import android.view.WindowManager;
...
@@ -14,6 +14,7 @@ import android.view.WindowManager;
import
com.topjohnwu.magisk.MagiskManager
;
import
com.topjohnwu.magisk.MagiskManager
;
import
com.topjohnwu.magisk.R
;
import
com.topjohnwu.magisk.R
;
import
com.topjohnwu.magisk.utils.Topic
;
import
com.topjohnwu.magisk.utils.Topic
;
import
com.topjohnwu.magisk.utils.Utils
;
public
class
Activity
extends
AppCompatActivity
{
public
class
Activity
extends
AppCompatActivity
{
...
@@ -88,14 +89,9 @@ public class Activity extends AppCompatActivity {
...
@@ -88,14 +89,9 @@ public class Activity extends AppCompatActivity {
@Keep
@Keep
public
void
swapResources
(
String
dexPath
)
{
public
void
swapResources
(
String
dexPath
)
{
try
{
mAssetManager
=
Utils
.
getAssets
(
dexPath
);
AssetManager
asset
=
AssetManager
.
class
.
newInstance
();
if
(
mAssetManager
==
null
)
AssetManager
.
class
.
getMethod
(
"addAssetPath"
,
String
.
class
).
invoke
(
asset
,
dexPath
);
mAssetManager
=
asset
;
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
return
;
return
;
}
Resources
res
=
super
.
getResources
();
Resources
res
=
super
.
getResources
();
mResources
=
new
Resources
(
mAssetManager
,
res
.
getDisplayMetrics
(),
res
.
getConfiguration
());
mResources
=
new
Resources
(
mAssetManager
,
res
.
getDisplayMetrics
(),
res
.
getConfiguration
());
mResources
.
newTheme
().
setTo
(
super
.
getTheme
());
mResources
.
newTheme
().
setTo
(
super
.
getTheme
());
...
...
app/src/main/java/com/topjohnwu/magisk/services/OnBootIntentService.java
View file @
05f41928
...
@@ -3,8 +3,9 @@ package com.topjohnwu.magisk.services;
...
@@ -3,8 +3,9 @@ package com.topjohnwu.magisk.services;
import
android.app.IntentService
;
import
android.app.IntentService
;
import
android.content.Intent
;
import
android.content.Intent
;
import
android.os.Build
;
import
android.os.Build
;
import
android.support.v
7
.app.NotificationCompat
;
import
android.support.v
4
.app.NotificationCompat
;
import
com.topjohnwu.magisk.MagiskManager
;
import
com.topjohnwu.magisk.R
;
import
com.topjohnwu.magisk.R
;
public
class
OnBootIntentService
extends
IntentService
{
public
class
OnBootIntentService
extends
IntentService
{
...
@@ -19,7 +20,8 @@ public class OnBootIntentService extends IntentService {
...
@@ -19,7 +20,8 @@ public class OnBootIntentService extends IntentService {
public
void
onCreate
()
{
public
void
onCreate
()
{
super
.
onCreate
();
super
.
onCreate
();
if
(
Build
.
VERSION
.
SDK_INT
>=
Build
.
VERSION_CODES
.
O
)
{
if
(
Build
.
VERSION
.
SDK_INT
>=
Build
.
VERSION_CODES
.
O
)
{
NotificationCompat
.
Builder
builder
=
new
NotificationCompat
.
Builder
(
this
);
NotificationCompat
.
Builder
builder
=
new
NotificationCompat
.
Builder
(
this
,
MagiskManager
.
NOTIFICATION_CHANNEL
);
builder
.
setSmallIcon
(
R
.
drawable
.
ic_magisk
)
builder
.
setSmallIcon
(
R
.
drawable
.
ic_magisk
)
.
setContentTitle
(
"onBoot"
)
.
setContentTitle
(
"onBoot"
)
.
setContentText
(
"Running onBoot operations..."
);
.
setContentText
(
"Running onBoot operations..."
);
...
...
app/src/main/java/com/topjohnwu/magisk/utils/BootSigner.java
0 → 100644
View file @
05f41928
package
com
.
topjohnwu
.
magisk
.
utils
;
import
android.content.res.AssetManager
;
import
com.topjohnwu.crypto.SignBoot
;
import
java.io.FileInputStream
;
import
java.io.InputStream
;
public
class
BootSigner
{
public
static
void
main
(
String
[]
args
)
throws
Exception
{
if
(
"-verify"
.
equals
(
args
[
0
]))
{
String
certPath
=
""
;
if
(
args
.
length
>=
4
&&
"-certificate"
.
equals
(
args
[
2
]))
{
/* args[3] is the path to a public key certificate */
certPath
=
args
[
3
];
}
/* args[1] is the path to a signed boot image */
boolean
signed
=
SignBoot
.
verifySignature
(
args
[
1
],
certPath
.
isEmpty
()
?
null
:
new
FileInputStream
(
certPath
));
System
.
exit
(
signed
?
0
:
1
);
}
else
{
/* args[0] is the target name, typically /boot
args[1] is the path to a boot image to sign
args[2] is the path where to output the signed boot image
args[3] is the path to a private key
args[4] is the path to the matching public key certificate
*/
InputStream
keyIn
,
sigIn
;
if
(
args
.
length
>=
5
)
{
keyIn
=
new
FileInputStream
(
args
[
3
]);
sigIn
=
new
FileInputStream
(
args
[
4
]);
}
else
{
/* Use internal test keys */
AssetManager
asset
=
Utils
.
getAssets
(
System
.
getProperty
(
"java.class.path"
));
if
(
asset
==
null
)
System
.
exit
(
1
);
keyIn
=
asset
.
open
(
ZipUtils
.
PRIVATE_KEY_NAME
);
sigIn
=
asset
.
open
(
ZipUtils
.
PUBLIC_KEY_NAME
);
}
SignBoot
.
doSignature
(
args
[
0
],
args
[
1
],
args
[
2
],
keyIn
,
sigIn
);
}
}
}
app/src/main/java/com/topjohnwu/magisk/utils/Utils.java
View file @
05f41928
...
@@ -7,6 +7,7 @@ import android.content.Context;
...
@@ -7,6 +7,7 @@ import android.content.Context;
import
android.content.IntentFilter
;
import
android.content.IntentFilter
;
import
android.content.SharedPreferences
;
import
android.content.SharedPreferences
;
import
android.content.pm.PackageManager
;
import
android.content.pm.PackageManager
;
import
android.content.res.AssetManager
;
import
android.content.res.Configuration
;
import
android.content.res.Configuration
;
import
android.database.Cursor
;
import
android.database.Cursor
;
import
android.net.ConnectivityManager
;
import
android.net.ConnectivityManager
;
...
@@ -203,4 +204,15 @@ public class Utils {
...
@@ -203,4 +204,15 @@ public class Utils {
public
static
File
getDatabasePath
(
Context
context
,
String
dbName
)
{
public
static
File
getDatabasePath
(
Context
context
,
String
dbName
)
{
return
new
File
(
context
.
getFilesDir
().
getParent
()
+
"/databases"
,
dbName
);
return
new
File
(
context
.
getFilesDir
().
getParent
()
+
"/databases"
,
dbName
);
}
}
public
static
AssetManager
getAssets
(
String
apk
)
{
try
{
AssetManager
asset
=
AssetManager
.
class
.
newInstance
();
AssetManager
.
class
.
getMethod
(
"addAssetPath"
,
String
.
class
).
invoke
(
asset
,
apk
);
return
asset
;
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
return
null
;
}
}
}
}
\ No newline at end of file
app/src/main/java/com/topjohnwu/magisk/utils/ZipUtils.java
View file @
05f41928
...
@@ -2,8 +2,8 @@ package com.topjohnwu.magisk.utils;
...
@@ -2,8 +2,8 @@ package com.topjohnwu.magisk.utils;
import
android.content.res.AssetManager
;
import
android.content.res.AssetManager
;
import
com.topjohnwu.
jarsigner
.JarMap
;
import
com.topjohnwu.
crypto
.JarMap
;
import
com.topjohnwu.
jarsigner
.SignAPK
;
import
com.topjohnwu.
crypto
.SignAPK
;
import
com.topjohnwu.magisk.MagiskManager
;
import
com.topjohnwu.magisk.MagiskManager
;
import
java.io.BufferedInputStream
;
import
java.io.BufferedInputStream
;
...
@@ -16,8 +16,8 @@ import java.util.jar.JarInputStream;
...
@@ -16,8 +16,8 @@ import java.util.jar.JarInputStream;
public
class
ZipUtils
{
public
class
ZipUtils
{
// File name in assets
// File name in assets
private
static
final
String
PUBLIC_KEY_NAME
=
"public.certificate.x509.pem"
;
static
final
String
PUBLIC_KEY_NAME
=
"public.certificate.x509.pem"
;
private
static
final
String
PRIVATE_KEY_NAME
=
"private.key.pk8"
;
static
final
String
PRIVATE_KEY_NAME
=
"private.key.pk8"
;
static
{
static
{
System
.
loadLibrary
(
"zipadjust"
);
System
.
loadLibrary
(
"zipadjust"
);
...
...
jarsigner
/.gitignore
→
crypto
/.gitignore
View file @
05f41928
File moved
jarsigner
/build.gradle
→
crypto
/build.gradle
View file @
05f41928
...
@@ -8,13 +8,14 @@ targetCompatibility = "1.8"
...
@@ -8,13 +8,14 @@ targetCompatibility = "1.8"
jar
{
jar
{
manifest
{
manifest
{
attributes
'Main-Class'
:
'com.topjohnwu.
jarsigner.CommandLine
'
attributes
'Main-Class'
:
'com.topjohnwu.
crypto.ZipSigner
'
}
}
}
}
shadowJar
{
shadowJar
{
classifier
=
'fat'
baseName
=
'zipsigner'
version
=
null
classifier
=
null
version
=
1.0
}
}
buildscript
{
buildscript
{
...
...
jarsigner/src/main/java/com/topjohnwu/jarsigner
/ByteArrayStream.java
→
crypto/src/main/java/com/topjohnwu/crypto
/ByteArrayStream.java
View file @
05f41928
package
com
.
topjohnwu
.
jarsigner
;
package
com
.
topjohnwu
.
crypto
;
import
java.io.ByteArrayInputStream
;
import
java.io.ByteArrayInputStream
;
import
java.io.ByteArrayOutputStream
;
import
java.io.ByteArrayOutputStream
;
...
...
crypto/src/main/java/com/topjohnwu/crypto/CryptoUtils.java
0 → 100644
View file @
05f41928
package
com
.
topjohnwu
.
crypto
;
import
org.bouncycastle.asn1.ASN1InputStream
;
import
org.bouncycastle.asn1.ASN1ObjectIdentifier
;
import
org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers
;
import
org.bouncycastle.asn1.pkcs.PrivateKeyInfo
;
import
org.bouncycastle.asn1.x509.AlgorithmIdentifier
;
import
org.bouncycastle.asn1.x9.X9ObjectIdentifiers
;
import
java.io.ByteArrayInputStream
;
import
java.io.IOException
;
import
java.io.InputStream
;
import
java.security.GeneralSecurityException
;
import
java.security.Key
;
import
java.security.KeyFactory
;
import
java.security.PrivateKey
;
import
java.security.PublicKey
;
import
java.security.Signature
;
import
java.security.cert.CertificateFactory
;
import
java.security.cert.X509Certificate
;
import
java.security.spec.ECPrivateKeySpec
;
import
java.security.spec.ECPublicKeySpec
;
import
java.security.spec.InvalidKeySpecException
;
import
java.security.spec.PKCS8EncodedKeySpec
;
import
java.util.Arrays
;
import
java.util.HashMap
;
import
java.util.Map
;
class
CryptoUtils
{
private
static
final
Map
<
String
,
String
>
ID_TO_ALG
;
private
static
final
Map
<
String
,
String
>
ALG_TO_ID
;
static
{
ID_TO_ALG
=
new
HashMap
<>();
ALG_TO_ID
=
new
HashMap
<>();
ID_TO_ALG
.
put
(
X9ObjectIdentifiers
.
ecdsa_with_SHA256
.
getId
(),
"SHA256withECDSA"
);
ID_TO_ALG
.
put
(
X9ObjectIdentifiers
.
ecdsa_with_SHA384
.
getId
(),
"SHA384withECDSA"
);
ID_TO_ALG
.
put
(
X9ObjectIdentifiers
.
ecdsa_with_SHA512
.
getId
(),
"SHA512withECDSA"
);
ID_TO_ALG
.
put
(
PKCSObjectIdentifiers
.
sha1WithRSAEncryption
.
getId
(),
"SHA1withRSA"
);
ID_TO_ALG
.
put
(
PKCSObjectIdentifiers
.
sha256WithRSAEncryption
.
getId
(),
"SHA256withRSA"
);
ID_TO_ALG
.
put
(
PKCSObjectIdentifiers
.
sha512WithRSAEncryption
.
getId
(),
"SHA512withRSA"
);
ALG_TO_ID
.
put
(
"SHA256withECDSA"
,
X9ObjectIdentifiers
.
ecdsa_with_SHA256
.
getId
());
ALG_TO_ID
.
put
(
"SHA384withECDSA"
,
X9ObjectIdentifiers
.
ecdsa_with_SHA384
.
getId
());
ALG_TO_ID
.
put
(
"SHA512withECDSA"
,
X9ObjectIdentifiers
.
ecdsa_with_SHA512
.
getId
());
ALG_TO_ID
.
put
(
"SHA1withRSA"
,
PKCSObjectIdentifiers
.
sha1WithRSAEncryption
.
getId
());
ALG_TO_ID
.
put
(
"SHA256withRSA"
,
PKCSObjectIdentifiers
.
sha256WithRSAEncryption
.
getId
());
ALG_TO_ID
.
put
(
"SHA512withRSA"
,
PKCSObjectIdentifiers
.
sha512WithRSAEncryption
.
getId
());
}
private
static
String
getSignatureAlgorithm
(
Key
key
)
throws
Exception
{
if
(
"EC"
.
equals
(
key
.
getAlgorithm
()))
{
int
curveSize
;
KeyFactory
factory
=
KeyFactory
.
getInstance
(
"EC"
);
if
(
key
instanceof
PublicKey
)
{
ECPublicKeySpec
spec
=
factory
.
getKeySpec
(
key
,
ECPublicKeySpec
.
class
);
curveSize
=
spec
.
getParams
().
getCurve
().
getField
().
getFieldSize
();
}
else
if
(
key
instanceof
PrivateKey
)
{
ECPrivateKeySpec
spec
=
factory
.
getKeySpec
(
key
,
ECPrivateKeySpec
.
class
);
curveSize
=
spec
.
getParams
().
getCurve
().
getField
().
getFieldSize
();
}
else
{
throw
new
InvalidKeySpecException
();
}
if
(
curveSize
<=
256
)
{
return
"SHA256withECDSA"
;
}
else
if
(
curveSize
<=
384
)
{
return
"SHA384withECDSA"
;
}
else
{
return
"SHA512withECDSA"
;
}
}
else
if
(
"RSA"
.
equals
(
key
.
getAlgorithm
()))
{
return
"SHA256withRSA"
;
}
else
{
throw
new
IllegalArgumentException
(
"Unsupported key type "
+
key
.
getAlgorithm
());
}
}
static
AlgorithmIdentifier
getSignatureAlgorithmIdentifier
(
Key
key
)
throws
Exception
{
String
id
=
ALG_TO_ID
.
get
(
getSignatureAlgorithm
(
key
));
if
(
id
==
null
)
{
throw
new
IllegalArgumentException
(
"Unsupported key type "
+
key
.
getAlgorithm
());
}
return
new
AlgorithmIdentifier
(
new
ASN1ObjectIdentifier
(
id
));
}
static
boolean
verify
(
PublicKey
key
,
byte
[]
input
,
byte
[]
signature
,
AlgorithmIdentifier
algId
)
throws
Exception
{
String
algName
=
ID_TO_ALG
.
get
(
algId
.
getAlgorithm
().
getId
());
if
(
algName
==
null
)
{
throw
new
IllegalArgumentException
(
"Unsupported algorithm "
+
algId
.
getAlgorithm
());
}
Signature
verifier
=
Signature
.
getInstance
(
algName
);
verifier
.
initVerify
(
key
);
verifier
.
update
(
input
);
return
verifier
.
verify
(
signature
);
}
static
byte
[]
sign
(
PrivateKey
privateKey
,
byte
[]
input
)
throws
Exception
{
Signature
signer
=
Signature
.
getInstance
(
getSignatureAlgorithm
(
privateKey
));
signer
.
initSign
(
privateKey
);
signer
.
update
(
input
);
return
signer
.
sign
();
}
static
X509Certificate
readPublicKey
(
InputStream
input
)
throws
IOException
,
GeneralSecurityException
{
try
{
CertificateFactory
cf
=
CertificateFactory
.
getInstance
(
"X.509"
);
return
(
X509Certificate
)
cf
.
generateCertificate
(
input
);
}
finally
{
input
.
close
();
}
}
/** Read a PKCS#8 format private key. */
static
PrivateKey
readPrivateKey
(
InputStream
input
)
throws
IOException
,
GeneralSecurityException
{
try
{
byte
[]
buffer
=
new
byte
[
4096
];
int
size
=
input
.
read
(
buffer
);
byte
[]
bytes
=
Arrays
.
copyOf
(
buffer
,
size
);
/* Check to see if this is in an EncryptedPrivateKeyInfo structure. */
PKCS8EncodedKeySpec
spec
=
new
PKCS8EncodedKeySpec
(
bytes
);
/*
* Now it's in a PKCS#8 PrivateKeyInfo structure. Read its Algorithm
* OID and use that to construct a KeyFactory.
*/
ASN1InputStream
bIn
=
new
ASN1InputStream
(
new
ByteArrayInputStream
(
spec
.
getEncoded
()));
PrivateKeyInfo
pki
=
PrivateKeyInfo
.
getInstance
(
bIn
.
readObject
());
String
algOid
=
pki
.
getPrivateKeyAlgorithm
().
getAlgorithm
().
getId
();
return
KeyFactory
.
getInstance
(
algOid
).
generatePrivate
(
spec
);
}
finally
{
input
.
close
();
}
}
}
jarsigner/src/main/java/com/topjohnwu/jarsigner
/JarMap.java
→
crypto/src/main/java/com/topjohnwu/crypto
/JarMap.java
View file @
05f41928
package
com
.
topjohnwu
.
jarsigner
;
package
com
.
topjohnwu
.
crypto
;
import
java.io.Closeable
;
import
java.io.Closeable
;
import
java.io.File
;
import
java.io.File
;
...
...
jarsigner/src/main/java/com/topjohnwu/jarsigner
/SignAPK.java
→
crypto/src/main/java/com/topjohnwu/crypto
/SignAPK.java
View file @
05f41928
package
com
.
topjohnwu
.
jarsigner
;
package
com
.
topjohnwu
.
crypto
;
import
org.bouncycastle.asn1.ASN1InputStream
;
import
org.bouncycastle.asn1.ASN1InputStream
;
import
org.bouncycastle.asn1.ASN1ObjectIdentifier
;
import
org.bouncycastle.asn1.ASN1ObjectIdentifier
;
import
org.bouncycastle.asn1.DEROutputStream
;
import
org.bouncycastle.asn1.DEROutputStream
;
import
org.bouncycastle.asn1.cms.CMSObjectIdentifiers
;
import
org.bouncycastle.asn1.cms.CMSObjectIdentifiers
;
import
org.bouncycastle.asn1.pkcs.PrivateKeyInfo
;
import
org.bouncycastle.cert.jcajce.JcaCertStore
;
import
org.bouncycastle.cert.jcajce.JcaCertStore
;
import
org.bouncycastle.cms.CMSException
;
import
org.bouncycastle.cms.CMSException
;
import
org.bouncycastle.cms.CMSProcessableByteArray
;
import
org.bouncycastle.cms.CMSProcessableByteArray
;
...
@@ -20,7 +19,6 @@ import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder;
...
@@ -20,7 +19,6 @@ import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder;
import
org.bouncycastle.util.encoders.Base64
;
import
org.bouncycastle.util.encoders.Base64
;
import
java.io.BufferedOutputStream
;
import
java.io.BufferedOutputStream
;
import
java.io.ByteArrayInputStream
;
import
java.io.ByteArrayOutputStream
;
import
java.io.ByteArrayOutputStream
;
import
java.io.File
;
import
java.io.File
;
import
java.io.FileOutputStream
;
import
java.io.FileOutputStream
;
...
@@ -31,15 +29,12 @@ import java.io.OutputStream;
...
@@ -31,15 +29,12 @@ import java.io.OutputStream;
import
java.io.PrintStream
;
import
java.io.PrintStream
;
import
java.security.DigestOutputStream
;
import
java.security.DigestOutputStream
;
import
java.security.GeneralSecurityException
;
import
java.security.GeneralSecurityException
;
import
java.security.KeyFactory
;
import
java.security.MessageDigest
;
import
java.security.MessageDigest
;
import
java.security.PrivateKey
;
import
java.security.PrivateKey
;
import
java.security.Provider
;
import
java.security.Provider
;
import
java.security.Security
;
import
java.security.Security
;
import
java.security.cert.CertificateEncodingException
;
import
java.security.cert.CertificateEncodingException
;
import
java.security.cert.CertificateFactory
;
import
java.security.cert.X509Certificate
;
import
java.security.cert.X509Certificate
;
import
java.security.spec.PKCS8EncodedKeySpec
;
import
java.util.ArrayList
;
import
java.util.ArrayList
;
import
java.util.Arrays
;
import
java.util.Arrays
;
import
java.util.Collections
;
import
java.util.Collections
;
...
@@ -69,8 +64,8 @@ public class SignAPK {
...
@@ -69,8 +64,8 @@ public class SignAPK {
private
static
final
int
USE_SHA256
=
2
;
private
static
final
int
USE_SHA256
=
2
;
static
{
static
{
SignAPK
.
sBouncyCastleProvider
=
new
BouncyCastleProvider
();
sBouncyCastleProvider
=
new
BouncyCastleProvider
();
Security
.
insertProviderAt
(
SignAPK
.
sBouncyCastleProvider
,
1
);
Security
.
insertProviderAt
(
sBouncyCastleProvider
,
1
);
}
}
public
static
void
signZip
(
InputStream
publicIn
,
InputStream
privateIn
,
public
static
void
signZip
(
InputStream
publicIn
,
InputStream
privateIn
,
...
@@ -78,14 +73,14 @@ public class SignAPK {
...
@@ -78,14 +73,14 @@ public class SignAPK {
int
alignment
=
4
;
int
alignment
=
4
;
BufferedOutputStream
outputFile
;
BufferedOutputStream
outputFile
;
int
hashes
=
0
;
int
hashes
=
0
;
X509Certificate
publicKey
=
readPublicKey
(
publicIn
);
X509Certificate
publicKey
=
CryptoUtils
.
readPublicKey
(
publicIn
);
hashes
|=
getDigestAlgorithm
(
publicKey
);
hashes
|=
getDigestAlgorithm
(
publicKey
);
// Set the ZIP file timestamp to the starting valid time
// Set the ZIP file timestamp to the starting valid time
// of the 0th certificate plus one hour (to match what
// of the 0th certificate plus one hour (to match what
// we've historically done).
// we've historically done).
long
timestamp
=
publicKey
.
getNotBefore
().
getTime
()
+
3600L
*
1000
;
long
timestamp
=
publicKey
.
getNotBefore
().
getTime
()
+
3600L
*
1000
;
PrivateKey
privateKey
=
readPrivateKey
(
privateIn
);
PrivateKey
privateKey
=
CryptoUtils
.
readPrivateKey
(
privateIn
);
outputFile
=
new
BufferedOutputStream
(
new
FileOutputStream
(
output
));
outputFile
=
new
BufferedOutputStream
(
new
FileOutputStream
(
output
));
if
(
minSign
)
{
if
(
minSign
)
{
...
@@ -144,37 +139,7 @@ public class SignAPK {
...
@@ -144,37 +139,7 @@ public class SignAPK {
private
static
Pattern
stripPattern
=
private
static
Pattern
stripPattern
=
Pattern
.
compile
(
"^(META-INF/((.*)[.](SF|RSA|DSA|EC)|com/android/otacert))|("
+
Pattern
.
compile
(
"^(META-INF/((.*)[.](SF|RSA|DSA|EC)|com/android/otacert))|("
+
Pattern
.
quote
(
JarFile
.
MANIFEST_NAME
)
+
")$"
);
Pattern
.
quote
(
JarFile
.
MANIFEST_NAME
)
+
")$"
);
private
static
X509Certificate
readPublicKey
(
InputStream
input
)
throws
IOException
,
GeneralSecurityException
{
try
{
CertificateFactory
cf
=
CertificateFactory
.
getInstance
(
"X.509"
);
return
(
X509Certificate
)
cf
.
generateCertificate
(
input
);
}
finally
{
input
.
close
();
}
}
/** Read a PKCS#8 format private key. */
private
static
PrivateKey
readPrivateKey
(
InputStream
input
)
throws
IOException
,
GeneralSecurityException
{
try
{
byte
[]
buffer
=
new
byte
[
4096
];
int
size
=
input
.
read
(
buffer
);
byte
[]
bytes
=
Arrays
.
copyOf
(
buffer
,
size
);
/* Check to see if this is in an EncryptedPrivateKeyInfo structure. */
PKCS8EncodedKeySpec
spec
=
new
PKCS8EncodedKeySpec
(
bytes
);
/*
* Now it's in a PKCS#8 PrivateKeyInfo structure. Read its Algorithm
* OID and use that to construct a KeyFactory.
*/
ASN1InputStream
bIn
=
new
ASN1InputStream
(
new
ByteArrayInputStream
(
spec
.
getEncoded
()));
PrivateKeyInfo
pki
=
PrivateKeyInfo
.
getInstance
(
bIn
.
readObject
());
String
algOid
=
pki
.
getPrivateKeyAlgorithm
().
getAlgorithm
().
getId
();
return
KeyFactory
.
getInstance
(
algOid
).
generatePrivate
(
spec
);
}
finally
{
input
.
close
();
}
}
/**
/**
* Add the hash(es) of every file to the manifest, creating it if
* Add the hash(es) of every file to the manifest, creating it if
* necessary.
* necessary.
...
...
crypto/src/main/java/com/topjohnwu/crypto/SignBoot.java
0 → 100644
View file @
05f41928
package
com
.
topjohnwu
.
crypto
;
import
org.bouncycastle.asn1.ASN1Encodable
;
import
org.bouncycastle.asn1.ASN1EncodableVector
;
import
org.bouncycastle.asn1.ASN1InputStream
;
import
org.bouncycastle.asn1.ASN1Integer
;
import
org.bouncycastle.asn1.ASN1Object
;
import
org.bouncycastle.asn1.ASN1ObjectIdentifier
;
import
org.bouncycastle.asn1.ASN1Primitive
;
import
org.bouncycastle.asn1.ASN1Sequence
;
import
org.bouncycastle.asn1.DEROctetString
;
import
org.bouncycastle.asn1.DERPrintableString
;
import
org.bouncycastle.asn1.DERSequence
;
import
org.bouncycastle.asn1.x509.AlgorithmIdentifier
;
import
org.bouncycastle.jce.provider.BouncyCastleProvider
;
import
java.io.ByteArrayInputStream
;
import
java.io.FileInputStream
;
import
java.io.FileOutputStream
;
import
java.io.IOException
;
import
java.io.InputStream
;
import
java.io.OutputStream
;
import
java.nio.ByteBuffer
;
import
java.nio.ByteOrder
;
import
java.security.PrivateKey
;
import
java.security.PublicKey
;
import
java.security.Security
;
import
java.security.cert.CertificateEncodingException
;
import
java.security.cert.CertificateFactory
;
import
java.security.cert.X509Certificate
;
import
java.util.Arrays
;
public
class
SignBoot
{
static
{
Security
.
addProvider
(
new
BouncyCastleProvider
());
}
public
static
void
doSignature
(
String
target
,
String
imagePath
,
String
outPath
,
InputStream
keyIn
,
InputStream
certIn
)
throws
Exception
{
doSignature
(
target
,
new
FileInputStream
(
imagePath
),
new
FileOutputStream
(
outPath
),
keyIn
,
certIn
);
}
public
static
void
doSignature
(
String
target
,
InputStream
imgIn
,
OutputStream
imgOut
,
InputStream
keyIn
,
InputStream
certIn
)
throws
Exception
{
ByteArrayStream
bas
=
new
ByteArrayStream
();
bas
.
readFrom
(
imgIn
);
byte
[]
image
=
bas
.
toByteArray
();
bas
.
close
();
imgIn
.
close
();
int
signableSize
=
getSignableImageSize
(
image
);
if
(
signableSize
<
image
.
length
)
{
System
.
err
.
println
(
"NOTE: truncating input from "
+
image
.
length
+
" to "
+
signableSize
+
" bytes"
);
image
=
Arrays
.
copyOf
(
image
,
signableSize
);
}
else
if
(
signableSize
>
image
.
length
)
{
throw
new
IllegalArgumentException
(
"Invalid image: too short, expected "
+
signableSize
+
" bytes"
);
}
BootSignature
bootsig
=
new
BootSignature
(
target
,
image
.
length
);
X509Certificate
cert
=
CryptoUtils
.
readPublicKey
(
certIn
);
bootsig
.
setCertificate
(
cert
);
PrivateKey
key
=
CryptoUtils
.
readPrivateKey
(
keyIn
);
bootsig
.
setSignature
(
bootsig
.
sign
(
image
,
key
),
CryptoUtils
.
getSignatureAlgorithmIdentifier
(
key
));
byte
[]
encoded_bootsig
=
bootsig
.
getEncoded
();
imgOut
.
write
(
image
);
imgOut
.
write
(
encoded_bootsig
);
imgOut
.
flush
();
imgOut
.
close
();
}
public
static
boolean
verifySignature
(
String
imagePath
,
InputStream
certPath
)
throws
Exception
{
ByteArrayStream
bas
=
new
ByteArrayStream
();
bas
.
readFrom
(
new
FileInputStream
(
imagePath
));
byte
[]
image
=
bas
.
toByteArray
();
bas
.
close
();
int
signableSize
=
getSignableImageSize
(
image
);
if
(
signableSize
>=
image
.
length
)
{
System
.
err
.
println
(
"Invalid image: not signed"
);
return
false
;
}
byte
[]
signature
=
Arrays
.
copyOfRange
(
image
,
signableSize
,
image
.
length
);
BootSignature
bootsig
=
new
BootSignature
(
signature
);
if
(
certPath
!=
null
)
{
bootsig
.
setCertificate
(
CryptoUtils
.
readPublicKey
(
certPath
));
}
try
{
if
(
bootsig
.
verify
(
Arrays
.
copyOf
(
image
,
signableSize
)))
{
System
.
err
.
println
(
"Signature is VALID"
);
return
true
;
}
else
{
System
.
err
.
println
(
"Signature is INVALID"
);
}
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
}
return
false
;
}
public
static
int
getSignableImageSize
(
byte
[]
data
)
throws
Exception
{
if
(!
Arrays
.
equals
(
Arrays
.
copyOfRange
(
data
,
0
,
8
),
"ANDROID!"
.
getBytes
(
"US-ASCII"
)))
{
throw
new
IllegalArgumentException
(
"Invalid image header: missing magic"
);
}
ByteBuffer
image
=
ByteBuffer
.
wrap
(
data
);
image
.
order
(
ByteOrder
.
LITTLE_ENDIAN
);
image
.
getLong
();
// magic
int
kernelSize
=
image
.
getInt
();
image
.
getInt
();
// kernel_addr
int
ramdskSize
=
image
.
getInt
();
image
.
getInt
();
// ramdisk_addr
int
secondSize
=
image
.
getInt
();
image
.
getLong
();
// second_addr + tags_addr
int
pageSize
=
image
.
getInt
();
int
length
=
pageSize
// include the page aligned image header
+
((
kernelSize
+
pageSize
-
1
)
/
pageSize
)
*
pageSize
+
((
ramdskSize
+
pageSize
-
1
)
/
pageSize
)
*
pageSize
+
((
secondSize
+
pageSize
-
1
)
/
pageSize
)
*
pageSize
;
length
=
((
length
+
pageSize
-
1
)
/
pageSize
)
*
pageSize
;
if
(
length
<=
0
)
{
throw
new
IllegalArgumentException
(
"Invalid image header: invalid length"
);
}
return
length
;
}
static
class
BootSignature
extends
ASN1Object
{
private
ASN1Integer
formatVersion
;
private
ASN1Encodable
certificate
;
private
AlgorithmIdentifier
algorithmIdentifier
;
private
DERPrintableString
target
;
private
ASN1Integer
length
;
private
DEROctetString
signature
;
private
PublicKey
publicKey
;
private
static
final
int
FORMAT_VERSION
=
1
;
/**
* Initializes the object for signing an image file
* @param target Target name, included in the signed data
* @param length Length of the image, included in the signed data
*/
public
BootSignature
(
String
target
,
int
length
)
{
this
.
formatVersion
=
new
ASN1Integer
(
FORMAT_VERSION
);
this
.
target
=
new
DERPrintableString
(
target
);
this
.
length
=
new
ASN1Integer
(
length
);
}
/**
* Initializes the object for verifying a signed image file
* @param signature Signature footer
*/
public
BootSignature
(
byte
[]
signature
)
throws
Exception
{
ASN1InputStream
stream
=
new
ASN1InputStream
(
signature
);
ASN1Sequence
sequence
=
(
ASN1Sequence
)
stream
.
readObject
();
formatVersion
=
(
ASN1Integer
)
sequence
.
getObjectAt
(
0
);
if
(
formatVersion
.
getValue
().
intValue
()
!=
FORMAT_VERSION
)
{
throw
new
IllegalArgumentException
(
"Unsupported format version"
);
}
certificate
=
sequence
.
getObjectAt
(
1
);
byte
[]
encoded
=
((
ASN1Object
)
certificate
).
getEncoded
();
ByteArrayInputStream
bis
=
new
ByteArrayInputStream
(
encoded
);
CertificateFactory
cf
=
CertificateFactory
.
getInstance
(
"X.509"
);
X509Certificate
c
=
(
X509Certificate
)
cf
.
generateCertificate
(
bis
);
publicKey
=
c
.
getPublicKey
();
ASN1Sequence
algId
=
(
ASN1Sequence
)
sequence
.
getObjectAt
(
2
);
algorithmIdentifier
=
new
AlgorithmIdentifier
(
(
ASN1ObjectIdentifier
)
algId
.
getObjectAt
(
0
));
ASN1Sequence
attrs
=
(
ASN1Sequence
)
sequence
.
getObjectAt
(
3
);
target
=
(
DERPrintableString
)
attrs
.
getObjectAt
(
0
);
length
=
(
ASN1Integer
)
attrs
.
getObjectAt
(
1
);
this
.
signature
=
(
DEROctetString
)
sequence
.
getObjectAt
(
4
);
}
public
ASN1Object
getAuthenticatedAttributes
()
{
ASN1EncodableVector
attrs
=
new
ASN1EncodableVector
();
attrs
.
add
(
target
);
attrs
.
add
(
length
);
return
new
DERSequence
(
attrs
);
}
public
byte
[]
getEncodedAuthenticatedAttributes
()
throws
IOException
{
return
getAuthenticatedAttributes
().
getEncoded
();
}
public
void
setSignature
(
byte
[]
sig
,
AlgorithmIdentifier
algId
)
{
algorithmIdentifier
=
algId
;
signature
=
new
DEROctetString
(
sig
);
}
public
void
setCertificate
(
X509Certificate
cert
)
throws
Exception
,
IOException
,
CertificateEncodingException
{
ASN1InputStream
s
=
new
ASN1InputStream
(
cert
.
getEncoded
());
certificate
=
s
.
readObject
();
publicKey
=
cert
.
getPublicKey
();
}
public
byte
[]
generateSignableImage
(
byte
[]
image
)
throws
IOException
{
byte
[]
attrs
=
getEncodedAuthenticatedAttributes
();
byte
[]
signable
=
Arrays
.
copyOf
(
image
,
image
.
length
+
attrs
.
length
);
for
(
int
i
=
0
;
i
<
attrs
.
length
;
i
++)
{
signable
[
i
+
image
.
length
]
=
attrs
[
i
];
}
return
signable
;
}
public
byte
[]
sign
(
byte
[]
image
,
PrivateKey
key
)
throws
Exception
{
byte
[]
signable
=
generateSignableImage
(
image
);
return
CryptoUtils
.
sign
(
key
,
signable
);
}
public
boolean
verify
(
byte
[]
image
)
throws
Exception
{
if
(
length
.
getValue
().
intValue
()
!=
image
.
length
)
{
throw
new
IllegalArgumentException
(
"Invalid image length"
);
}
byte
[]
signable
=
generateSignableImage
(
image
);
return
CryptoUtils
.
verify
(
publicKey
,
signable
,
signature
.
getOctets
(),
algorithmIdentifier
);
}
@Override
public
ASN1Primitive
toASN1Primitive
()
{
ASN1EncodableVector
v
=
new
ASN1EncodableVector
();
v
.
add
(
formatVersion
);
v
.
add
(
certificate
);
v
.
add
(
algorithmIdentifier
);
v
.
add
(
getAuthenticatedAttributes
());
v
.
add
(
signature
);
return
new
DERSequence
(
v
);
}
}
}
jarsigner/src/main/java/com/topjohnwu/jarsigner/CommandLine
.java
→
crypto/src/main/java/com/topjohnwu/crypto/ZipSigner
.java
View file @
05f41928
package
com
.
topjohnwu
.
jarsigner
;
package
com
.
topjohnwu
.
crypto
;
import
org.bouncycastle.jce.provider.BouncyCastleProvider
;
import
org.bouncycastle.jce.provider.BouncyCastleProvider
;
...
@@ -7,7 +7,7 @@ import java.io.FileInputStream;
...
@@ -7,7 +7,7 @@ import java.io.FileInputStream;
import
java.io.InputStream
;
import
java.io.InputStream
;
import
java.security.Security
;
import
java.security.Security
;
public
class
CommandLine
{
public
class
ZipSigner
{
public
static
void
main
(
String
[]
args
)
{
public
static
void
main
(
String
[]
args
)
{
boolean
minSign
=
false
;
boolean
minSign
=
false
;
int
argStart
=
0
;
int
argStart
=
0
;
...
...
settings.gradle
View file @
05f41928
include
':app'
,
':snet'
,
':jarsigner'
include
':app'
,
':snet'
,
':crypto'
\ No newline at end of file
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment