mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Update fastlane decryption
This commit is contained in:
parent
38a5a886c8
commit
9bb5be209f
@ -104,11 +104,16 @@ def decrypt_codesigning_directory_recursively(source_base_path, destination_base
|
|||||||
source_path = source_base_path + '/' + file_name
|
source_path = source_base_path + '/' + file_name
|
||||||
destination_path = destination_base_path + '/' + file_name
|
destination_path = destination_base_path + '/' + file_name
|
||||||
if os.path.isfile(source_path):
|
if os.path.isfile(source_path):
|
||||||
os.system('openssl aes-256-cbc -md md5 -k "{password}" -in "{source_path}" -out "{destination_path}" -a -d 2>/dev/null'.format(
|
os.system('ruby build-system/decrypt.rb "{password}" "{source_path}" "{destination_path}"'.format(
|
||||||
password=password,
|
password=password,
|
||||||
source_path=source_path,
|
source_path=source_path,
|
||||||
destination_path=destination_path
|
destination_path=destination_path
|
||||||
))
|
))
|
||||||
|
'''os.system('openssl aes-256-cbc -md md5 -k "{password}" -in "{source_path}" -out "{destination_path}" -a -d 2>/dev/null'.format(
|
||||||
|
password=password,
|
||||||
|
source_path=source_path,
|
||||||
|
destination_path=destination_path
|
||||||
|
))'''
|
||||||
elif os.path.isdir(source_path):
|
elif os.path.isdir(source_path):
|
||||||
os.makedirs(destination_path, exist_ok=True)
|
os.makedirs(destination_path, exist_ok=True)
|
||||||
decrypt_codesigning_directory_recursively(source_path, destination_path, password)
|
decrypt_codesigning_directory_recursively(source_path, destination_path, password)
|
||||||
|
156
build-system/decrypt.rb
Normal file
156
build-system/decrypt.rb
Normal file
@ -0,0 +1,156 @@
|
|||||||
|
require 'base64'
|
||||||
|
require 'openssl'
|
||||||
|
require 'securerandom'
|
||||||
|
|
||||||
|
class EncryptionV1
|
||||||
|
ALGORITHM = 'aes-256-cbc'
|
||||||
|
|
||||||
|
def encrypt(data:, password:, salt:, hash_algorithm: "MD5")
|
||||||
|
cipher = ::OpenSSL::Cipher.new(ALGORITHM)
|
||||||
|
cipher.encrypt
|
||||||
|
|
||||||
|
keyivgen(cipher, password, salt, hash_algorithm)
|
||||||
|
|
||||||
|
encrypted_data = cipher.update(data)
|
||||||
|
encrypted_data << cipher.final
|
||||||
|
{ encrypted_data: encrypted_data }
|
||||||
|
end
|
||||||
|
|
||||||
|
def decrypt(encrypted_data:, password:, salt:, hash_algorithm: "MD5")
|
||||||
|
cipher = ::OpenSSL::Cipher.new(ALGORITHM)
|
||||||
|
cipher.decrypt
|
||||||
|
|
||||||
|
keyivgen(cipher, password, salt, hash_algorithm)
|
||||||
|
|
||||||
|
data = cipher.update(encrypted_data)
|
||||||
|
data << cipher.final
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def keyivgen(cipher, password, salt, hash_algorithm)
|
||||||
|
cipher.pkcs5_keyivgen(password, salt, 1, hash_algorithm)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# The newer encryption mechanism, which features a more secure key and IV generation.
|
||||||
|
#
|
||||||
|
# The IV is randomly generated and provided unencrypted.
|
||||||
|
# The salt should be randomly generated and provided unencrypted (like in the current implementation).
|
||||||
|
# The key is generated with OpenSSL::KDF::pbkdf2_hmac with properly chosen parameters.
|
||||||
|
#
|
||||||
|
# Short explanation about salt and IV: https://stackoverflow.com/a/1950674/6324550
|
||||||
|
class EncryptionV2
|
||||||
|
ALGORITHM = 'aes-256-gcm'
|
||||||
|
|
||||||
|
def encrypt(data:, password:, salt:)
|
||||||
|
cipher = ::OpenSSL::Cipher.new(ALGORITHM)
|
||||||
|
cipher.encrypt
|
||||||
|
|
||||||
|
keyivgen(cipher, password, salt)
|
||||||
|
|
||||||
|
encrypted_data = cipher.update(data)
|
||||||
|
encrypted_data << cipher.final
|
||||||
|
|
||||||
|
auth_tag = cipher.auth_tag
|
||||||
|
|
||||||
|
{ encrypted_data: encrypted_data, auth_tag: auth_tag }
|
||||||
|
end
|
||||||
|
|
||||||
|
def decrypt(encrypted_data:, password:, salt:, auth_tag:)
|
||||||
|
cipher = ::OpenSSL::Cipher.new(ALGORITHM)
|
||||||
|
cipher.decrypt
|
||||||
|
|
||||||
|
keyivgen(cipher, password, salt)
|
||||||
|
|
||||||
|
cipher.auth_tag = auth_tag
|
||||||
|
|
||||||
|
data = cipher.update(encrypted_data)
|
||||||
|
data << cipher.final
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def keyivgen(cipher, password, salt)
|
||||||
|
keyIv = ::OpenSSL::KDF.pbkdf2_hmac(password, salt: salt, iterations: 10_000, length: 32 + 12 + 24, hash: "sha256")
|
||||||
|
key = keyIv[0..31]
|
||||||
|
iv = keyIv[32..43]
|
||||||
|
auth_data = keyIv[44..-1]
|
||||||
|
cipher.key = key
|
||||||
|
cipher.iv = iv
|
||||||
|
cipher.auth_data = auth_data
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class MatchDataEncryption
|
||||||
|
V1_PREFIX = "Salted__"
|
||||||
|
V2_PREFIX = "match_encrypted_v2__"
|
||||||
|
|
||||||
|
def encrypt(data:, password:, version: 2)
|
||||||
|
salt = SecureRandom.random_bytes(8)
|
||||||
|
if version == 2
|
||||||
|
e = EncryptionV2.new
|
||||||
|
encryption = e.encrypt(data: data, password: password, salt: salt)
|
||||||
|
encrypted_data = V2_PREFIX + salt + encryption[:auth_tag] + encryption[:encrypted_data]
|
||||||
|
else
|
||||||
|
e = EncryptionV1.new
|
||||||
|
encryption = e.encrypt(data: data, password: password, salt: salt)
|
||||||
|
encrypted_data = V1_PREFIX + salt + encryption[:encrypted_data]
|
||||||
|
end
|
||||||
|
Base64.encode64(encrypted_data)
|
||||||
|
end
|
||||||
|
|
||||||
|
def decrypt(base64encoded_encrypted:, password:)
|
||||||
|
stored_data = Base64.decode64(base64encoded_encrypted)
|
||||||
|
if stored_data.start_with?(V2_PREFIX)
|
||||||
|
salt = stored_data[20..27]
|
||||||
|
auth_tag = stored_data[28..43]
|
||||||
|
data_to_decrypt = stored_data[44..-1]
|
||||||
|
|
||||||
|
e = EncryptionV2.new
|
||||||
|
e.decrypt(encrypted_data: data_to_decrypt, password: password, salt: salt, auth_tag: auth_tag)
|
||||||
|
else
|
||||||
|
salt = stored_data[8..15]
|
||||||
|
data_to_decrypt = stored_data[16..-1]
|
||||||
|
e = EncryptionV1.new
|
||||||
|
begin
|
||||||
|
# Note that we are not guaranteed to catch the decryption errors here if the password or the hash is wrong
|
||||||
|
# as there's no integrity checks.
|
||||||
|
# see https://github.com/fastlane/fastlane/issues/21663
|
||||||
|
e.decrypt(encrypted_data: data_to_decrypt, password: password, salt: salt)
|
||||||
|
# With the wrong hash_algorithm, there's here 0.4% chance that the decryption failure will go undetected
|
||||||
|
rescue => _ex
|
||||||
|
# With a wrong password, there's a 0.4% chance it will decrypt garbage and not fail
|
||||||
|
fallback_hash_algorithm = "SHA256"
|
||||||
|
e.decrypt(encrypted_data: data_to_decrypt, password: password, salt: salt, hash_algorithm: fallback_hash_algorithm)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
class MatchFileEncryption
|
||||||
|
def encrypt(file_path:, password:, output_path: nil)
|
||||||
|
output_path = file_path unless output_path
|
||||||
|
data_to_encrypt = File.binread(file_path)
|
||||||
|
e = MatchDataEncryption.new
|
||||||
|
data = e.encrypt(data: data_to_encrypt, password: password)
|
||||||
|
File.write(output_path, data)
|
||||||
|
end
|
||||||
|
|
||||||
|
def decrypt(file_path:, password:, output_path: nil)
|
||||||
|
output_path = file_path unless output_path
|
||||||
|
content = File.read(file_path)
|
||||||
|
e = MatchDataEncryption.new
|
||||||
|
decrypted_data = e.decrypt(base64encoded_encrypted: content, password: password)
|
||||||
|
File.binwrite(output_path, decrypted_data)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
if ARGV.length != 3
|
||||||
|
print 'Invalid command line'
|
||||||
|
else
|
||||||
|
dec = MatchFileEncryption.new
|
||||||
|
dec.decrypt(file_path: ARGV[1], password: ARGV[0], output_path: ARGV[2])
|
||||||
|
end
|
Loading…
x
Reference in New Issue
Block a user