Class: Virgil::Crypto::VirgilCrypto

Inherits:
Object
  • Object
show all
Defined in:
lib/virgil/crypto/virgil_crypto.rb

Overview

Wrapper for cryptographic operations.

Class provides a cryptographic operations in applications, such as hashing, signature generation and verification, key creation, import and export key, encryption and decryption.

Constant Summary collapse

CUSTOM_PARAM_KEY_SIGNATURE =
Bytes.from_string(
  'VIRGIL-DATA-SIGNATURE'
)
CUSTOM_PARAM_KEY_SIGNER_ID =
Bytes.from_string(
  'VIRGIL-DATA-SIGNER-ID'
)

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(key_pair_type: KeyPairType::Default) ⇒ VirgilCrypto

Returns a new instance of VirgilCrypto.

[View source]

46
47
48
# File 'lib/virgil/crypto/virgil_crypto.rb', line 46

def initialize(key_pair_type: KeyPairType::Default)
  @default_key_type = key_pair_type
end

Instance Attribute Details

#use_SHA256_fingerprintsObject

Returns the value of attribute use_SHA256_fingerprints.


44
45
46
# File 'lib/virgil/crypto/virgil_crypto.rb', line 44

def use_SHA256_fingerprints
  @use_SHA256_fingerprints
end

Instance Method Details

#decrypt(cipher_bytes, private_key) ⇒ Bytes

Decrypts the specified bytes using Private key.

Examples:

# You can decrypt data using your private key
include Virgil::Crypto
crypto = VirgilCrypto.new
alice_keys = crypto.generate_keys
plain_data = crypto.decrypt(cipher_data, alice_keys.private_key)

Parameters:

  • cipher_bytes (Bytes)

    encrypted data bytes for decryption.

  • private_key (VirgilPrivateKey)

    private key for decryption.

Returns:

  • (Bytes)

    Decrypted data bytes.

See Also:

[View source]

271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
# File 'lib/virgil/crypto/virgil_crypto.rb', line 271

def decrypt(cipher_bytes, private_key)
  cipher_bytes = Validation.check_filled_array_argument!(cipher_bytes)
  private_key = Validation.check_type_argument!(VirgilPrivateKey, private_key)

  begin
    cipher = Core::VirgilCipher.new
    decrypted_bytes = cipher.decrypt_with_key(
      cipher_bytes,
      private_key.id,
      private_key.raw_key
    )
    wrap_bytes(decrypted_bytes)
  rescue StandardError => error
    raise VirgilCryptoException, error.message
  end
end

#decrypt_stream(cipher_stream, output_stream, private_key) ⇒ Object

Decrypts the specified stream using Private key.

Examples:

include Virgil::Crypto
crypto = VirgilCrypto.new
File.open('[YOUR_CIPHER_FILE_PATH_HERE]', 'r') do |cipher_stream|
  File.open('[YOUR_DECRYPTED_FILE_PATH_HERE]', 'w') do |decrypted_stream|
    alice_private_key = crypto.import_private_key(exported_private_key)
    crypto.decrypt_stream(cipher_stream, decrypted_stream, alice_private_key)
  end
end

Parameters:

  • cipher_stream (IO)

    readable stream containing encrypted data.

  • output_stream (IO)

    writable stream for output.

  • private_key (VirgilPrivateKey)

    private key for decryption.

See Also:

[View source]

482
483
484
485
486
487
488
489
490
491
492
# File 'lib/virgil/crypto/virgil_crypto.rb', line 482

def decrypt_stream(cipher_stream, output_stream, private_key)
  private_key = Validation.check_type_argument!(VirgilPrivateKey, private_key)
  begin
    cipher = Core::VirgilChunkCipher.new
    source = VirgilStreamDataSource.new(cipher_stream)
    sink = VirgilStreamDataSink.new(output_stream)
    cipher.decrypt_with_key(source, sink, private_key.id, private_key.raw_key)
  rescue StandardError => error
    raise VirgilCryptoException, error.message
  end
end

#decrypt_then_verify(bytes, private_key, *public_keys) ⇒ Bytes

Decrypts and verifies the data. for verification,

which can contain signer's public key.

Examples:

include Virgil::Crypto
crypto = VirgilCrypto.new

alice = crypto.generate_keys
bob = crypto.generate_keys

decrypted_data = crypto.decrypt_then_verify(
  cipher_data,
  bob.private_key,
  alice.public_key
)

Parameters:

Returns:

  • (Bytes)

    Decrypted data bytes.

Raises:

See Also:

[View source]

352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
# File 'lib/virgil/crypto/virgil_crypto.rb', line 352

def decrypt_then_verify(bytes, private_key, *public_keys)
  bytes = Validation.check_filled_array_argument!(bytes)
  private_key = Validation.check_type_argument!(VirgilPrivateKey, private_key)

  begin
    cipher = Core::VirgilCipher.new
    decrypted_bytes = cipher.decrypt_with_key(
      bytes,
      private_key.id,
      private_key.raw_key
    )
    signature = cipher.custom_params.get_data(CUSTOM_PARAM_KEY_SIGNATURE)

    signer_public_key = public_keys.first

    if public_keys.count > 1
      signer_id = cipher.custom_params.get_data(CUSTOM_PARAM_KEY_SIGNER_ID)
      signer_public_key = public_keys.find {|public_key| public_key.id == signer_id}
    end

    is_valid = verify_signature(signature, decrypted_bytes, signer_public_key)
    raise VirgilCryptoException, 'Signature is not valid' unless is_valid

    wrap_bytes(decrypted_bytes)
  rescue StandardError => error
    raise VirgilCryptoException, error.message
  end
end

#encrypt(bytes, *public_keys) ⇒ Bytes

Encrypts the specified data using the specified recipients Public keys. of public keys.

Examples:

include Virgil::Crypto
crypto = VirgilCrypto.new
alice_keys = crypto.generate_keys
plain_data = Bytes.from_string('Hello Bob!')
cipher_data = crypto.encrypt(plain_data, alice_keys.public_key)

Parameters:

  • bytes (Virgil::Bytes)

    raw data bytes for encryption.

  • *public_keys (Array<VirgilPublicKey>)

    list

Returns:

  • (Bytes)

    Encrypted bytes.

See Also:

[View source]

249
250
251
252
253
254
255
256
257
# File 'lib/virgil/crypto/virgil_crypto.rb', line 249

def encrypt(bytes, *public_keys)
  bytes = Validation.check_filled_array_argument!(bytes)

  begin
    encrypt_for_recipients(bytes, Core::VirgilCipher.new, public_keys)
  rescue StandardError => error
    raise VirgilCryptoException, error.message
  end
end

#encrypt_stream(input_stream, cipher_stream, *public_keys) ⇒ Object

Encrypts the specified stream using public_keys Public keys. public_keys' public keys. cipher_stream, alice_keys.public_key)

  end
end

Examples:

include Virgil::Crypto
crypto = VirgilCrypto.new
alice_keys = crypto.generate_keys()
File.open('[YOUR_FILE_PATH_HERE]', 'r') do |input_stream|
  File.open('[YOUR_CIPHER_FILE_PATH_HERE]', 'w') do |cipher_stream|
    crypto.encrypt_stream(input_stream,

Parameters:

  • input_stream (IO)

    readable stream containing input bytes.

  • cipher_stream (IO)

    writable stream for output.

  • *public_keys (Array<VirgilPublicKey>)

    list of

[View source]

452
453
454
455
456
457
458
459
460
461
462
463
464
465
# File 'lib/virgil/crypto/virgil_crypto.rb', line 452

def encrypt_stream(input_stream, cipher_stream, *public_keys)
  begin
    cipher = Core::VirgilChunkCipher.new
    public_keys.each do |public_key|
      public_key = Validation.check_type_argument!(VirgilPublicKey, public_key)
      cipher.add_key_recipient(public_key.id, public_key.raw_key)
    end
    source = VirgilStreamDataSource.new(input_stream)
    sink = VirgilStreamDataSink.new(cipher_stream)
    cipher.encrypt(source, sink)
  rescue StandardError => error
    raise VirgilCryptoException, error.message
  end
end

#export_private_key(private_key, password = nil) ⇒ Bytes

Exports the Private key into material representation.

Examples:

include Virgil::Crypto
crypto = VirgilCrypto.new
alice_keys = crypto.generate_keys
exported_private_key = crypto.export_private_key(alice_keys.private_key, 'my_password')

Parameters:

  • private_key (VirgilPrivateKey)

    private key for export.

  • password (String) (defaults to: nil)

    private key password, nil by default.

Returns:

  • (Bytes)

    Private key material representation bytes.

[View source]

168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
# File 'lib/virgil/crypto/virgil_crypto.rb', line 168

def export_private_key(private_key, password = nil)
  private_key = Validation.check_type_argument!(VirgilPrivateKey, private_key)

  begin
    unless password
      return Core::VirgilKeyPair.private_key_to_der(
        private_key.raw_key
      )
    end
    password_bytes = Bytes.from_string(password)
    private_key_bytes = Core::VirgilKeyPair.encrypt_private_key(
      private_key.raw_key,
      password_bytes
    )
    wrap_bytes(
      Core::VirgilKeyPair.private_key_to_der(
        private_key_bytes,
        password_bytes
      )
    )
  rescue StandardError => error
    raise VirgilCryptoException, error.message
  end
end

#export_public_key(public_key) ⇒ Bytes

Exports the Public key into material representation.

Examples:

include Virgil::Crypto
crypto = VirgilCrypto.new
alice_keys = crypto.generate_keys
exported_public_key = crypto.export_public_key(alice_keys.public_key)

Parameters:

Returns:

  • (Bytes)

    Key material representation bytes.

[View source]

201
202
203
204
205
206
207
208
209
210
211
# File 'lib/virgil/crypto/virgil_crypto.rb', line 201

def export_public_key(public_key)
  public_key = Validation.check_type_argument!(VirgilPublicKey, public_key)

  begin
    wrap_bytes(
      Core::VirgilKeyPair.public_key_to_der(public_key.raw_key)
    )
  rescue StandardError => error
    raise VirgilCryptoException, error.message
  end
end

#extract_public_key(private_key) ⇒ VirgilPublicKey

Extracts the Public key from Private key. key for extraction.

Parameters:

Returns:

[View source]

217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
# File 'lib/virgil/crypto/virgil_crypto.rb', line 217

def extract_public_key(private_key)
  private_key = Validation.check_type_argument!(VirgilPrivateKey, private_key)

  begin
    public_key_bytes = Core::VirgilKeyPair.extract_public_key(
      private_key.raw_key,
      []
    )
    VirgilPublicKey.new(
      private_key.id,
      wrap_bytes(
        Core::VirgilKeyPair.public_key_to_der(public_key_bytes)
      )
    )
  rescue StandardError => error
    raise VirgilCryptoException, error.message
  end
end

#generate_hash(bytes, algorithm = nil) ⇒ Bytes

Computes the hash of specified data and the specified [HashAlgorithm]

Parameters:

  • bytes (Bytes)

    original data bytes to be hashed.

  • algorithm (HashAlgorithm) (defaults to: nil)

    hashing algorithm. The possible values can be found in HashAlgorithm enum.

Returns:

  • (Bytes)

    Hash bytes.

[View source]

551
552
553
554
555
556
557
558
559
560
561
562
563
564
# File 'lib/virgil/crypto/virgil_crypto.rb', line 551

def generate_hash(bytes, algorithm = nil)
  bytes = Validation.check_filled_array_argument!(bytes)

  alg = algorithm
  alg ||= use_SHA256_fingerprints ? HashAlgorithm::SHA256 : HashAlgorithm::SHA512

  begin
    native_algorithm = HashAlgorithm.convert_to_native(alg)
    native_hasher = Core::VirgilHash.new(native_algorithm)
    wrap_bytes(native_hasher.hash(bytes))
  rescue StandardError => error
    raise VirgilCryptoException, error.message
  end
end

#generate_keys(keys_type: @default_key_type, key_material: nil) ⇒ KeyPair

Generates asymmetric key pair that is comprised of both public and private keys by specified type. key generation, length must be more than 31.

Examples:

Generated key pair with default type FAST_EC_ED25519

include Virgil::Crypto
crypto = VirgilCrypto.new
alice_keys = crypto.generate_keys

Generated key pair with type EC_SECP256R1

include Virgil::Crypto
crypto = VirgilCrypto.new
alice_keys = crypto.generate_keys(key_type: KeyPairType::EC_SECP256R1)

Parameters:

  • keys_type (Symbol) (defaults to: @default_key_type)

    type of the generated keys. The possible values can be found in KeyPairType enum.

  • key_material (Bytes) (defaults to: nil)

    the only data to be used for

Returns:

  • (KeyPair)

    Generated key pair with the special type.

[View source]

73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# File 'lib/virgil/crypto/virgil_crypto.rb', line 73

def generate_keys(keys_type: @default_key_type, key_material: nil)
  key_material = Validation.check_filled_array_argument!(key_material) if key_material
  begin
    native_type = KeyPairType.convert_to_native(keys_type)
    native_key_pair = nil
    native_key_pair = if key_material
                        Core::VirgilKeyPair.generate_from_key_material(
                          native_type,
                          key_material
                        )
                      else
                        Core::VirgilKeyPair.generate(native_type)
                      end
    key_pair_id = compute_public_key_hash(native_key_pair.public_key)
    private_key = VirgilPrivateKey.new(
      key_pair_id,
      wrap_bytes(
        Core::VirgilKeyPair.private_key_to_der(native_key_pair.private_key)
      )
    )
    public_key = VirgilPublicKey.new(
      key_pair_id,
      wrap_bytes(
        Core::VirgilKeyPair.public_key_to_der(native_key_pair.public_key)
      )
    )
    return KeyPair.new(private_key, public_key)
  rescue StandardError => error
    raise VirgilCryptoException, error.message
  end
end

#generate_signature(bytes, private_key) ⇒ Bytes

Signs the specified data using Private key.

Examples:

Sign the fingerprint of bytes using your private key.

include Virgil::Crypto
crypto = VirgilCrypto.new
alice_keys = crypto.generate_keys()
# The data to be signed with alice's Private key
data = Bytes.from_string('Hello Bob, How are you?')
signature = crypto.generate_signature(data, alice.private_key)

Parameters:

  • bytes (Bytes)

    raw data bytes for signing.

  • private_key (VirgilPrivateKey)

    private key for signing.

Returns:

  • (Bytes)

    Signature data.

See Also:

[View source]

394
395
396
397
398
399
400
401
402
403
404
405
# File 'lib/virgil/crypto/virgil_crypto.rb', line 394

def generate_signature(bytes, private_key)
  bytes = Validation.check_filled_array_argument!(bytes)
  private_key = Validation.check_type_argument!(VirgilPrivateKey, private_key)

  begin
    native_algorithm = HashAlgorithm.convert_to_native(HashAlgorithm::SHA512)
    signer = Core::VirgilSigner.new(native_algorithm)
    wrap_bytes(signer.sign(bytes, private_key.raw_key))
  rescue StandardError => error
    raise VirgilCryptoException, error.message
  end
end

#generate_stream_signature(input_stream, private_key) ⇒ Bytes

Signs the specified stream using Private key.

@see #verify_stream_signature How to verify the signature

Examples:

include Virgil::Crypto
crypto = VirgilCrypto.new
alice_keys = crypto.generate_keys()
File.open('[YOUR_FILE_PATH_HERE]', 'r') do |input_stream|
    signature = crypto.generate_stream_signature(input_stream, alice_keys.private_key)
end

Parameters:

  • input_stream (IO)

    readable stream containing input data.

  • private_key (VirgilPrivateKey)

    private key for signing.

Returns:

  • (Bytes)

    Signature bytes.

[View source]

506
507
508
509
510
511
512
513
514
515
516
517
# File 'lib/virgil/crypto/virgil_crypto.rb', line 506

def generate_stream_signature(input_stream, private_key)
  private_key = Validation.check_type_argument!(VirgilPrivateKey, private_key)

  begin
    native_algorithm = HashAlgorithm.convert_to_native(HashAlgorithm::SHA512)
    signer = Core::VirgilStreamSigner.new(native_algorithm)
    source = VirgilStreamDataSource.new(input_stream)
    wrap_bytes(signer.sign(source, private_key.raw_key))
  rescue StandardError => error
    raise VirgilCryptoException, error.message
  end
end

#import_private_key(key_bytes, password = nil) ⇒ VirgilPrivateKey

Imports the Private key from material representation. representation bytes.

Examples:

private_key = crypto.import_private_key(exported_private_key, 'my_password')

Parameters:

  • key_bytes (Bytes)

    private key material

  • password (String) (defaults to: nil)

    private key password, nil by default.

Returns:

See Also:

[View source]

113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
# File 'lib/virgil/crypto/virgil_crypto.rb', line 113

def import_private_key(key_bytes, password = nil)
  key_bytes = Validation.check_filled_array_argument!(key_bytes)

  begin
    decrypted_private_key = if !password
                              Core::VirgilKeyPair.private_key_to_der(key_bytes)
                            else
                              Core::VirgilKeyPair.decrypt_private_key(
                                  key_bytes,
                                  Bytes.from_string(password)
                              )
                            end

    public_key_bytes = Core::VirgilKeyPair.extract_public_key(
        decrypted_private_key, []
    )
    key_pair_id = compute_public_key_hash(public_key_bytes)
    private_key_bytes = Core::VirgilKeyPair.private_key_to_der(
        decrypted_private_key
    )
    return VirgilPrivateKey.new(key_pair_id, wrap_bytes(private_key_bytes))
  rescue => error
    raise VirgilCryptoException, error.message
  end

end

#import_public_key(key_bytes) ⇒ VirgilPublicKey

Imports the Public key from material representation. representation bytes.

Examples:

public_key = crypto.import_public_key(exported_public_key)

Parameters:

  • key_bytes (Bytes)

    public key material

Returns:

See Also:

[View source]

147
148
149
150
151
152
153
154
155
156
157
# File 'lib/virgil/crypto/virgil_crypto.rb', line 147

def import_public_key(key_bytes)
  key_bytes = Validation.check_filled_array_argument!(key_bytes)

  begin
    key_pair_id = compute_public_key_hash(key_bytes)
    public_key_bytes = Core::VirgilKeyPair.public_key_to_der(key_bytes)
    VirgilPublicKey.new(key_pair_id, wrap_bytes(public_key_bytes))
  rescue StandardError => error
    raise VirgilCryptoException, error.message
  end
end

#sign_then_encrypt(bytes, private_key, *public_keys) ⇒ Bytes

Signs and encrypts the data.

Examples:

include Virgil::Crypto
crypto = VirgilCrypto.new

alice = crypto.generate_keys
bob = crypto.generate_keys

# The data to be signed with alice's Private key
data = Bytes.from_string('Hello Bob, How are you?')
cipher_data = crypto.sign_then_encrypt(
  data,
  alice.private_key,
  bob.public_key
)

Parameters:

  • bytes (Bytes)

    data bytes for signing and encryption.

  • private_key (VirgilPrivateKey)

    private key to sign the data.

  • *public_keys (Array<VirgilPublicKey>)

    list of public keys to encrypt the data.

Returns:

  • (Bytes)

    Signed and encrypted data bytes.

[View source]

308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
# File 'lib/virgil/crypto/virgil_crypto.rb', line 308

def sign_then_encrypt(bytes, private_key, *public_keys)
  bytes = Validation.check_filled_array_argument!(bytes)
  private_key = Validation.check_type_argument!(VirgilPrivateKey, private_key)

  begin
    cipher = Core::VirgilCipher.new
    custom_bytes = cipher.custom_params
    custom_bytes.set_data(
      CUSTOM_PARAM_KEY_SIGNATURE,
      generate_signature(bytes, private_key)
    )

    public_key = extract_public_key(private_key)
    custom_bytes.set_data(
      CUSTOM_PARAM_KEY_SIGNER_ID,
      wrap_bytes(public_key.id)
    )
    encrypt_for_recipients(bytes, cipher, public_keys)
  rescue StandardError => error
    raise VirgilCryptoException, error.message
  end
end

#verify_signature(signature, bytes, signer_public_key) ⇒ Boolean

Verifies the specified signature using original data and signer's public key. key for verification. bytes using Public key.

include Virgil::Crypto
crypto = VirgilCrypto.new
alice_keys = crypto.generate_keys()
data = Bytes.from_string('Hello Bob, How are you?')
is_valid = crypto.verify_signature(signature, data, alice.public_key)

Examples:

Verify the signature of the fingerprint of

Parameters:

  • bytes (Bytes)

    original data bytes for verification.

  • signature (Bytes)

    signature bytes for verification.

  • signer_public_key (VirgilPublicKey)

    signer public

Returns:

  • (Boolean)

    True if signature is valid, False otherwise.

See Also:

[View source]

422
423
424
425
426
427
428
429
430
431
432
433
434
435
# File 'lib/virgil/crypto/virgil_crypto.rb', line 422

def verify_signature(signature, bytes, signer_public_key)
  signature = Validation.check_filled_array_argument!(signature)
  bytes = Validation.check_filled_array_argument!(bytes)
  signer_public_key = Validation.check_type_argument!(VirgilPublicKey, signer_public_key)

  begin
    native_algorithm = HashAlgorithm.convert_to_native(HashAlgorithm::SHA512)
    signer = Core::VirgilSigner.new(native_algorithm)
    signer.verify(bytes, signature, signer_public_key.raw_key)
  rescue StandardError => error
    raise VirgilCryptoException, error.message
  end

end

#verify_stream_signature(signature, input_stream, signer_public_key) ⇒ Boolean

Verifies the specified signature using original stream and signer's Public key.

@see #generate_stream_signature How to get the signature

Examples:

include Virgil::Crypto
crypto = VirgilCrypto.new
alice_keys = crypto.generate_keys()
File.open('[YOUR_FILE_PATH_HERE]', 'r') do |input_stream|
    verified = crypto.verify_stream_signature(signature, input_stream, alice_keys.public_key)
end

Parameters:

  • input_stream (IO)

    readable stream containing input data.

  • signature (Bytes)

    signature bytes for verification.

  • signer_public_key (VirgilPublicKey)

    signer public key for verification.

Returns:

  • (Boolean)

    True if signature is valid, False otherwise.

[View source]

532
533
534
535
536
537
538
539
540
541
542
543
544
# File 'lib/virgil/crypto/virgil_crypto.rb', line 532

def verify_stream_signature(signature, input_stream, signer_public_key)
  signature = Validation.check_filled_array_argument!(signature)
  signer_public_key = Validation.check_type_argument!(VirgilPublicKey, signer_public_key)

  begin
    native_algorithm = HashAlgorithm.convert_to_native(HashAlgorithm::SHA512)
    signer = Core::VirgilStreamSigner.new(native_algorithm)
    source = VirgilStreamDataSource.new(input_stream)
    signer.verify(source, signature, signer_public_key.raw_key)
  rescue StandardError => error
    raise VirgilCryptoException, error.message
  end
end