Database encryption & generating keys server side with Rails

Hello,

When using your database I am attempting to encrypt/decrypt the database by generating a database key server-side to then be read by the mobile application utilizing Realm. Since I am using Ruby on Rails I’ve been using the following Ruby code to generate a key to store as a property called “database_key” on a model and am setting it like below:
self.database_key = Base64.urlsafe_encode64(SecureRandom.random_bytes(64))

I’ve noticed there are times when Realm reads the database key and throws an error message that the key is not valid / 64 bytes. I am unsure as to how the code above could produce different results at different times. Here’s the error:

2020-02-03 14:56:15.125625-0600 Dentologie[43101:1041036] *** Terminating app due to uncaught exception ‘RLMException’, reason: ‘Encryption key must be exactly 64 bytes long’***
First throw call stack:( 0 CoreFoundation 0x000000010df361bb exceptionPreprocess + 331 1 libobjc.A.dylib 0x000000010ced9735 objc_exception_throw + 48 2 Realm 0x000000010c3bbed8 RLMRealmValidatedEncryptionKey + 189 3 Realm 0x000000010c3c2a0d -[RLMRealmConfiguration setEncryptionKey:] + 25 4 RealmSwift 0x000000010cabbb60 $S10RealmSwift0A0C13ConfigurationV03rlmC0So08RLMRealmC0Cvg + 944 5 RealmSwift 0x000000010cabbec5 $S10RealmSwift0A0C13ConfigurationV07defaultC0AEvsZ + 37 6 Dentologie 0x0000000107b908d9 $S10Dentologie6AuthVCC5login5email8passwordySS_SStFyypcfU_yAA4UserCcfU + 1465 7 Dentologie 0x0000000107b94a8d $S10Dentologie6AuthVCC5login5email8passwordySS_SStFyypcfU_yAA4UserCcfU_TA + 13 8 Dentologie 0x0000000107b90e99 $S10Dentologie4UserCs5Error_pIeggzo_ACytsAD_pIegnrzo_TR + 25 9 Dentologie 0x0000000107b94aeb $S10Dentologie4UserCs5Error_pIeggzo_ACytsAD_pIegnrzo_TRTA + 27 10 PromiseKit 0x000000010bf58679 $S10PromiseKit0A0C4then2on7executeACyqd__GSo17OS_dispatch_queueC_qd__xKctlFyyAA10ResolutionOyqd__GcXEfU_yxKcfU + 89 11 PromiseKit 0x000000010bf5bee9 $S10PromiseKit0A0C4then2on7executeACyqd__GSo17OS_dispatch_queueC_qd__xKctlFyyAA10ResolutionOyqd__GcXEfU_yxKcfU_TA + 41 12 PromiseKit 0x000000010bf67ebb $S10PromiseKit5StateC4then2on4else7executeySo17OS_dispatch_queueC_yAA10ResolutionOyqd__GcyxKctlFyAKyxGcfU_yyKcfU_TA + 43 13 PromiseKit 0x000000010bf738ce $S10PromiseKit13contain_zalgo_8rejecter5blockySo17OS_dispatch_queueC_yAA10ResolutionOyxGcyyKctlFyycfU_ + 78 14 PromiseKit 0x000000010bf67d4d $S10PromiseKit13contain_zalgo_8rejecter5blockySo17OS_dispatch_queueC_yAA10ResolutionOyxGcyyKctlFyycfU_TA + 29 15 PromiseKit 0x000000010bf69249 $S10PromiseKit13contain_zalgo_8rejecter5blockySo17OS_dispatch_queueC_yAA10ResolutionOyxGcyyKctlFyycfU_TA.254 + 9 16 PromiseKit 0x000000010bf3b8e0 $SIeg_IeyB_TR + 32 17 libdispatch.dylib 0x000000010ff76595 _dispatch_call_block_and_release + 12 18 libdispatch.dylib 0x000000010ff77602 _dispatch_client_callout + 8 19 libdispatch.dylib 0x000000010ff8499a _dispatch_main_queue_callback_4CF + 1541 20 CoreFoundation 0x000000010de9b3e9 CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE + 9 21 CoreFoundation 0x000000010de95a76 __CFRunLoopRun + 2342 22 CoreFoundation 0x000000010de94e11 CFRunLoopRunSpecific + 625 23 GraphicsServices 0x000000011635f1dd GSEventRunModal + 62 24 UIKitCore 0x000000011376381d UIApplicationMain + 140 25 Dentologie 0x0000000107bd95a7 main + 71 26 libdyld.dylib 0x000000010ffed575 start + 1)libc++abi.dylib: terminating with uncaught exception of type NSException

Is there a code snippet or any advice you could provide on how to properly set this value so that Realm can use it to encrypt/decrypt the database as expected?

The Realm encryption key must be exactly 64 bytes long. You are generating the correct key length with SecureRandom.random_bytes(64), but then changing the length by converting the binary into printable characters via Base64.urlsafe_encode64(). Base64 encoding will generally always be larger than a random source binary string.

You need to either avoid base64 encoding or use a different method to generate a printable random key.

For example, SecureRandom.alphanumeric(64) will generate a 64-byte string consisting of printable numbers and letters.

Regards,
Stennie