Obfuscating an ID

前端 未结 11 490
逝去的感伤
逝去的感伤 2020-11-28 02:20

I\'m looking for a way to encrypt/obfuscate an integer ID into another integer. More precisely, I need a function int F(int x), so that

  • x<->F(x
相关标签:
11条回答
  • 2020-11-28 02:41

    Generate a private symmetric key for use in your application, and encrypt your integer with it. This will satisfy all three requirements, including the hardest #3: one would need to guess your key in order to break your scheme.

    0 讨论(0)
  • 2020-11-28 02:45

    Do anything with the bits of the ID that won't destroy them. For example:

    • rotate the value
    • use lookup to replace certain parts of the value
    • xor with some value
    • swap bits
    • swap bytes
    • mirror the whole value
    • mirror a part of the value
    • ... use your imagination

    For decryption, do all that in reverse order.

    Create a program that will 'encrypt' some interesting values for you and put them in a table you can examine. Have same program TEST your encryption/decryption routine WITH all set of values that you want to have in your system.

    Add stuff to the above list into the routines until your numbers will look properly mangled to you.

    For anything else, get a copy of The Book.

    0 讨论(0)
  • 2020-11-28 02:45

    Not sure how "hard" you need it to be, how fast, or how little memory to use. If you have no memory constraints you could make a list of all integers, shuffle them and use that list as a mapping. However, even for a 4 byte integer you would need a lot of memory.

    However, this could be made smaller so instead of mapping all integers you would map only 2 (or worst case 1) byte and apply this to each group in the integer. So, using 2 bytes a integer would be (group1)(group2) you would map each group through the random map. But that means that if you only change group2 then the mapping for group1 would stay the same. This could "fixed" by mapping different bits to each group.

    So, *(group2) could be (bit 14,12,10,8,6,4,2,0) so, adding 1 would change both group1 and group2.

    Still, this is only security by obscurity, anyone that can feed numbers into your function (even if you keep the function secret) could fairly easily figure it out.

    0 讨论(0)
  • 2020-11-28 02:50

    I found this particular piece of Python/PHP code very useful:

    https://github.com/marekweb/opaque-id

    0 讨论(0)
  • 2020-11-28 02:50

    I wrote some JS code using some of the ideas in this thread:

    const BITS = 32n;
    const MAX = 4294967295n;
    const COPRIME = 65521n;
    const INVERSE = 2166657316n;
    const ROT = 6n;
    const XOR1 = 10296065n; 
    const XOR2 = 2426476569n;
    
    
    function rotRight(n, bits, size) {
        const mask = (1n << bits) - 1n;
        // console.log('mask',mask.toString(2).padStart(Number(size),'0'));
        const left = n & mask;
        const right = n >> bits;
        return (left << (size - bits)) | right;
    }
    
    const pipe = fns => fns.reduce((f, g) => (...args) => g(f(...args)));
    
    function build(...fns) {
        const enc = fns.map(f => Array.isArray(f) ? f[0] : f);
        const dec = fns.map(f => Array.isArray(f) ? f[1] : f).reverse();
    
        return [
            pipe(enc),
            pipe(dec),
        ]
    }
    
    [exports.encode, exports.decode] = build(
        [BigInt, Number],
        [i => (i * COPRIME) % MAX, i => (i * INVERSE) % MAX],
        x => x ^ XOR1,
        [x => rotRight(x, ROT, BITS), x => rotRight(x, BITS-ROT, BITS)],
        x => x ^ XOR2,
    );
    

    It produces some nice results like:

    1 1352888202n 1 'mdh37u'
    2 480471946n 2 '7y26iy'
    3 3634587530n 3 '1o3xtoq'
    4 2225300362n 4 '10svwqy'
    5 1084456843n 5 'hxno97'
    6 212040587n 6 '3i8rkb'
    7 3366156171n 7 '1jo4eq3'
    8 3030610827n 8 '1e4cia3'
    9 1889750920n 9 'v93x54'
    10 1017334664n 10 'gtp0g8'
    11 4171450248n 11 '1wzknm0'
    12 2762163080n 12 '19oiqo8'
    13 1621319561n 13 'qtai6h'
    14 748903305n 14 'cdvlhl'
    15 3903018889n 15 '1sjr8nd'
    16 3567473545n 16 '1mzzc7d'
    17 2426613641n 17 '144qr2h'
    18 1554197390n 18 'ppbudq'
    19 413345678n 19 '6u3fke'
    20 3299025806n 20 '1ik5klq'
    21 2158182286n 21 'zoxc3y'
    22 1285766031n 22 'l9iff3'
    23 144914319n 23 '2ea0lr'
    24 4104336271n 24 '1vvm64v'
    25 2963476367n 25 '1d0dkzz'
    26 2091060108n 26 'ykyob0'
    27 950208396n 27 'fpq9ho'
    28 3835888524n 28 '1rfsej0'
    29 2695045004n 29 '18kk618'
    30 1822628749n 30 'u559cd'
    31 681777037n 31 'b9wuj1'
    32 346231693n 32 '5q4y31'
    

    Testing with:

      const {encode,decode} = require('./obfuscate')
    
      for(let i = 1; i <= 1000; ++i) {
            const j = encode(i);
            const k = decode(j);
            console.log(i, j, k, j.toString(36));
       }
    

    XOR1 and XOR2 are just random numbers between 0 and MAX. MAX is 2**32-1; you should set this to whatever you think your highest ID will be.

    COPRIME is a number that's coprime w/ MAX. I think prime numbers themselves are coprime with every other number (except multiples of themselves).

    INVERSE is the tricky one to figure out. These blog posts don't give a straight answer, but WolframAlpha can figure it out for you. Basically, just solve the equation (COPRIME * x) % MAX = 1 for x.

    The build function is something I created to make it easier to create these encode/decode pipelines. You can feed it as many operations as you want as [encode, decode] pairs. These functions have to be equal and opposite. The XOR functions are their own compliments so you don't need a pair there.


    Here's another fun involution:

    function mixHalves(n) {
        const mask = 2n**12n-1n;
        const right = n & mask;
        const left = n >> 12n;
        const mix = left ^ right;
        return (mix << 12n) | right;
    }
    

    (assumes 24-bit integers -- just change the numbers for any other size)

    0 讨论(0)
  • 2020-11-28 02:52

    You want the transformation to be reversible, and not obvious. That sounds like an encryption that takes a number in a given range and produces a different number in the same range. If your range is 64 bit numbers, then use DES. If your range is 128 bit numbers then use AES. If you want a different range, then your best bet is probably Hasty Pudding cipher, which is designed to cope with different block sizes and with number ranges that do not fit neatly into a block, such as 100,000 to 999,999.

    0 讨论(0)
提交回复
热议问题