Advertisement
Guest User

Untitled

a guest
Aug 18th, 2020
130
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Ruby 4.81 KB | None | 0 0
  1. #!/usr/bin/env ruby
  2. #
  3. # Copyright (c) 2017 Jens Kuske <jenskuske@gmail.com>
  4. #
  5. # This program is free software; you can redistribute it and/or
  6. # modify it under the terms of the GNU General Public License
  7. # as published by the Free Software Foundation; either version 2
  8. # of the License, or (at your option) any later version.
  9. #
  10. # This program is distributed in the hope that it will be useful,
  11. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13. # GNU General Public License for more details.
  14. #
  15. #
  16. # Usage example:
  17. #
  18. # $ openssl genrsa -out privkey.pem 2048
  19. #
  20. # $ mktoc0 privkey.pem sunxi-spl.bin output.img
  21. # $ dd if=output.img of=/dev/sdX bs=1024 seek=8
  22. #
  23. require 'openssl'
  24.  
  25. class RawASN1
  26.     def initialize(type, value)
  27.         @type = type
  28.         @value = value
  29.     end
  30.  
  31.     def to_der
  32.         if @value.length < 128
  33.             [ @type, @value.length ].pack('CC') + @value
  34.         elsif @value.length < 256
  35.             [ @type, 0x81, @value.length ].pack('CCC') + @value
  36.         else
  37.             [ @type, 0x82, @value.length ].pack('CCn') + @value
  38.         end
  39.     end
  40. end
  41.  
  42. class Certificate < OpenSSL::ASN1::Sequence
  43.     def initialize(key, hash)
  44.         certificate = TBSCertificate(key.public_key, hash)
  45.         signature = Signature(sign(key, certificate.to_der[0...-4]))
  46.         super( [ certificate, signature ] )
  47.     end
  48.  
  49.     private
  50.  
  51.     def AlgorithmIdentifier(algorithm)
  52.         algorithm = OpenSSL::ASN1::ObjectId.new(algorithm)
  53.         parameters = OpenSSL::ASN1::Null.new(nil)
  54.         OpenSSL::ASN1::Sequence.new( [ algorithm, parameters ] )
  55.     end
  56.  
  57.     def SubjectPublicKeyInfo(n, e)
  58.         algorithm = AlgorithmIdentifier('rsaEncryption')
  59.         n = RawASN1.new(OpenSSL::ASN1::INTEGER, [n.to_s(16)].pack('H*'))
  60.         e = RawASN1.new(OpenSSL::ASN1::INTEGER, [e.to_s(16)].pack('H*'))
  61.         subjectPublicKey = OpenSSL::ASN1::Sequence.new( [ n, e ] )
  62.         OpenSSL::ASN1::Sequence.new( [ algorithm, subjectPublicKey ] )
  63.     end
  64.  
  65.     def Payload(hash)
  66.         hash = RawASN1.new(OpenSSL::ASN1::INTEGER, hash)
  67.         OpenSSL::ASN1::Sequence.new( [ hash ], 3, :EXPLICIT)
  68.     end
  69.  
  70.     def TBSCertificate(pubkey, hash)
  71.         version = OpenSSL::ASN1::Integer.new(2, 0, :EXPLICIT)
  72.         serial = OpenSSL::ASN1::Integer.new(2)
  73.         signature = AlgorithmIdentifier('sha256WithRSAEncryption')
  74.         issuer = OpenSSL::ASN1::Sequence.new( [] )
  75.         validity = OpenSSL::ASN1::Sequence.new( [] )
  76.         subject = OpenSSL::ASN1::Sequence.new( [] )
  77.         subjectPublicKeyInfo = SubjectPublicKeyInfo(pubkey.params['n'], pubkey.params['e'])
  78.         payload = Payload(hash)
  79.  
  80.         OpenSSL::ASN1::Sequence.new( [ version, serial, signature, issuer, validity, subject, subjectPublicKeyInfo, payload ] )
  81.     end
  82.  
  83.     def sign(key, data)
  84.         hash = OpenSSL::Digest::SHA256.digest(data).rjust(256, "\0")
  85.         key.private_encrypt(hash, OpenSSL::PKey::RSA::NO_PADDING)
  86.     end
  87.  
  88.     def Signature(signature)
  89.         signatureAlgorithm = AlgorithmIdentifier('rsassaPss')
  90.         signatureValue = RawASN1.new(OpenSSL::ASN1::BIT_STRING, signature)
  91.         signature = signatureAlgorithm.to_der + signatureValue.to_der
  92.         RawASN1.new(OpenSSL::ASN1::BIT_STRING, signature)
  93.     end
  94. end
  95.  
  96. def align(value, alignment)
  97.     (value + alignment - 1) & ~(alignment - 1)
  98. end
  99.  
  100. class TOC0Item
  101.     CERTIFICATE = 1
  102.     CODE = 2
  103.  
  104.     def initialize(id, data, type, run_addr = 0)
  105.         @id = id
  106.         @data = data
  107.         @type = type
  108.         @run_addr = run_addr
  109.     end
  110.  
  111.     def get_header(offset)
  112.         [ @id, offset, @data.length, 0, @type, @run_addr, 0, 'IIE;' ].pack('V7a4')
  113.     end
  114.  
  115.     def get_data
  116.         @data.ljust(align(@data.length, 32), "\0")
  117.     end
  118. end
  119.  
  120. class TOC0
  121.     def initialize(items)
  122.         @items = items
  123.     end
  124.  
  125.     def to_s
  126.         header_len = align(48 + @items.length * 32, 32)
  127.         headers = ''
  128.         data = ''
  129.  
  130.         @items.each do |item|
  131.             headers << item.get_header(header_len + data.length)
  132.             data << item.get_data()
  133.         end
  134.  
  135.         total_length = align(header_len + data.length, 16 * 1024)
  136.  
  137.         main_header = pack_header(@items.length, total_length)
  138.  
  139. #       checksum = (main_header + headers + data).unpack('V*').sum % 2 ** 32
  140.         checksum = (main_header + headers + data).unpack('V*').reduce(:+) % 2 ** 32
  141.         main_header = pack_header(@items.length, total_length, checksum)
  142.  
  143.         headers = (main_header + headers).ljust(header_len, "\0")
  144.         (headers + data).ljust(total_length, "\0")
  145.     end
  146.  
  147.     private
  148.  
  149.     def pack_header(num_items, length, checksum = 0x5F0A6C39)
  150.         [ 'TOC0.GLH', 0x89119800, checksum, 0, 0, num_items, length, 0, 0, 0, 'MIE;' ].pack('a8V9a4')
  151.     end
  152. end
  153.  
  154.  
  155.  
  156. if ARGV.length < 3
  157.     puts "Usage: #{$PROGRAM_NAME} key_file input_file output_file"
  158.     exit false
  159. end
  160.  
  161. key = OpenSSL::PKey::RSA.new(File.read(ARGV[0]))
  162. code = File.binread(ARGV[1])
  163.  
  164. cert = Certificate.new(key, OpenSSL::Digest::SHA256.digest(code))
  165.  
  166. toc0_cert = TOC0Item.new(0x010101, cert.to_der, TOC0Item::CERTIFICATE)
  167. toc0_code = TOC0Item.new(0x010202, code, TOC0Item::CODE, 0x00020000)
  168.  
  169. toc0 = TOC0.new( [ toc0_cert, toc0_code ] )
  170.  
  171. File.binwrite(ARGV[2], toc0.to_s)
  172.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement